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