Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-03 10:19:17

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file corecel/io/Logger.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <utility>
0010 
0011 #include "corecel/Macros.hh"
0012 #include "corecel/io/detail/NullLoggerMessage.hh"
0013 
0014 #include "LoggerTypes.hh"
0015 
0016 #include "detail/LoggerMessage.hh"  // IWYU pragma: export
0017 #if CELER_DEVICE_COMPILE
0018 #    include "detail/NullLoggerMessage.hh"  // IWYU pragma: export
0019 #endif
0020 
0021 //---------------------------------------------------------------------------//
0022 // MACROS
0023 //---------------------------------------------------------------------------//
0024 //! Inject the source code provenance (current file and line)
0025 #define CELER_CODE_PROVENANCE \
0026     ::celeritas::LogProvenance \
0027     { \
0028         __FILE__, __LINE__ \
0029     }
0030 
0031 /*!
0032  * \def CELER_LOG
0033  *
0034  * Return a LogMessage object for streaming into at the given level. The
0035  * regular \c CELER_LOG call is for code paths that happen uniformly in
0036  * parallel, approximately the same message from every thread and task.
0037  *
0038  * The logger will only format and print messages. It is not responsible
0039  * for cleaning up the state or exiting an app.
0040  *
0041  * \code
0042  CELER_LOG(debug) << "Don't print this in general";
0043  CELER_LOG(warning) << "You may want to reconsider your life choices";
0044  CELER_LOG(critical) << "Caught a fatal exception: " << e.what();
0045  * \endcode
0046  */
0047 #define CELER_LOG(LEVEL) \
0048     ::celeritas::world_logger()(CELER_CODE_PROVENANCE, \
0049                                 ::celeritas::LogLevel::LEVEL)
0050 
0051 /*!
0052  * \def CELER_LOG_LOCAL
0053  *
0054  * Like \c CELER_LOG but for code paths that may only happen on a single
0055  * process or thread. Use sparingly because this can be very verbose. This
0056  * should be used for error messages from an event or
0057  * track at runtime.
0058  */
0059 #define CELER_LOG_LOCAL(LEVEL) \
0060     ::celeritas::self_logger()(CELER_CODE_PROVENANCE, \
0061                                ::celeritas::LogLevel::LEVEL)
0062 
0063 // Allow CELER_LOG to be present (but ignored) in device code
0064 #if CELER_DEVICE_COMPILE
0065 #    undef CELER_LOG
0066 #    define CELER_LOG(LEVEL) ::celeritas::null_log_message()
0067 #    undef CELER_LOG_LOCAL
0068 #    define CELER_LOG_LOCAL(LEVEL) ::celeritas::null_log_message()
0069 #endif
0070 
0071 namespace celeritas
0072 {
0073 //---------------------------------------------------------------------------//
0074 /*!
0075  * Create a log message to be printed based on output/verbosity settings.
0076  *
0077  * This should generally be called by the \c world_logger and \c
0078  * self_logger functions below. The call \c operator() returns an object that
0079  * should be streamed into in order to create a log message.
0080  *
0081  * This object \em is assignable, so to replace the default log handler with a
0082  * different one, you can call \code
0083    world_logger = Logger(my_handler);
0084  * \endcode
0085  *
0086  * When using with MPI, set a null handle to \c world_logger on all processes
0087  * other than rank 0, or use \c LocalMpiHandler on each process.
0088  *
0089  * \todo Replace the back-end with \c spdlog to reduce maintenance
0090  * burden and improve flexibility.
0091  */
0092 class Logger
0093 {
0094   public:
0095     //!@{
0096     //! \name Type aliases
0097     using Message = detail::LoggerMessage;
0098     //!@}
0099 
0100   public:
0101     //! Get the default log level
0102     static constexpr LogLevel default_level() { return LogLevel::status; }
0103 
0104     // Construct a null logger
0105     Logger() = default;
0106 
0107     // Construct a logger with handle and default level
0108     explicit Logger(LogHandler&& handle);
0109 
0110     // Construct a logger with handle and level
0111     Logger(LogHandler&& handle, LogLevel min_lev);
0112 
0113     // Create a log message that flushes its contents when it destructs
0114     inline Message operator()(LogProvenance&& prov, LogLevel lev) const;
0115 
0116     //! Set the minimum logging verbosity
0117     void level(LogLevel lev) { min_level_ = lev; }
0118 
0119     //! Get the current logging verbosity
0120     LogLevel level() const { return min_level_; }
0121 
0122     //! Access the log handle
0123     LogHandler const& handle() const { return handle_; }
0124 
0125     //! Set the log handle (null disables logger)
0126     void handle(LogHandler&& handle) { handle_ = std::move(handle); }
0127 
0128   private:
0129     LogHandler handle_;
0130     LogLevel min_level_{default_level()};
0131 };
0132 
0133 //---------------------------------------------------------------------------//
0134 // INLINE DEFINITIONS
0135 //---------------------------------------------------------------------------//
0136 /*!
0137  * Create a logger that flushes its contents when it destructs.
0138  *
0139  * It's assumed that log messages will be relatively unlikely (and expensive
0140  * anyway), so we mark as \c CELER_UNLIKELY to optimize for the no-logging
0141  * case.
0142  */
0143 auto Logger::operator()(LogProvenance&& prov, LogLevel lev) const -> Message
0144 {
0145     LogHandler const* handle = nullptr;
0146     if (CELER_UNLIKELY(handle_ && lev >= min_level_))
0147     {
0148         handle = &handle_;
0149     }
0150     return Message{handle, std::move(prov), lev};
0151 }
0152 
0153 //---------------------------------------------------------------------------//
0154 // FREE FUNCTIONS
0155 //---------------------------------------------------------------------------//
0156 
0157 // Parallel logger (print only on "main" process using CELER_LOG)
0158 Logger& world_logger();
0159 
0160 // Serial logger (print on *every* process using CELER_LOG_LOCAL)
0161 Logger& self_logger();
0162 
0163 //! Return a stream-like object that ignores everything (used for device code)
0164 CELER_CONSTEXPR_FUNCTION auto null_log_message()
0165 {
0166     return detail::NullLoggerMessage();
0167 }
0168 
0169 //---------------------------------------------------------------------------//
0170 }  // namespace celeritas