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