File indexing completed on 2025-01-18 10:10:45
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #ifndef ROOT7_RLogger
0017 #define ROOT7_RLogger
0018
0019 #include <atomic>
0020 #include <list>
0021 #include <memory>
0022 #include <mutex>
0023 #include <sstream>
0024 #include <string>
0025 #include <utility>
0026
0027 namespace ROOT {
0028 namespace Experimental {
0029
0030 class RLogEntry;
0031 class RLogManager;
0032
0033
0034
0035
0036 enum class ELogLevel : unsigned char {
0037 kUnset,
0038 kFatal,
0039 kError,
0040 kWarning,
0041 kInfo,
0042 kDebug
0043 };
0044
0045 inline ELogLevel operator+(ELogLevel severity, int offset)
0046 {
0047 return static_cast<ELogLevel>(static_cast<int>(severity) + offset);
0048 }
0049
0050
0051
0052
0053 class RLogDiagCount {
0054 protected:
0055 std::atomic<long long> fNumWarnings{0ll};
0056 std::atomic<long long> fNumErrors{0ll};
0057 std::atomic<long long> fNumFatalErrors{0ll};
0058
0059 public:
0060
0061 long long GetNumWarnings() const { return fNumWarnings; }
0062
0063
0064 long long GetNumErrors() const { return fNumErrors; }
0065
0066
0067 long long GetNumFatalErrors() const { return fNumFatalErrors; }
0068
0069
0070 void Increment(ELogLevel severity)
0071 {
0072 switch (severity) {
0073 case ELogLevel::kFatal: ++fNumFatalErrors; break;
0074 case ELogLevel::kError: ++fNumErrors; break;
0075 case ELogLevel::kWarning: ++fNumWarnings; break;
0076 default:;
0077 }
0078 }
0079 };
0080
0081
0082
0083
0084
0085 class RLogHandler {
0086 public:
0087 virtual ~RLogHandler();
0088
0089
0090
0091
0092
0093
0094 virtual bool Emit(const RLogEntry &entry) = 0;
0095 };
0096
0097
0098
0099
0100
0101 class RLogChannel : public RLogDiagCount {
0102
0103 std::string fName;
0104
0105
0106 ELogLevel fVerbosity = ELogLevel::kUnset;
0107
0108 public:
0109
0110 RLogChannel() = default;
0111
0112
0113 explicit RLogChannel(ELogLevel verbosity) : fVerbosity(verbosity) {}
0114
0115
0116 RLogChannel(const std::string &name) : fName(name) {}
0117
0118 ELogLevel SetVerbosity(ELogLevel verbosity)
0119 {
0120 std::swap(fVerbosity, verbosity);
0121 return verbosity;
0122 }
0123 ELogLevel GetVerbosity() const { return fVerbosity; }
0124 ELogLevel GetEffectiveVerbosity(const RLogManager &mgr) const;
0125
0126 const std::string &GetName() const { return fName; }
0127 };
0128
0129
0130
0131
0132
0133
0134
0135
0136 class RLogManager : public RLogChannel, public RLogHandler {
0137 std::mutex fMutex;
0138 std::list<std::unique_ptr<RLogHandler>> fHandlers;
0139
0140 public:
0141
0142 RLogManager(std::unique_ptr<RLogHandler> lh) : RLogChannel(ELogLevel::kWarning)
0143 {
0144 fHandlers.emplace_back(std::move(lh));
0145 }
0146
0147 static RLogManager &Get();
0148
0149
0150 void PushFront(std::unique_ptr<RLogHandler> handler) { fHandlers.emplace_front(std::move(handler)); }
0151
0152
0153 void PushBack(std::unique_ptr<RLogHandler> handler) { fHandlers.emplace_back(std::move(handler)); }
0154
0155
0156 std::unique_ptr<RLogHandler> Remove(RLogHandler *handler);
0157
0158
0159
0160 bool Emit(const RLogEntry &entry) override;
0161 };
0162
0163
0164
0165
0166 struct RLogLocation {
0167 std::string fFile;
0168 std::string fFuncName;
0169 int fLine;
0170 };
0171
0172
0173
0174
0175
0176
0177
0178 class RLogEntry {
0179 public:
0180 RLogLocation fLocation;
0181 std::string fMessage;
0182 RLogChannel *fChannel = nullptr;
0183 ELogLevel fLevel = ELogLevel::kFatal;
0184
0185 RLogEntry(ELogLevel level, RLogChannel &channel) : fChannel(&channel), fLevel(level) {}
0186 RLogEntry(ELogLevel level, RLogChannel &channel, const RLogLocation &loc)
0187 : fLocation(loc), fChannel(&channel), fLevel(level)
0188 {
0189 }
0190
0191 bool IsDebug() const { return fLevel >= ELogLevel::kDebug; }
0192 bool IsInfo() const { return fLevel == ELogLevel::kInfo; }
0193 bool IsWarning() const { return fLevel == ELogLevel::kWarning; }
0194 bool IsError() const { return fLevel == ELogLevel::kError; }
0195 bool IsFatal() const { return fLevel == ELogLevel::kFatal; }
0196 };
0197
0198 namespace Detail {
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213 class RLogBuilder : public std::ostringstream {
0214
0215 RLogEntry fEntry;
0216
0217 public:
0218 RLogBuilder(ELogLevel level, RLogChannel &channel) : fEntry(level, channel) {}
0219 RLogBuilder(ELogLevel level, RLogChannel &channel, const std::string &filename, int line,
0220 const std::string &funcname)
0221 : fEntry(level, channel, {filename, funcname, line})
0222 {
0223 }
0224
0225
0226 ~RLogBuilder()
0227 {
0228 fEntry.fMessage = str();
0229 RLogManager::Get().Emit(fEntry);
0230 }
0231 };
0232 }
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243 class RLogScopedVerbosity {
0244 RLogChannel *fChannel;
0245 ELogLevel fPrevLevel;
0246
0247 public:
0248 RLogScopedVerbosity(RLogChannel &channel, ELogLevel verbosity)
0249 : fChannel(&channel), fPrevLevel(channel.SetVerbosity(verbosity))
0250 {
0251 }
0252 explicit RLogScopedVerbosity(ELogLevel verbosity) : RLogScopedVerbosity(RLogManager::Get(), verbosity) {}
0253 ~RLogScopedVerbosity() { fChannel->SetVerbosity(fPrevLevel); }
0254 };
0255
0256
0257
0258
0259
0260 class RLogScopedDiagCount {
0261 RLogDiagCount *fCounter = nullptr;
0262
0263 long long fInitialWarnings = 0;
0264
0265 long long fInitialErrors = 0;
0266
0267 long long fInitialFatalErrors = 0;
0268
0269 public:
0270
0271
0272 explicit RLogScopedDiagCount(RLogDiagCount &cnt)
0273 : fCounter(&cnt), fInitialWarnings(cnt.GetNumWarnings()), fInitialErrors(cnt.GetNumErrors()),
0274 fInitialFatalErrors(cnt.GetNumFatalErrors())
0275 {
0276 }
0277
0278
0279 RLogScopedDiagCount() : RLogScopedDiagCount(RLogManager::Get()) {}
0280
0281
0282 long long GetAccumulatedWarnings() const { return fCounter->GetNumWarnings() - fInitialWarnings; }
0283
0284
0285 long long GetAccumulatedErrors() const { return fCounter->GetNumErrors() - fInitialErrors; }
0286
0287
0288 long long GetAccumulatedFatalErrors() const { return fCounter->GetNumFatalErrors() - fInitialFatalErrors; }
0289
0290
0291 bool HasWarningOccurred() const { return GetAccumulatedWarnings(); }
0292
0293
0294 bool HasErrorOccurred() const { return GetAccumulatedErrors() + GetAccumulatedFatalErrors(); }
0295
0296
0297 bool HasErrorOrWarningOccurred() const { return HasWarningOccurred() || HasErrorOccurred(); }
0298 };
0299
0300 namespace Internal {
0301
0302 inline RLogChannel &GetChannelOrManager()
0303 {
0304 return RLogManager::Get();
0305 }
0306 inline RLogChannel &GetChannelOrManager(RLogChannel &channel)
0307 {
0308 return channel;
0309 }
0310
0311 }
0312
0313 inline ELogLevel RLogChannel::GetEffectiveVerbosity(const RLogManager &mgr) const
0314 {
0315 if (fVerbosity == ELogLevel::kUnset)
0316 return mgr.GetVerbosity();
0317 return fVerbosity;
0318 }
0319
0320 }
0321 }
0322
0323 #if defined(_MSC_VER)
0324 #define R__LOG_PRETTY_FUNCTION __FUNCSIG__
0325 #else
0326 #define R__LOG_PRETTY_FUNCTION __PRETTY_FUNCTION__
0327 #endif
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344 #define R__LOG_TO_CHANNEL(SEVERITY, CHANNEL) \
0345 ((SEVERITY < ROOT::Experimental::ELogLevel::kInfo + 0) || \
0346 ROOT::Experimental::Internal::GetChannelOrManager(CHANNEL).GetEffectiveVerbosity( \
0347 ROOT::Experimental::RLogManager::Get()) >= SEVERITY) && \
0348 ROOT::Experimental::Detail::RLogBuilder(SEVERITY, ROOT::Experimental::Internal::GetChannelOrManager(CHANNEL), \
0349 __FILE__, __LINE__, R__LOG_PRETTY_FUNCTION)
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361 #define R__LOG_FATAL(...) R__LOG_TO_CHANNEL(ROOT::Experimental::ELogLevel::kFatal, __VA_ARGS__)
0362 #define R__LOG_ERROR(...) R__LOG_TO_CHANNEL(ROOT::Experimental::ELogLevel::kError, __VA_ARGS__)
0363 #define R__LOG_WARNING(...) R__LOG_TO_CHANNEL(ROOT::Experimental::ELogLevel::kWarning, __VA_ARGS__)
0364 #define R__LOG_INFO(...) R__LOG_TO_CHANNEL(ROOT::Experimental::ELogLevel::kInfo, __VA_ARGS__)
0365 #define R__LOG_DEBUG(DEBUGLEVEL, ...) R__LOG_TO_CHANNEL(ROOT::Experimental::ELogLevel::kDebug + DEBUGLEVEL, __VA_ARGS__)
0366
0367
0368 #endif