Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/Acts/Utilities/Logger.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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   do {                                                                         \
0070     if (logger().doPrint(level)) {                                             \
0071       std::ostringstream os;                                                   \
0072       os << x;                                                                 \
0073       logger().log(level, os.str());                                           \
0074     }                                                                          \
0075   }                                                                            \
0076   while(0)
0077 
0078 /// @brief macro for verbose debug output
0079 /// @ingroup Logging
0080 ///
0081 /// @param x debug message
0082 ///
0083 /// @pre @c logger() must be a valid expression in the scope where this
0084 ///      macro is used and it must return a Acts::Logger object.
0085 ///
0086 /// The debug message is printed if the current Acts::Logging::Level <=
0087 /// Acts::Logging::VERBOSE.
0088 #define ACTS_VERBOSE(x)  ACTS_LOG(Acts::Logging::VERBOSE, x)
0089 
0090 /// @brief macro for debug debug output
0091 /// @ingroup Logging
0092 ///
0093 /// @param x debug message
0094 ///
0095 /// @pre @c logger() must be a valid expression in the scope where this
0096 ///      macro is used and it must return a Acts::Logger object.
0097 ///
0098 /// The debug message is printed if the current Acts::Logging::Level <=
0099 /// Acts::Logging::DEBUG.
0100 #define ACTS_DEBUG(x)  ACTS_LOG(Acts::Logging::DEBUG, x)
0101 
0102 /// @brief macro for info debug output
0103 /// @ingroup Logging
0104 ///
0105 /// @param x debug message
0106 ///
0107 /// @pre @c logger() must be a valid expression in the scope where this
0108 ///      macro is used and it must return a Acts::Logger object.
0109 ///
0110 /// The debug message is printed if the current Acts::Logging::Level <=
0111 /// Acts::Logging::INFO.
0112 #define ACTS_INFO(x)  ACTS_LOG(Acts::Logging::INFO, x)
0113 
0114 /// @brief macro for warning debug output
0115 /// @ingroup Logging
0116 ///
0117 /// @param x debug message
0118 ///
0119 /// @pre @c logger() must be a valid expression in the scope where this
0120 ///      macro is used and it must return a Acts::Logger object.
0121 ///
0122 /// The debug message is printed if the current Acts::Logging::Level <=
0123 /// Acts::Logging::WARNING.
0124 #define ACTS_WARNING(x)  ACTS_LOG(Acts::Logging::WARNING, x)
0125 
0126 /// @brief macro for error debug output
0127 /// @ingroup Logging
0128 ///
0129 /// @param x debug message
0130 ///
0131 /// @pre @c logger() must be a valid expression in the scope where this
0132 ///      macro is used and it must return a Acts::Logger object.
0133 ///
0134 /// The debug message is printed if the current Acts::Logging::Level <=
0135 /// Acts::Logging::ERROR.
0136 #define ACTS_ERROR(x)  ACTS_LOG(Acts::Logging::ERROR, x)
0137 
0138 /// @brief macro for fatal debug output
0139 /// @ingroup Logging
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 // clang-format on
0150 
0151 namespace Acts {
0152 
0153 /// @brief debug output related helper classes and functions
0154 /// @ingroup Logging
0155 namespace Logging {
0156 /// @brief constants steering the debug output
0157 ///
0158 /// All messages with a debug level equal or higher than the currently set
0159 /// debug output level will be printed.
0160 enum Level {
0161   VERBOSE = 0,  ///< VERBOSE level
0162   DEBUG,        ///< DEBUG level
0163   INFO,         ///< INFO level
0164   WARNING,      ///< WARNING level
0165   ERROR,        ///< ERROR level
0166   FATAL,        ///< FATAL level
0167   MAX           ///< Must be kept above the maximum supported debug level
0168 };
0169 
0170 inline std::string_view levelName(Level level) {
0171   switch (level) {
0172     case Level::VERBOSE:
0173       return "VERBOSE";
0174     case Level::DEBUG:
0175       return "DEBUG";
0176     case Level::INFO:
0177       return "INFO";
0178     case Level::WARNING:
0179       return "WARNING";
0180     case Level::ERROR:
0181       return "ERROR";
0182     case Level::FATAL:
0183       return "FATAL";
0184     case Level::MAX:
0185       return "MAX";
0186     default:
0187       throw std::invalid_argument{"Unknown level"};
0188   }
0189 }
0190 
0191 #ifdef DOXYGEN
0192 /// @brief Get debug level above which an exception will be thrown after logging
0193 ///
0194 /// All messages with a debug level equal or higher than the return value of
0195 /// this function will cause an exception to be thrown after log emission.
0196 ///
0197 /// @note Depending on preprocessor settings @c ACTS_ENABLE_LOG_FAILURE_THRESHOLD
0198 ///       and @c ACTS_LOG_FAILURE_THRESHOLD, this operations is either constexpr
0199 ///       or a runtime operation.
0200 Level getFailureThreshold();
0201 
0202 #else
0203 
0204 #ifdef ACTS_ENABLE_LOG_FAILURE_THRESHOLD
0205 #ifdef ACTS_LOG_FAILURE_THRESHOLD
0206 // We have a fixed compile time log failure threshold
0207 constexpr Level getFailureThreshold() {
0208   return Level::ACTS_LOG_FAILURE_THRESHOLD;
0209 }
0210 #else
0211 Level getFailureThreshold();
0212 #endif
0213 #else
0214 constexpr Level getFailureThreshold() {
0215   // Default "NO" failure threshold
0216   return Level::MAX;
0217 }
0218 #endif
0219 
0220 #endif
0221 
0222 /// @brief Set debug level above which an exception will be thrown after logging
0223 ///
0224 /// All messages with a debug level equal or higher than @p level will
0225 /// cause an exception to be thrown after log emission.
0226 ///
0227 /// @warning The runtime log failure threshold is **global state**, therefore
0228 ///          this function is  **not threadsafe**. The intention is that this
0229 ///          level is set once, before multi-threaded execution begins, and then
0230 ///          not modified before the end of the job.
0231 /// @note This function is only available if @c ACTS_LOG_FAILURE_THRESHOLD is
0232 ///       unset, i.e. no compile-time threshold is used. Otherwise an
0233 ///       exception is thrown.
0234 void setFailureThreshold(Level level);
0235 
0236 /// Custom exception class so threshold failures can be caught
0237 class ThresholdFailure : public std::runtime_error {
0238   using std::runtime_error::runtime_error;
0239 };
0240 
0241 /// Helper class that changes the failure threshold for the duration of its
0242 /// lifetime.
0243 class ScopedFailureThreshold {
0244  public:
0245   explicit ScopedFailureThreshold(Level level) { setFailureThreshold(level); }
0246   ScopedFailureThreshold(const ScopedFailureThreshold&) = delete;
0247   ScopedFailureThreshold& operator=(const ScopedFailureThreshold&) = delete;
0248   ScopedFailureThreshold(ScopedFailureThreshold&&) = delete;
0249   ScopedFailureThreshold& operator=(ScopedFailureThreshold&&) = delete;
0250 
0251   ~ScopedFailureThreshold() noexcept;
0252 
0253  private:
0254   Level m_previousLevel{getFailureThreshold()};
0255 };
0256 
0257 /// @brief abstract base class for printing debug output
0258 ///
0259 /// Implementations of this interface need to define how and where to @a print
0260 /// debug messages (e.g. to a file, to a stream into a database etc).
0261 class OutputPrintPolicy {
0262  public:
0263   /// virtual default destructor
0264   virtual ~OutputPrintPolicy() = default;
0265 
0266   /// @brief handle output of debug message
0267   ///
0268   /// @param [in] lvl   debug output level of message
0269   /// @param [in] input text of debug message
0270   virtual void flush(const Level& lvl, const std::string& input) = 0;
0271 
0272   /// Return the name of the print policy
0273   /// @return the name
0274   virtual const std::string& name() const = 0;
0275 
0276   /// Make a copy of this print policy with a new name
0277   /// @param name the new name
0278   /// @return the copy
0279   virtual std::unique_ptr<OutputPrintPolicy> clone(
0280       const std::string& name) const = 0;
0281 };
0282 
0283 /// @brief abstract base class for filtering debug output
0284 ///
0285 /// Implementations of this interface need to define whether a debug message
0286 /// with a certain debug level is processed or filtered out.
0287 class OutputFilterPolicy {
0288  public:
0289   /// virtual default destructor
0290   virtual ~OutputFilterPolicy() = default;
0291 
0292   /// @brief decide whether a debug message should be processed
0293   ///
0294   /// @param [in] lvl debug level of debug message
0295   ///
0296   /// @return @c true of debug message should be processed, @c false if debug
0297   ///         message should be skipped
0298   virtual bool doPrint(const Level& lvl) const = 0;
0299 
0300   /// Get the level of this filter policy
0301   /// @return the levele
0302   virtual Level level() const = 0;
0303 
0304   /// Make a copy of this filter policy with a new level
0305   /// @param level the new level
0306   /// @return the new copy
0307   virtual std::unique_ptr<OutputFilterPolicy> clone(Level level) const = 0;
0308 };
0309 
0310 /// @brief default filter policy for debug messages
0311 ///
0312 /// All debug messages with a debug level equal or larger to the specified
0313 /// threshold level are processed.
0314 class DefaultFilterPolicy final : public OutputFilterPolicy {
0315  public:
0316   /// @brief constructor
0317   ///
0318   /// @param [in] lvl threshold debug level
0319   explicit DefaultFilterPolicy(Level lvl) : m_level(lvl) {
0320     if (lvl > getFailureThreshold()) {
0321       throw ThresholdFailure(
0322           "Requested debug level is incompatible with "
0323           "the ACTS_LOG_FAILURE_THRESHOLD=" +
0324           std::string{levelName(getFailureThreshold())} +
0325           " configuration. See "
0326           "https://acts.readthedocs.io/en/latest/core/misc/"
0327           "logging.html#logging-thresholds");
0328     }
0329   }
0330 
0331   /// virtual default destructor
0332   ~DefaultFilterPolicy() override = default;
0333 
0334   /// @brief decide whether a debug message should be processed
0335   ///
0336   /// @param [in] lvl debug level of debug message
0337   ///
0338   /// @return @c true if @p lvl >= #m_level, otherwise @c false
0339   bool doPrint(const Level& lvl) const override { return m_level <= lvl; }
0340 
0341   /// Get the level of this filter policy
0342   /// @return the levele
0343   Level level() const override { return m_level; }
0344 
0345   /// Make a copy of this filter policy with a new level
0346   /// @param level the new level
0347   /// @return the new copy
0348   std::unique_ptr<OutputFilterPolicy> clone(Level level) const override {
0349     return std::make_unique<DefaultFilterPolicy>(level);
0350   }
0351 
0352  private:
0353   /// threshold debug level for messages to be processed
0354   Level m_level;
0355 };
0356 
0357 /// @brief base class for decorating the debug output
0358 ///
0359 /// Derived classes may augment the debug message with additional information.
0360 /// Chaining different decorators is possible to customize the output to your
0361 /// needs.
0362 class OutputDecorator : public OutputPrintPolicy {
0363  public:
0364   /// @brief constructor wrapping actual output print policy
0365   ///
0366   /// @param [in] wrappee output print policy object which is wrapped by this
0367   ///        decorator object
0368   explicit OutputDecorator(std::unique_ptr<OutputPrintPolicy> wrappee)
0369       : m_wrappee(std::move(wrappee)) {}
0370 
0371   /// @brief flush the debug message to the destination stream
0372   ///
0373   /// @param [in] lvl   debug level of debug message
0374   /// @param [in] input text of debug message
0375   ///
0376   /// This function delegates the flushing of the debug message to its wrapped
0377   /// object.
0378   void flush(const Level& lvl, const std::string& input) override {
0379     m_wrappee->flush(lvl, input);
0380   }
0381 
0382   /// Return the name of the output decorator (forwards to wrappee)
0383   /// @return the name
0384   const std::string& name() const override { return m_wrappee->name(); }
0385 
0386  protected:
0387   /// wrapped object for printing the debug message
0388   std::unique_ptr<OutputPrintPolicy> m_wrappee;
0389 };
0390 
0391 /// @brief decorate debug message with a name
0392 ///
0393 /// The debug message is complemented with a name.
0394 class NamedOutputDecorator final : public OutputDecorator {
0395  public:
0396   /// @brief constructor
0397   ///
0398   /// @param [in] wrappee  output print policy object to be wrapped
0399   /// @param [in] name     name to be added to debug message
0400   /// @param [in] maxWidth maximum width of field used for name
0401   NamedOutputDecorator(std::unique_ptr<OutputPrintPolicy> wrappee,
0402                        const std::string& name, unsigned int maxWidth = 15)
0403       : OutputDecorator(std::move(wrappee)),
0404         m_name(name),
0405         m_maxWidth(maxWidth) {}
0406 
0407   /// @brief flush the debug message to the destination stream
0408   ///
0409   /// @param [in] lvl   debug level of debug message
0410   /// @param [in] input text of debug message
0411   ///
0412   /// This function prepends the given name to the debug message and then
0413   /// delegates the flushing of the whole message to its wrapped object.
0414   void flush(const Level& lvl, const std::string& input) override {
0415     std::ostringstream os;
0416     os << std::left << std::setw(m_maxWidth) << m_name.substr(0, m_maxWidth - 3)
0417        << input;
0418     OutputDecorator::flush(lvl, os.str());
0419   }
0420 
0421   /// Make a copy of this print policy with a new name
0422   /// @param name the new name
0423   /// @return the copy
0424   std::unique_ptr<OutputPrintPolicy> clone(
0425       const std::string& name) const override {
0426     return std::make_unique<NamedOutputDecorator>(m_wrappee->clone(name), name,
0427                                                   m_maxWidth);
0428   }
0429 
0430   /// Get this named output decorators name
0431   /// @return the name
0432   const std::string& name() const override { return m_name; }
0433 
0434  private:
0435   /// name to be prepended
0436   std::string m_name;
0437 
0438   /// maximum width of field for printing the name
0439   unsigned int m_maxWidth;
0440 };
0441 
0442 /// @brief decorate debug message with a time stamp
0443 ///
0444 /// The debug message is complemented with a time stamp.
0445 class TimedOutputDecorator final : public OutputDecorator {
0446  public:
0447   /// @brief constructor
0448   ///
0449   /// @param [in] wrappee output print policy object to be wrapped
0450   /// @param [in] format  format of time stamp (see std::strftime)
0451   TimedOutputDecorator(std::unique_ptr<OutputPrintPolicy> wrappee,
0452                        const std::string& format = "%X")
0453       : OutputDecorator(std::move(wrappee)), m_format(format) {}
0454 
0455   /// @brief flush the debug message to the destination stream
0456   ///
0457   /// @param [in] lvl   debug level of debug message
0458   /// @param [in] input text of debug message
0459   ///
0460   /// This function prepends a time stamp to the debug message and then
0461   /// delegates the flushing of the whole message to its wrapped object.
0462   void flush(const Level& lvl, const std::string& input) override {
0463     std::ostringstream os;
0464     os << std::left << std::setw(12) << now() << input;
0465     OutputDecorator::flush(lvl, os.str());
0466   }
0467 
0468   /// Make a copy of this print policy with a new name
0469   /// @param name the new name
0470   /// @return the copy
0471   std::unique_ptr<OutputPrintPolicy> clone(
0472       const std::string& name) const override {
0473     return std::make_unique<TimedOutputDecorator>(m_wrappee->clone(name),
0474                                                   m_format);
0475   }
0476 
0477  private:
0478   /// @brief get current time stamp
0479   ///
0480   /// @return current time stamp as string
0481   std::string now() const {
0482     char buffer[20];
0483     time_t t{};
0484     std::time(&t);
0485     std::strftime(buffer, sizeof(buffer), m_format.c_str(), localtime(&t));
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