Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:01:55

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