Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-03 07:52:17

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