Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-05 08:03:16

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