Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:11

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