Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:55:05

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 <string>
0010 #include <utility>
0011 
0012 #include "corecel/Config.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 is
0056  * typically used only for error messages coming from an a 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::detail::NullLoggerMessage()
0067 #    undef CELER_LOG_LOCAL
0068 #    define CELER_LOG_LOCAL(LEVEL) ::celeritas::detail::NullLoggerMessage()
0069 #endif
0070 
0071 namespace celeritas
0072 {
0073 class MpiCommunicator;
0074 
0075 //---------------------------------------------------------------------------//
0076 /*!
0077  * Create a log message to be printed based on output/verbosity sttings.
0078  *
0079  * This should generally be called by the \c world_logger and \c
0080  * self_logger functions below. The call \c operator() returns an object that
0081  * should be streamed into in order to create a log message.
0082  *
0083  * This object \em is assignable, so to replace the default log handler with a
0084  * different one, you can call \code
0085    world_logger = Logger(my_handler);
0086  * \endcode
0087  *
0088  * When using with MPI, the \c world_logger global objects are different on
0089  * each process: rank 0 will have a handler that outputs to screen, and the
0090  * other ranks will have a "null" handler that suppresses all log output.
0091  *
0092  * \todo For v1.0, replace the back-end with \c spdlog to reduce maintenance
0093  * burden and improve flexibility.
0094  */
0095 class Logger
0096 {
0097   public:
0098     //!@{
0099     //! \name Type aliases
0100     using Message = detail::LoggerMessage;
0101     //!@}
0102 
0103   public:
0104     //! Get the default log level
0105     static constexpr LogLevel default_level() { return LogLevel::status; }
0106 
0107     // Create a logger from a handle and level environment variable
0108     static Logger from_handle_env(LogHandler&& handle, std::string const& key);
0109 
0110     // Construct from an output handle
0111     explicit Logger(LogHandler&& handle);
0112 
0113     // Create a logger that flushes its contents when it destructs
0114     inline Message operator()(LogProvenance&& prov, LogLevel lev);
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   private:
0123     LogHandler handle_;
0124     LogLevel min_level_{default_level()};
0125 };
0126 
0127 //---------------------------------------------------------------------------//
0128 // INLINE DEFINITIONS
0129 //---------------------------------------------------------------------------//
0130 /*!
0131  * Create a logger that flushes its contents when it destructs.
0132  *
0133  * It's assumed that log messages will be relatively unlikely (and expensive
0134  * anyway), so we mark as \c CELER_UNLIKELY to optimize for the no-logging
0135  * case.
0136  */
0137 auto Logger::operator()(LogProvenance&& prov, LogLevel lev) -> Message
0138 {
0139     LogHandler* handle = nullptr;
0140     if (CELER_UNLIKELY(handle_ && lev >= min_level_))
0141     {
0142         handle = &handle_;
0143     }
0144     return {handle, std::move(prov), lev};
0145 }
0146 
0147 //---------------------------------------------------------------------------//
0148 // FREE FUNCTIONS
0149 //---------------------------------------------------------------------------//
0150 // Get the log level from an environment variable
0151 LogLevel log_level_from_env(std::string const&, LogLevel default_lev);
0152 LogLevel log_level_from_env(std::string const&);
0153 
0154 // Create loggers with reasonable default behaviors.
0155 Logger make_default_world_logger();
0156 Logger make_default_self_logger();
0157 
0158 // Parallel logger (print only on "main" process)
0159 Logger& world_logger();
0160 
0161 // Serial logger (print on *every* process)
0162 Logger& self_logger();
0163 
0164 //---------------------------------------------------------------------------//
0165 }  // namespace celeritas