Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-23 07:34:31

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 // STL include(s)
0012 #include <ctime>
0013 #include <iomanip>
0014 #include <iostream>
0015 #include <memory>
0016 #include <mutex>
0017 #include <optional>
0018 #include <sstream>
0019 #include <stdexcept>
0020 #include <string>
0021 #include <string_view>
0022 #include <thread>
0023 #include <utility>
0024 
0025 /// @addtogroup logging
0026 /// @{
0027 
0028 /// @defgroup logging_macros Logging Macros
0029 /// @ingroup logging
0030 /// @brief Helper macros for logging with @ref Acts::Logger
0031 ///
0032 /// When a logger accessible via the `logger()` method, see @ref logging_patterns,
0033 /// use these macros to perform the actual logging:
0034 ///
0035 /// @snippet{trimleft} examples/logging.cpp Logging Macros
0036 ///
0037 /// The macros support stream-style formatting with `<<` operators.
0038 /// @{
0039 
0040 /// @brief Macro to use a local Acts::Logger object
0041 ///
0042 /// @param log_object logger instance of type
0043 //         `std::unique_ptr<const Acts::Logger>`
0044 ///
0045 /// @pre In the current scope, the symbol @c logger is not yet defined.
0046 /// @post The ownership of the given @c log_object is transferred and
0047 ///       @c log_object should not be used directly any more.
0048 ///
0049 /// This macro allows to use a locally defined logging object with the ACTS_*
0050 /// logging macros. The envisaged usage is the following:
0051 ///
0052 /// @snippet{trimleft} examples/logging.cpp Local logger macro
0053 #define ACTS_LOCAL_LOGGER(log_object)                                          \
0054   struct __local_acts_logger {                                                 \
0055     explicit __local_acts_logger(std::unique_ptr<const ::Acts::Logger> logger) \
0056         : m_logger(std::move(logger)) {}                                       \
0057                                                                                \
0058     const ::Acts::Logger& operator()() const { return *m_logger; }             \
0059                                                                                \
0060     std::unique_ptr<const ::Acts::Logger> m_logger;                            \
0061   };                                                                           \
0062   __local_acts_logger logger(log_object);
0063 
0064 /// Log a message at the specified level with an explicit logger instance
0065 /// @param lgr The logger instance (must be a Acts::Logger reference)
0066 /// @param level The logging level
0067 /// @param x The message to log
0068 #define ACTS_LOG_WITH_LOGGER(lgr, level, x) \
0069   do {                                      \
0070     if ((lgr).doPrint(level)) {             \
0071       std::ostringstream os;                \
0072       os << x;                              \
0073       (lgr).log(level, os.str());           \
0074     }                                       \
0075   } while (0)
0076 
0077 /// Log a message at the specified level
0078 /// @param level The logging level
0079 /// @param x The message to log
0080 #define ACTS_LOG(level, x) ACTS_LOG_WITH_LOGGER(logger(), level, x)
0081 
0082 /// @brief macro for verbose debug output
0083 ///
0084 /// @param x debug message
0085 ///
0086 /// @pre @c logger() must be a valid expression in the scope where this
0087 ///      macro is used and it must return a Acts::Logger object.
0088 ///
0089 /// The debug message is printed if the current Acts::Logging::Level <=
0090 /// Acts::Logging::VERBOSE.
0091 #define ACTS_VERBOSE(x) ACTS_LOG(Acts::Logging::VERBOSE, x)
0092 
0093 /// @brief macro for debug debug output
0094 ///
0095 /// @param x debug message
0096 ///
0097 /// @pre @c logger() must be a valid expression in the scope where this
0098 ///      macro is used and it must return a Acts::Logger object.
0099 ///
0100 /// The debug message is printed if the current Acts::Logging::Level <=
0101 /// Acts::Logging::DEBUG.
0102 #define ACTS_DEBUG(x) ACTS_LOG(Acts::Logging::DEBUG, x)
0103 
0104 /// @brief macro for info debug output
0105 ///
0106 /// @param x debug message
0107 ///
0108 /// @pre @c logger() must be a valid expression in the scope where this
0109 ///      macro is used and it must return a Acts::Logger object.
0110 ///
0111 /// The debug message is printed if the current Acts::Logging::Level <=
0112 /// Acts::Logging::INFO.
0113 #define ACTS_INFO(x) ACTS_LOG(Acts::Logging::INFO, x)
0114 
0115 /// @brief macro for warning debug output
0116 ///
0117 /// @param x debug message
0118 ///
0119 /// @pre @c logger() must be a valid expression in the scope where this
0120 ///      macro is used and it must return a Acts::Logger object.
0121 ///
0122 /// The debug message is printed if the current Acts::Logging::Level <=
0123 /// Acts::Logging::WARNING.
0124 #define ACTS_WARNING(x) ACTS_LOG(Acts::Logging::WARNING, x)
0125 
0126 /// @brief macro for error debug output
0127 ///
0128 /// @param x debug message
0129 ///
0130 /// @pre @c logger() must be a valid expression in the scope where this
0131 ///      macro is used and it must return a Acts::Logger object.
0132 ///
0133 /// The debug message is printed if the current Acts::Logging::Level <=
0134 /// Acts::Logging::ERROR.
0135 #define ACTS_ERROR(x) ACTS_LOG(Acts::Logging::ERROR, x)
0136 
0137 /// @brief macro for fatal debug output
0138 ///
0139 /// @param x debug message
0140 ///
0141 /// @pre @c logger() must be a valid expression in the scope where this
0142 ///      macro is used and it must return a Acts::Logger object.
0143 ///
0144 /// The debug message is printed if the current Acts::Logging::Level <=
0145 /// Acts::Logging::FATAL.
0146 #define ACTS_FATAL(x) ACTS_LOG(Acts::Logging::FATAL, x)
0147 
0148 /// @}
0149 /// @}
0150 
0151 namespace Acts {
0152 
0153 namespace Logging {
0154 
0155 /// @addtogroup logging
0156 /// @{
0157 
0158 /// @brief constants steering the debug output
0159 ///
0160 /// All messages with a debug level equal or higher than the currently set
0161 /// debug output level will be printed.
0162 enum Level {
0163   VERBOSE = 0,  ///< Detailed diagnostic trace information
0164   DEBUG,        ///< Debug information during development
0165   INFO,         ///< General information messages
0166   WARNING,      ///< Non-critical error conditions
0167   ERROR,        ///< Error conditions which require follow-up
0168   FATAL,        ///< Unrecoverable error conditions
0169   MAX           ///< Filler level
0170 };
0171 
0172 /// @brief Get the string name for a logging level
0173 /// @param level The logging level
0174 /// @return String representation of the logging level
0175 inline std::string_view levelName(Level level) {
0176   switch (level) {
0177     case Level::VERBOSE:
0178       return "VERBOSE";
0179     case Level::DEBUG:
0180       return "DEBUG";
0181     case Level::INFO:
0182       return "INFO";
0183     case Level::WARNING:
0184       return "WARNING";
0185     case Level::ERROR:
0186       return "ERROR";
0187     case Level::FATAL:
0188       return "FATAL";
0189     case Level::MAX:
0190       return "MAX";
0191     default:
0192       throw std::invalid_argument{"Unknown level"};
0193   }
0194 }
0195 
0196 /// @defgroup logging_thresholds Logging Thresholds
0197 /// @ingroup logging
0198 /// @brief Functions and classes to manage logging failure thresholds
0199 ///
0200 /// Generally, log levels in ACTS are only of informative value: even
0201 /// @ref Acts::Logging::Level::ERROR and @ref Acts::Logging::Level::FATAL will only print
0202 /// messages, **and not terminate execution**.
0203 ///
0204 /// This is desirable in an experiment context, where jobs should not
0205 /// immediately terminate when ACTS encounters something that is logged as an
0206 /// error. In a test context, however, this behavior is not optimal: the tests
0207 /// should ensure in known configurations errors do not occur, or only in
0208 /// specific circumstances. To solve this, ACTS implements an optional log
0209 /// *threshold* mechanism.
0210 ///
0211 /// The threshold mechanism is steered via two CMake options:
0212 /// `ACTS_ENABLE_LOG_FAILURE_THRESHOLD` and `ACTS_LOG_FAILURE_THRESHOLD`.
0213 /// Depending on their configuration, the logging can operate in three modes:
0214 ///
0215 /// 1. **No log failure threshold** exists, log levels are informative only.
0216 /// This is
0217 ///    the default behavior.
0218 /// 2. A **compile-time log failure threshold** is set. If
0219 ///    `ACTS_ENABLE_LOG_FAILURE_THRESHOLD=ON` and
0220 ///    `ACTS_LOG_FAILURE_THRESHOLD=<LEVEL>` are set, the logger code will
0221 ///    compile in a fixed check if the log level of a particular message exceeds
0222 ///    `<LEVEL>`.
0223 ///    If that is the case, an exception of type @ref Acts::Logging::ThresholdFailure is
0224 ///    thrown.
0225 /// 3. A **runtime log failure threshold** is set. If only
0226 ///    `ACTS_ENABLE_LOG_FAILURE_THRESHOLD=ON` and no fixed threshold level is
0227 ///    set, the logger code will compile in a check of a global runtime
0228 ///    threshold variable.
0229 ///
0230 /// @note If only `ACTS_LOG_FAILURE_THRESHOLD` is set,
0231 /// `ACTS_ENABLE_LOG_FAILURE_THRESHOLD` will be set automatically, i.e. a
0232 /// compile-time threshold will be set.
0233 ///
0234 /// @{
0235 
0236 #ifdef DOXYGEN
0237 /// @brief Get debug level above which an exception will be thrown after logging
0238 ///
0239 /// All messages with a debug level equal or higher than the return value of
0240 /// this function will cause an exception to be thrown after log emission.
0241 ///
0242 /// @note Depending on preprocessor settings @c ACTS_ENABLE_LOG_FAILURE_THRESHOLD
0243 ///       and @c ACTS_LOG_FAILURE_THRESHOLD, this operations is either constexpr
0244 ///       or a runtime operation.
0245 /// @return The log level threshold for failure
0246 Level getFailureThreshold();
0247 
0248 #else
0249 
0250 #ifdef ACTS_ENABLE_LOG_FAILURE_THRESHOLD
0251 #ifdef ACTS_LOG_FAILURE_THRESHOLD
0252 // We have a fixed compile time log failure threshold
0253 constexpr Level getFailureThreshold() {
0254   return Level::ACTS_LOG_FAILURE_THRESHOLD;
0255 }
0256 #else
0257 Level getFailureThreshold();
0258 #endif
0259 #else
0260 constexpr Level getFailureThreshold() {
0261   // Default "NO" failure threshold
0262   return Level::MAX;
0263 }
0264 #endif
0265 
0266 #endif
0267 
0268 /// @brief Set debug level above which an exception will be thrown after logging
0269 ///
0270 /// All messages with a debug level equal or higher than @p level will
0271 /// cause an exception to be thrown after log emission.
0272 ///
0273 /// @warning The runtime log failure threshold is **global state**, therefore
0274 ///          this function is  **not threadsafe**. The intention is that this
0275 ///          level is set once, before multi-threaded execution begins, and then
0276 ///          not modified before the end of the job.
0277 /// @note This function is only available if @c ACTS_LOG_FAILURE_THRESHOLD is
0278 ///       unset, i.e. no compile-time threshold is used. Otherwise an
0279 ///       exception is thrown.
0280 /// @param level Log level above which exceptions will be thrown
0281 void setFailureThreshold(Level level);
0282 
0283 /// Custom exception class so threshold failures can be caught
0284 class ThresholdFailure : public std::runtime_error {
0285   using std::runtime_error::runtime_error;
0286 };
0287 
0288 /// Helper class that changes the failure threshold for the duration of its
0289 /// lifetime.
0290 class ScopedFailureThreshold {
0291  public:
0292   /// Constructor that sets the failure threshold for the scope
0293   /// @param level The logging level to set as failure threshold
0294   explicit ScopedFailureThreshold(Level level) { setFailureThreshold(level); }
0295   ScopedFailureThreshold(const ScopedFailureThreshold&) = delete;
0296   ScopedFailureThreshold& operator=(const ScopedFailureThreshold&) = delete;
0297   ScopedFailureThreshold(ScopedFailureThreshold&&) = delete;
0298   ScopedFailureThreshold& operator=(ScopedFailureThreshold&&) = delete;
0299 
0300   ~ScopedFailureThreshold() noexcept;
0301 
0302  private:
0303   Level m_previousLevel{getFailureThreshold()};
0304 };
0305 
0306 /// @}
0307 
0308 /// @brief abstract base class for printing debug output
0309 ///
0310 /// Implementations of this interface need to define how and where to @a print
0311 /// debug messages (e.g. to a file, to a stream into a database etc).
0312 class OutputPrintPolicy {
0313  public:
0314   /// virtual default destructor
0315   virtual ~OutputPrintPolicy() = default;
0316 
0317   /// @brief handle output of debug message
0318   ///
0319   /// @param [in] lvl   debug output level of message
0320   /// @param [in] input text of debug message
0321   virtual void flush(const Level& lvl, const std::string& input) = 0;
0322 
0323   /// Return the name of the print policy
0324   /// @return the name
0325   virtual const std::string& name() const = 0;
0326 
0327   /// Make a copy of this print policy with a new name
0328   /// @param name the new name
0329   /// @return the copy
0330   virtual std::unique_ptr<OutputPrintPolicy> clone(
0331       const std::string& name) const = 0;
0332 };
0333 
0334 /// @brief abstract base class for filtering debug output
0335 ///
0336 /// Implementations of this interface need to define whether a debug message
0337 /// with a certain debug level is processed or filtered out.
0338 class OutputFilterPolicy {
0339  public:
0340   /// virtual default destructor
0341   virtual ~OutputFilterPolicy() = default;
0342 
0343   /// @brief decide whether a debug message should be processed
0344   ///
0345   /// @param [in] lvl debug level of debug message
0346   ///
0347   /// @return @c true of debug message should be processed, @c false if debug
0348   ///         message should be skipped
0349   virtual bool doPrint(const Level& lvl) const = 0;
0350 
0351   /// Get the level of this filter policy
0352   /// @return the levele
0353   virtual Level level() const = 0;
0354 
0355   /// Make a copy of this filter policy with a new level
0356   /// @param level the new level
0357   /// @return the new copy
0358   virtual std::unique_ptr<OutputFilterPolicy> clone(Level level) const = 0;
0359 };
0360 
0361 /// @brief default filter policy for debug messages
0362 ///
0363 /// All debug messages with a debug level equal or larger to the specified
0364 /// threshold level are processed.
0365 class DefaultFilterPolicy final : public OutputFilterPolicy {
0366  public:
0367   /// @brief constructor
0368   ///
0369   /// @param [in] lvl threshold debug level
0370   explicit DefaultFilterPolicy(Level lvl) : m_level(lvl) {
0371     if (lvl > getFailureThreshold()) {
0372       throw ThresholdFailure(
0373           "Requested debug level is incompatible with "
0374           "the ACTS_LOG_FAILURE_THRESHOLD=" +
0375           std::string{levelName(getFailureThreshold())} +
0376           " configuration. See "
0377           "https://cern.ch/acts-log-thresh");
0378     }
0379   }
0380 
0381   /// virtual default destructor
0382   ~DefaultFilterPolicy() override = default;
0383 
0384   /// @brief decide whether a debug message should be processed
0385   ///
0386   /// @param [in] lvl debug level of debug message
0387   ///
0388   /// @return @c true if @p lvl >= #m_level, otherwise @c false
0389   bool doPrint(const Level& lvl) const override { return m_level <= lvl; }
0390 
0391   /// Get the level of this filter policy
0392   /// @return the levele
0393   Level level() const override { return m_level; }
0394 
0395   /// Make a copy of this filter policy with a new level
0396   /// @param level the new level
0397   /// @return the new copy
0398   std::unique_ptr<OutputFilterPolicy> clone(Level level) const override {
0399     return std::make_unique<DefaultFilterPolicy>(level);
0400   }
0401 
0402  private:
0403   /// threshold debug level for messages to be processed
0404   Level m_level;
0405 };
0406 
0407 /// @brief base class for decorating the debug output
0408 ///
0409 /// Derived classes may augment the debug message with additional information.
0410 /// Chaining different decorators is possible to customize the output to your
0411 /// needs.
0412 class OutputDecorator : public OutputPrintPolicy {
0413  public:
0414   /// @brief constructor wrapping actual output print policy
0415   ///
0416   /// @param [in] wrappee output print policy object which is wrapped by this
0417   ///        decorator object
0418   explicit OutputDecorator(std::unique_ptr<OutputPrintPolicy> wrappee)
0419       : m_wrappee(std::move(wrappee)) {}
0420 
0421   /// @brief flush the debug message to the destination stream
0422   ///
0423   /// @param [in] lvl   debug level of debug message
0424   /// @param [in] input text of debug message
0425   ///
0426   /// This function delegates the flushing of the debug message to its wrapped
0427   /// object.
0428   void flush(const Level& lvl, const std::string& input) override {
0429     m_wrappee->flush(lvl, input);
0430   }
0431 
0432   /// Return the name of the output decorator (forwards to wrappee)
0433   /// @return the name
0434   const std::string& name() const override { return m_wrappee->name(); }
0435 
0436  protected:
0437   /// wrapped object for printing the debug message
0438   std::unique_ptr<OutputPrintPolicy> m_wrappee;
0439 };
0440 
0441 /// @brief decorate debug message with a name
0442 ///
0443 /// The debug message is complemented with a name.
0444 class NamedOutputDecorator final : public OutputDecorator {
0445  public:
0446   /// @brief constructor
0447   ///
0448   /// @param [in] wrappee  output print policy object to be wrapped
0449   /// @param [in] name     name to be added to debug message
0450   /// @param [in] maxWidth maximum width of field used for name
0451   NamedOutputDecorator(std::unique_ptr<OutputPrintPolicy> wrappee,
0452                        const std::string& name, unsigned int maxWidth = 15)
0453       : OutputDecorator(std::move(wrappee)),
0454         m_name(name),
0455         m_maxWidth(maxWidth) {}
0456 
0457   /// @brief flush the debug message to the destination stream
0458   ///
0459   /// @param [in] lvl   debug level of debug message
0460   /// @param [in] input text of debug message
0461   ///
0462   /// This function prepends the given name to the debug message and then
0463   /// delegates the flushing of the whole message to its wrapped object.
0464   void flush(const Level& lvl, const std::string& input) override {
0465     std::ostringstream os;
0466     os << std::left << std::setw(m_maxWidth) << m_name.substr(0, m_maxWidth - 3)
0467        << input;
0468     OutputDecorator::flush(lvl, os.str());
0469   }
0470 
0471   /// Make a copy of this print policy with a new name
0472   /// @param name the new name
0473   /// @return the copy
0474   std::unique_ptr<OutputPrintPolicy> clone(
0475       const std::string& name) const override {
0476     return std::make_unique<NamedOutputDecorator>(m_wrappee->clone(name), name,
0477                                                   m_maxWidth);
0478   }
0479 
0480   /// Get this named output decorators name
0481   /// @return the name
0482   const std::string& name() const override { return m_name; }
0483 
0484  private:
0485   /// name to be prepended
0486   std::string m_name;
0487 
0488   /// maximum width of field for printing the name
0489   unsigned int m_maxWidth;
0490 };
0491 
0492 /// @brief decorate debug message with a time stamp
0493 ///
0494 /// The debug message is complemented with a time stamp.
0495 class TimedOutputDecorator final : public OutputDecorator {
0496  public:
0497   /// @brief constructor
0498   ///
0499   /// @param [in] wrappee output print policy object to be wrapped
0500   /// @param [in] format  format of time stamp (see std::strftime)
0501   explicit TimedOutputDecorator(std::unique_ptr<OutputPrintPolicy> wrappee,
0502                                 const std::string& format = "%X")
0503       : OutputDecorator(std::move(wrappee)), m_format(format) {}
0504 
0505   /// @brief flush the debug message to the destination stream
0506   ///
0507   /// @param [in] lvl   debug level of debug message
0508   /// @param [in] input text of debug message
0509   ///
0510   /// This function prepends a time stamp to the debug message and then
0511   /// delegates the flushing of the whole message to its wrapped object.
0512   void flush(const Level& lvl, const std::string& input) override {
0513     std::ostringstream os;
0514     os << std::left << std::setw(12) << now() << input;
0515     OutputDecorator::flush(lvl, os.str());
0516   }
0517 
0518   /// Make a copy of this print policy with a new name
0519   /// @param name the new name
0520   /// @return the copy
0521   std::unique_ptr<OutputPrintPolicy> clone(
0522       const std::string& name) const override {
0523     return std::make_unique<TimedOutputDecorator>(m_wrappee->clone(name),
0524                                                   m_format);
0525   }
0526 
0527  private:
0528   /// @brief get current time stamp
0529   ///
0530   /// @return current time stamp as string
0531   std::string now() const {
0532     char buffer[20];
0533     time_t t{};
0534     std::time(&t);
0535     struct tm tbuf{};
0536     std::strftime(buffer, sizeof(buffer), m_format.c_str(),
0537                   localtime_r(&t, &tbuf));
0538     return buffer;
0539   }
0540 
0541   /// format of the time stamp (see std::strftime for details)
0542   std::string m_format;
0543 };
0544 
0545 /// @brief decorate debug message with a thread ID
0546 ///
0547 /// The debug message is complemented with a thread ID.
0548 class ThreadOutputDecorator final : public OutputDecorator {
0549  public:
0550   /// @brief constructor
0551   ///
0552   /// @param [in] wrappee output print policy object to be wrapped
0553   explicit ThreadOutputDecorator(std::unique_ptr<OutputPrintPolicy> wrappee)
0554       : OutputDecorator(std::move(wrappee)) {}
0555 
0556   /// @brief flush the debug message to the destination stream
0557   ///
0558   /// @param [in] lvl   debug level of debug message
0559   /// @param [in] input text of debug message
0560   ///
0561   /// This function prepends the thread ID to the debug message and then
0562   /// delegates the flushing of the whole message to its wrapped object.
0563   void flush(const Level& lvl, const std::string& input) override {
0564     std::ostringstream os;
0565     os << std::left << std::setw(20) << std::this_thread::get_id() << input;
0566     OutputDecorator::flush(lvl, os.str());
0567   }
0568 
0569   /// Make a copy of this print policy with a new name
0570   /// @param name the new name
0571   /// @return the copy
0572   std::unique_ptr<OutputPrintPolicy> clone(
0573       const std::string& name) const override {
0574     return std::make_unique<ThreadOutputDecorator>(m_wrappee->clone(name));
0575   }
0576 };
0577 
0578 /// @brief decorate debug message with its debug level
0579 ///
0580 /// The debug message is complemented with its debug level.
0581 class LevelOutputDecorator final : public OutputDecorator {
0582  public:
0583   /// @brief constructor
0584   ///
0585   /// @param [in] wrappee output print policy object to be wrapped
0586   explicit LevelOutputDecorator(std::unique_ptr<OutputPrintPolicy> wrappee)
0587       : OutputDecorator(std::move(wrappee)) {}
0588 
0589   /// @brief flush the debug message to the destination stream
0590   ///
0591   /// @param [in] lvl   debug level of debug message
0592   /// @param [in] input text of debug message
0593   ///
0594   /// This function prepends the debug level to the debug message and then
0595   /// delegates the flushing of the whole message to its wrapped object.
0596   void flush(const Level& lvl, const std::string& input) override {
0597     std::ostringstream os;
0598     os << std::left << std::setw(10) << toString(lvl) << input;
0599     OutputDecorator::flush(lvl, os.str());
0600   }
0601 
0602   /// Make a copy of this print policy with a new name
0603   /// @param name the new name
0604   /// @return the copy
0605   std::unique_ptr<OutputPrintPolicy> clone(
0606       const std::string& name) const override {
0607     return std::make_unique<LevelOutputDecorator>(m_wrappee->clone(name));
0608   }
0609 
0610  private:
0611   /// @brief convert debug level to string
0612   ///
0613   /// @param [in] lvl debug level
0614   ///
0615   /// @return string representation of debug level
0616   std::string toString(const Level& lvl) const {
0617     static const char* const buffer[] = {"VERBOSE", "DEBUG", "INFO",
0618                                          "WARNING", "ERROR", "FATAL"};
0619     return buffer[lvl];
0620   }
0621 };
0622 
0623 /// @brief default print policy for debug messages
0624 ///
0625 /// This class allows to print debug messages without further modifications to
0626 /// a specified output stream.
0627 class DefaultPrintPolicy final : public OutputPrintPolicy {
0628  public:
0629   /// @brief constructor
0630   ///
0631   /// @param [in] out pointer to output stream object
0632   ///
0633   /// @pre @p out is non-zero
0634   explicit DefaultPrintPolicy(std::ostream* out = &std::cout) : m_out(out) {}
0635 
0636   /// @brief flush the debug message to the destination stream
0637   ///
0638   /// @param [in] lvl   debug level of debug message
0639   /// @param [in] input text of debug message
0640   void flush(const Level& lvl, const std::string& input) final {
0641     // Mutex to serialize access to std::cout
0642     static std::mutex s_stdoutMutex;
0643     std::unique_lock lock{s_stdoutMutex,
0644                           std::defer_lock};  // prep empty, we might not need it
0645 
0646     if (m_out == &std::cout) {
0647       lock.lock();  // lock only if we are printing to std::cout
0648     }
0649 
0650     (*m_out) << input << std::endl;
0651     if (lvl >= getFailureThreshold()) {
0652       throw ThresholdFailure(
0653           "Previous debug message exceeds the "
0654           "ACTS_LOG_FAILURE_THRESHOLD=" +
0655           std::string{levelName(getFailureThreshold())} +
0656           " configuration, bailing out. See "
0657           "https://acts.readthedocs.io/en/latest/core/misc/"
0658           "logging.html#logging-thresholds");
0659     }
0660   }
0661 
0662   /// Fulfill @c OutputPrintPolicy interface. This policy doesn't actually have a
0663   /// name, so the assumption is that somewhere in the decorator hierarchy,
0664   /// there is something that returns a name without delegating to a wrappee,
0665   /// before reaching this overload.
0666   /// @note This method will throw an exception
0667   /// @return the name, but it never returns
0668   const std::string& name() const override {
0669     throw std::runtime_error{
0670         "Default print policy doesn't have a name. Is there no named output in "
0671         "the decorator chain?"};
0672   };
0673 
0674   /// Make a copy of this print policy with a new name
0675   /// @return the copy
0676   std::unique_ptr<OutputPrintPolicy> clone(
0677       const std::string& /*name*/) const override {
0678     return std::make_unique<DefaultPrintPolicy>(m_out);
0679   };
0680 
0681  private:
0682   /// pointer to destination output stream
0683   std::ostream* m_out;
0684 };
0685 
0686 /// @}
0687 
0688 }  // namespace Logging
0689 
0690 /// @brief class for printing debug output
0691 /// @ingroup logging
0692 ///
0693 /// This class provides the user interface for printing debug messages with
0694 /// different levels of severity.
0695 ///
0696 class Logger {
0697  public:
0698   /// @brief construct from output print and filter policy
0699   ///
0700   /// @param [in] pPrint  policy for printing debug messages
0701   /// @param [in] pFilter policy for filtering debug messages
0702   Logger(std::unique_ptr<Logging::OutputPrintPolicy> pPrint,
0703          std::unique_ptr<Logging::OutputFilterPolicy> pFilter)
0704       : m_printPolicy(std::move(pPrint)), m_filterPolicy(std::move(pFilter)) {}
0705 
0706   /// @brief decide whether a message with a given debug level has to be printed
0707   ///
0708   /// @param [in] lvl debug level of debug message
0709   ///
0710   /// @return @c true if debug message should be printed, otherwise @c false
0711   bool doPrint(const Logging::Level& lvl) const {
0712     return m_filterPolicy->doPrint(lvl);
0713   }
0714 
0715   /// @brief log a debug message
0716   ///
0717   /// @param [in] lvl debug level of debug message
0718   /// @param [in] input text of debug message
0719   void log(const Logging::Level& lvl, const std::string& input) const {
0720     if (doPrint(lvl)) {
0721       m_printPolicy->flush(lvl, input);
0722     }
0723   }
0724 
0725   /// Return the print policy for this logger
0726   /// @return the print policy
0727   const Logging::OutputPrintPolicy& printPolicy() const {
0728     return *m_printPolicy;
0729   }
0730 
0731   /// Return the filter policy for this logger
0732   /// @return the filter policy
0733   const Logging::OutputFilterPolicy& filterPolicy() const {
0734     return *m_filterPolicy;
0735   }
0736 
0737   /// Return the level of the filter policy of this logger
0738   /// @return the level
0739   Logging::Level level() const { return m_filterPolicy->level(); }
0740 
0741   /// Return the name of the print policy of this logger
0742   /// @return the name
0743   const std::string& name() const { return m_printPolicy->name(); }
0744 
0745   /// Make a copy of this logger, optionally changing the name or the level
0746   /// @param _name the optional new name
0747   /// @param _level the optional new level
0748   /// @return Unique pointer to a cloned logger
0749   std::unique_ptr<Logger> clone(
0750       const std::optional<std::string>& _name = std::nullopt,
0751       const std::optional<Logging::Level>& _level = std::nullopt) const {
0752     return std::make_unique<Logger>(
0753         m_printPolicy->clone(_name.value_or(name())),
0754         m_filterPolicy->clone(_level.value_or(level())));
0755   }
0756 
0757   /// Make a copy of the logger, with a new level. Convenience function for
0758   /// if you only want to change the level but not the name.
0759   /// @param _level the new level
0760   /// @return the new logger
0761   std::unique_ptr<Logger> clone(Logging::Level _level) const {
0762     return clone(std::nullopt, _level);
0763   }
0764 
0765   /// Make a copy of the logger, with a suffix added to the end of it's
0766   /// name. You can also optionally supply a new level
0767   /// @param suffix the suffix to add to the end of the name
0768   /// @param _level the optional new level
0769   /// @return Unique pointer to a cloned logger with modified name
0770   std::unique_ptr<Logger> cloneWithSuffix(
0771       const std::string& suffix,
0772       std::optional<Logging::Level> _level = std::nullopt) const {
0773     return clone(name() + suffix, _level.value_or(level()));
0774   }
0775 
0776   /// Helper function so a logger reference can be used as is with the logging
0777   /// macros
0778   /// @return Reference to this logger
0779   const Logger& operator()() const { return *this; }
0780 
0781  private:
0782   /// policy object for printing debug messages
0783   std::unique_ptr<Logging::OutputPrintPolicy> m_printPolicy;
0784 
0785   /// policy object for filtering debug messages
0786   std::unique_ptr<Logging::OutputFilterPolicy> m_filterPolicy;
0787 };
0788 
0789 /// @brief get default debug output logger
0790 ///
0791 /// @param [in] name       name of the logger instance
0792 /// @param [in] lvl        debug threshold level
0793 /// @param [in] log_stream output stream used for printing debug messages
0794 ///
0795 /// This function returns a pointer to a Logger instance with the following
0796 /// decorations enabled:
0797 /// - time stamps
0798 /// - name of logging instance
0799 /// - debug level
0800 ///
0801 /// @return pointer to logging instance
0802 std::unique_ptr<const Logger> getDefaultLogger(
0803     const std::string& name, const Logging::Level& lvl,
0804     std::ostream* log_stream = &std::cout);
0805 
0806 /// Get a dummy logger that discards all output
0807 /// @return Reference to dummy logger instance
0808 const Logger& getDummyLogger();
0809 
0810 }  // namespace Acts