Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-05 09:55:24

0001 /// \file ROOT/RLogger.hxx
0002 /// \ingroup Base ROOT7
0003 /// \author Axel Naumann <axel@cern.ch>
0004 /// \date 2015-03-29
0005 
0006 /*************************************************************************
0007  * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers.               *
0008  * All rights reserved.                                                  *
0009  *                                                                       *
0010  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0011  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0012  *************************************************************************/
0013 
0014 #ifndef ROOT_RLogger
0015 #define ROOT_RLogger
0016 
0017 #include <atomic>
0018 #include <list>
0019 #include <memory>
0020 #include <mutex>
0021 #include <sstream>
0022 #include <string>
0023 #include <utility>
0024 
0025 namespace ROOT {
0026 
0027 class RLogEntry;
0028 class RLogManager;
0029 
0030 /**
0031  Kinds of diagnostics.
0032  */
0033 enum class ELogLevel : unsigned char {
0034    kUnset,
0035    kFatal,   ///< An error which causes further processing to be unreliable
0036    kError,   ///< An error
0037    kWarning, ///< Warnings about likely unexpected behavior
0038    kInfo,    ///< Informational messages; used for instance for tracing
0039    kDebug    ///< Debug information; only useful for developers; can have added verbosity up to 255-kDebug.
0040 };
0041 
0042 inline ELogLevel operator+(ELogLevel severity, int offset)
0043 {
0044    return static_cast<ELogLevel>(static_cast<int>(severity) + offset);
0045 }
0046 
0047 /**
0048  Keep track of emitted errors and warnings.
0049  */
0050 class RLogDiagCount {
0051 protected:
0052    std::atomic<long long> fNumWarnings{0ll};    /// Number of warnings.
0053    std::atomic<long long> fNumErrors{0ll};      /// Number of errors.
0054    std::atomic<long long> fNumFatalErrors{0ll}; /// Number of fatal errors.
0055 
0056 public:
0057    /// Returns the current number of warnings.
0058    long long GetNumWarnings() const { return fNumWarnings; }
0059 
0060    /// Returns the current number of errors.
0061    long long GetNumErrors() const { return fNumErrors; }
0062 
0063    /// Returns the current number of fatal errors.
0064    long long GetNumFatalErrors() const { return fNumFatalErrors; }
0065 
0066    /// Increase warning or error count.
0067    void Increment(ELogLevel severity)
0068    {
0069       switch (severity) {
0070       case ELogLevel::kFatal: ++fNumFatalErrors; break;
0071       case ELogLevel::kError: ++fNumErrors; break;
0072       case ELogLevel::kWarning: ++fNumWarnings; break;
0073       default:;
0074       }
0075    }
0076 };
0077 
0078 /**
0079  Abstract RLogHandler base class. ROOT logs everything from info to error
0080  to entities of this class.
0081  */
0082 class RLogHandler {
0083 public:
0084    virtual ~RLogHandler();
0085    /// Emit a log entry.
0086    /// \param entry - the RLogEntry to be emitted.
0087    /// \returns false if further emission of this Log should be suppressed.
0088    ///
0089    /// \note This function is called concurrently; log emission must be locked
0090    /// if needed. (The default log handler using ROOT's DefaultErrorHandler is locked.)
0091    virtual bool Emit(const RLogEntry &entry) = 0;
0092 };
0093 
0094 /**
0095  A log configuration for a channel, e.g. "RHist".
0096  Each ROOT module has its own log, with potentially distinct verbosity.
0097  */
0098 class RLogChannel : public RLogDiagCount {
0099    /// Name as shown in diagnostics
0100    std::string fName;
0101 
0102    /// Verbosity of this channel. By default, use the global verbosity.
0103    ELogLevel fVerbosity = ELogLevel::kUnset;
0104 
0105 public:
0106    /// Construct an anonymous channel.
0107    RLogChannel() = default;
0108 
0109    /// Construct an anonymous channel with a default verbosity.
0110    explicit RLogChannel(ELogLevel verbosity) : fVerbosity(verbosity) {}
0111 
0112    /// Construct a log channel given its name, which is part of the diagnostics.
0113    RLogChannel(const std::string &name) : fName(name) {}
0114 
0115    ELogLevel SetVerbosity(ELogLevel verbosity)
0116    {
0117       std::swap(fVerbosity, verbosity);
0118       return verbosity;
0119    }
0120    ELogLevel GetVerbosity() const { return fVerbosity; }
0121    ELogLevel GetEffectiveVerbosity(const RLogManager &mgr) const;
0122 
0123    const std::string &GetName() const { return fName; }
0124 };
0125 
0126 /**
0127  A RLogHandler that multiplexes diagnostics to different client `RLogHandler`s
0128  and keeps track of the sum of `RLogDiagCount`s for all channels.
0129 
0130  `RLogHandler::Get()` returns the process's (static) log manager.
0131  */
0132 
0133 class RLogManager : public RLogChannel, public RLogHandler {
0134    std::mutex fMutex;
0135    std::list<std::unique_ptr<RLogHandler>> fHandlers;
0136 
0137 public:
0138    /// Initialize taking a RLogHandler.
0139    RLogManager(std::unique_ptr<RLogHandler> lh) : RLogChannel(ELogLevel::kWarning)
0140    {
0141       fHandlers.emplace_back(std::move(lh));
0142    }
0143 
0144    static RLogManager &Get();
0145 
0146    /// Add a RLogHandler in the front - to be called before all others.
0147    void PushFront(std::unique_ptr<RLogHandler> handler) { fHandlers.emplace_front(std::move(handler)); }
0148 
0149    /// Add a RLogHandler in the back - to be called after all others.
0150    void PushBack(std::unique_ptr<RLogHandler> handler) { fHandlers.emplace_back(std::move(handler)); }
0151 
0152    /// Remove and return the given log handler. Returns `nullptr` if not found.
0153    std::unique_ptr<RLogHandler> Remove(RLogHandler *handler);
0154 
0155    // Emit a `RLogEntry` to the RLogHandlers.
0156    // Returns false if further emission of this Log should be suppressed.
0157    bool Emit(const RLogEntry &entry) override;
0158 };
0159 
0160 /**
0161  A diagnostic location, part of an RLogEntry.
0162  */
0163 struct RLogLocation {
0164    std::string fFile;
0165    std::string fFuncName;
0166    int fLine; // C++11 forbids "= 0" for braced-init-list initialization.
0167 };
0168 
0169 /**
0170  A diagnostic that can be emitted by the RLogManager.
0171  One can construct a RLogEntry through RLogBuilder, including streaming into
0172  the diagnostic message and automatic emission.
0173  */
0174 
0175 class RLogEntry {
0176 public:
0177    RLogLocation fLocation;
0178    std::string fMessage;
0179    RLogChannel *fChannel = nullptr;
0180    ELogLevel fLevel = ELogLevel::kFatal;
0181 
0182    RLogEntry(ELogLevel level, RLogChannel &channel) : fChannel(&channel), fLevel(level) {}
0183    RLogEntry(ELogLevel level, RLogChannel &channel, const RLogLocation &loc)
0184       : fLocation(loc), fChannel(&channel), fLevel(level)
0185    {
0186    }
0187 
0188    bool IsDebug() const { return fLevel >= ELogLevel::kDebug; }
0189    bool IsInfo() const { return fLevel == ELogLevel::kInfo; }
0190    bool IsWarning() const { return fLevel == ELogLevel::kWarning; }
0191    bool IsError() const { return fLevel == ELogLevel::kError; }
0192    bool IsFatal() const { return fLevel == ELogLevel::kFatal; }
0193 };
0194 
0195 namespace Detail {
0196 /**
0197  Builds a diagnostic entry, emitted by the static RLogManager upon destruction of this builder,
0198  where - by definition - the RLogEntry has been completely built.
0199 
0200  This builder can be used through the utility preprocessor macros R__LOG_ERROR,
0201  R__LOG_WARNING etc like this:
0202 ~~~ {.cpp}
0203      R__LOG_INFO(ROOT::Experimental::HistLog()) << "all we know is " << 42;
0204      const int decreasedInfoLevel = 5;
0205      R__LOG_XDEBUG(ROOT::WebGUILog(), decreasedInfoLevel) << "nitty-gritty details";
0206 ~~~
0207  This will automatically capture the current class and function name, the file and line number.
0208  */
0209 
0210 class RLogBuilder : public std::ostringstream {
0211    /// The log entry to be built.
0212    RLogEntry fEntry;
0213 
0214 public:
0215    RLogBuilder(ELogLevel level, RLogChannel &channel) : fEntry(level, channel) {}
0216    RLogBuilder(ELogLevel level, RLogChannel &channel, const std::string &filename, int line,
0217                const std::string &funcname)
0218       : fEntry(level, channel, {filename, funcname, line})
0219    {
0220    }
0221 
0222    /// Emit the log entry through the static log manager.
0223    ~RLogBuilder()
0224    {
0225       fEntry.fMessage = str();
0226       RLogManager::Get().Emit(fEntry);
0227    }
0228 };
0229 } // namespace Detail
0230 
0231 /**
0232  Change the verbosity level (global or specific to the RLogChannel passed to the
0233  constructor) for the lifetime of this object.
0234  Example:
0235 ~~~ {.cpp}
0236  RLogScopedVerbosity debugThis(gFooLog, ELogLevel::kDebug);
0237  Foo::SomethingToDebug();
0238 ~~~
0239  */
0240 class RLogScopedVerbosity {
0241    RLogChannel *fChannel;
0242    ELogLevel fPrevLevel;
0243 
0244 public:
0245    RLogScopedVerbosity(RLogChannel &channel, ELogLevel verbosity)
0246       : fChannel(&channel), fPrevLevel(channel.SetVerbosity(verbosity))
0247    {
0248    }
0249    explicit RLogScopedVerbosity(ELogLevel verbosity) : RLogScopedVerbosity(RLogManager::Get(), verbosity) {}
0250    ~RLogScopedVerbosity() { fChannel->SetVerbosity(fPrevLevel); }
0251 };
0252 
0253 /**
0254  Object to count the number of warnings and errors emitted by a section of code,
0255  after construction of this type.
0256  */
0257 class RLogScopedDiagCount {
0258    RLogDiagCount *fCounter = nullptr;
0259    /// The number of the RLogDiagCount's emitted warnings at construction time of *this.
0260    long long fInitialWarnings = 0;
0261    /// The number of the RLogDiagCount's emitted errors at construction time.
0262    long long fInitialErrors = 0;
0263    /// The number of the RLogDiagCount's emitted fatal errors at construction time.
0264    long long fInitialFatalErrors = 0;
0265 
0266 public:
0267    /// Construct the scoped count given a counter (e.g. a channel or RLogManager).
0268    /// The counter's lifetime must exceed the lifetime of this object!
0269    explicit RLogScopedDiagCount(RLogDiagCount &cnt)
0270       : fCounter(&cnt), fInitialWarnings(cnt.GetNumWarnings()), fInitialErrors(cnt.GetNumErrors()),
0271         fInitialFatalErrors(cnt.GetNumFatalErrors())
0272    {
0273    }
0274 
0275    /// Construct the scoped count for any diagnostic, whatever its channel.
0276    RLogScopedDiagCount() : RLogScopedDiagCount(RLogManager::Get()) {}
0277 
0278    /// Get the number of warnings that the RLogDiagCount has emitted since construction of *this.
0279    long long GetAccumulatedWarnings() const { return fCounter->GetNumWarnings() - fInitialWarnings; }
0280 
0281    /// Get the number of errors that the RLogDiagCount has emitted since construction of *this.
0282    long long GetAccumulatedErrors() const { return fCounter->GetNumErrors() - fInitialErrors; }
0283 
0284    /// Get the number of errors that the RLogDiagCount has emitted since construction of *this.
0285    long long GetAccumulatedFatalErrors() const { return fCounter->GetNumFatalErrors() - fInitialFatalErrors; }
0286 
0287    /// Whether the RLogDiagCount has emitted a warnings since construction time of *this.
0288    bool HasWarningOccurred() const { return GetAccumulatedWarnings(); }
0289 
0290    /// Whether the RLogDiagCount has emitted an error (fatal or not) since construction time of *this.
0291    bool HasErrorOccurred() const { return GetAccumulatedErrors() + GetAccumulatedFatalErrors(); }
0292 
0293    /// Whether the RLogDiagCount has emitted an error or a warning since construction time of *this.
0294    bool HasErrorOrWarningOccurred() const { return HasWarningOccurred() || HasErrorOccurred(); }
0295 };
0296 
0297 namespace Internal {
0298 
0299 inline RLogChannel &GetChannelOrManager()
0300 {
0301    return RLogManager::Get();
0302 }
0303 inline RLogChannel &GetChannelOrManager(RLogChannel &channel)
0304 {
0305    return channel;
0306 }
0307 
0308 } // namespace Internal
0309 
0310 inline ELogLevel RLogChannel::GetEffectiveVerbosity(const RLogManager &mgr) const
0311 {
0312    if (fVerbosity == ELogLevel::kUnset)
0313       return mgr.GetVerbosity();
0314    return fVerbosity;
0315 }
0316 
0317 } // namespace ROOT
0318 
0319 #if defined(_MSC_VER)
0320 #define R__LOG_PRETTY_FUNCTION __FUNCSIG__
0321 #else
0322 #define R__LOG_PRETTY_FUNCTION __PRETTY_FUNCTION__
0323 #endif
0324 
0325 /*
0326  Some implementation details:
0327 
0328  - The conditional `RLogBuilder` use prevents stream operators from being called if
0329  verbosity is too low, i.e.:
0330  ~~~
0331  RLogScopedVerbosity silence(RLogLevel::kFatal);
0332  R__LOG_DEBUG(7) << WillNotBeCalled();
0333  ~~~
0334  - To update counts of warnings / errors / fatal errors, those RLogEntries must
0335  always be created, even if in the end their emission will be silenced. This
0336  should be fine, performance-wise, as they should not happen frequently.
0337  - Use `(condition) && RLogBuilder(...)` instead of `if (condition) RLogBuilder(...)`
0338  to prevent "ambiguous else" in invocations such as `if (something) R__LOG_DEBUG()...`.
0339  */
0340 #define R__LOG_TO_CHANNEL(SEVERITY, CHANNEL)                                                                     \
0341    ((SEVERITY < ROOT::ELogLevel::kInfo + 0) ||                                                                   \
0342     ROOT::Internal::GetChannelOrManager(CHANNEL).GetEffectiveVerbosity(ROOT::RLogManager::Get()) >= SEVERITY) && \
0343       ROOT::Detail::RLogBuilder(SEVERITY, ROOT::Internal::GetChannelOrManager(CHANNEL), __FILE__, __LINE__,      \
0344                                 R__LOG_PRETTY_FUNCTION)
0345 
0346 /// \name LogMacros
0347 /// Macros to log diagnostics.
0348 /// ~~~ {.cpp}
0349 ///     R__LOG_INFO(ROOT::HistLog()) << "all we know is " << 42;
0350 ///
0351 ///     RLogScopedVerbosity verbose(kDebug + 5);
0352 ///     const int decreasedInfoLevel = 5;
0353 ///     R__LOG_DEBUG(ROOT::WebGUILog(), decreasedInfoLevel) << "nitty-gritty details";
0354 /// ~~~
0355 ///\{
0356 #define R__LOG_FATAL(...) R__LOG_TO_CHANNEL(ROOT::ELogLevel::kFatal, __VA_ARGS__)
0357 #define R__LOG_ERROR(...) R__LOG_TO_CHANNEL(ROOT::ELogLevel::kError, __VA_ARGS__)
0358 #define R__LOG_WARNING(...) R__LOG_TO_CHANNEL(ROOT::ELogLevel::kWarning, __VA_ARGS__)
0359 #define R__LOG_INFO(...) R__LOG_TO_CHANNEL(ROOT::ELogLevel::kInfo, __VA_ARGS__)
0360 #define R__LOG_DEBUG(DEBUGLEVEL, ...) R__LOG_TO_CHANNEL(ROOT::ELogLevel::kDebug + DEBUGLEVEL, __VA_ARGS__)
0361 ///\}
0362 
0363 #endif