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