Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RLogger.hxx
Go to the documentation of this file.
1/// \file ROOT/RLogger.hxx
2/// \ingroup Base ROOT7
3/// \author Axel Naumann <axel@cern.ch>
4/// \date 2015-03-29
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#ifndef ROOT7_RLogger
17#define ROOT7_RLogger
18
19#include <atomic>
20#include <list>
21#include <memory>
22#include <mutex>
23#include <sstream>
24#include <string>
25#include <utility>
26
27namespace ROOT {
28namespace Experimental {
29
30class RLogEntry;
31class RLogManager;
32
33/**
34 Kinds of diagnostics.
35 */
36enum class ELogLevel : unsigned char {
37 kUnset,
38 kFatal, ///< An error which causes further processing to be unreliable
39 kError, ///< An error
40 kWarning, ///< Warnings about likely unexpected behavior
41 kInfo, ///< Informational messages; used for instance for tracing
42 kDebug ///< Debug information; only useful for developers; can have added verbosity up to 255-kDebug.
43};
44
45inline ELogLevel operator+(ELogLevel severity, int offset)
46{
47 return static_cast<ELogLevel>(static_cast<int>(severity) + offset);
48}
49
50/**
51 Keep track of emitted errors and warnings.
52 */
54protected:
55 std::atomic<long long> fNumWarnings{0ll}; /// Number of warnings.
56 std::atomic<long long> fNumErrors{0ll}; /// Number of errors.
57 std::atomic<long long> fNumFatalErrors{0ll}; /// Number of fatal errors.
58
59public:
60 /// Returns the current number of warnings.
61 long long GetNumWarnings() const { return fNumWarnings; }
62
63 /// Returns the current number of errors.
64 long long GetNumErrors() const { return fNumErrors; }
65
66 /// Returns the current number of fatal errors.
67 long long GetNumFatalErrors() const { return fNumFatalErrors; }
68
69 /// Increase warning or error count.
70 void Increment(ELogLevel severity)
71 {
72 switch (severity) {
74 case ELogLevel::kError: ++fNumErrors; break;
75 case ELogLevel::kWarning: ++fNumWarnings; break;
76 default:;
77 }
78 }
79};
80
81/**
82 Abstract RLogHandler base class. ROOT logs everything from info to error
83 to entities of this class.
84 */
86public:
87 virtual ~RLogHandler();
88 /// Emit a log entry.
89 /// \param entry - the RLogEntry to be emitted.
90 /// \returns false if further emission of this Log should be suppressed.
91 ///
92 /// \note This function is called concurrently; log emission must be locked
93 /// if needed. (The default log handler using ROOT's DefaultErrorHandler is locked.)
94 virtual bool Emit(const RLogEntry &entry) = 0;
95};
96
97/**
98 A log configuration for a channel, e.g. "RHist".
99 Each ROOT module has its own log, with potentially distinct verbosity.
100 */
102 /// Name as shown in diagnostics
103 std::string fName;
104
105 /// Verbosity of this channel. By default, use the global verbosity.
107
108public:
109 /// Construct an anonymous channel.
110 RLogChannel() = default;
111
112 /// Construct an anonymous channel with a default vebosity.
113 explicit RLogChannel(ELogLevel verbosity) : fVerbosity(verbosity) {}
114
115 /// Construct a log channel given its name, which is part of the diagnostics.
116 RLogChannel(const std::string &name) : fName(name) {}
117
119 {
120 std::swap(fVerbosity, verbosity);
121 return verbosity;
122 }
125
126 const std::string &GetName() const { return fName; }
127};
128
129/**
130 A RLogHandler that multiplexes diagnostics to different client `RLogHandler`s
131 and keeps track of the sum of `RLogDiagCount`s for all channels.
132
133 `RLogHandler::Get()` returns the process's (static) log manager.
134 */
135
136class RLogManager : public RLogChannel, public RLogHandler {
137 std::mutex fMutex;
138 std::list<std::unique_ptr<RLogHandler>> fHandlers;
139
140public:
141 /// Initialize taking a RLogHandler.
142 RLogManager(std::unique_ptr<RLogHandler> lh) : RLogChannel(ELogLevel::kWarning)
143 {
144 fHandlers.emplace_back(std::move(lh));
145 }
146
147 static RLogManager &Get();
148
149 /// Add a RLogHandler in the front - to be called before all others.
150 void PushFront(std::unique_ptr<RLogHandler> handler) { fHandlers.emplace_front(std::move(handler)); }
151
152 /// Add a RLogHandler in the back - to be called after all others.
153 void PushBack(std::unique_ptr<RLogHandler> handler) { fHandlers.emplace_back(std::move(handler)); }
154
155 /// Remove and return the given log handler. Returns `nullptr` if not found.
156 std::unique_ptr<RLogHandler> Remove(RLogHandler *handler);
157
158 // Emit a `RLogEntry` to the RLogHandlers.
159 // Returns false if further emission of this Log should be suppressed.
160 bool Emit(const RLogEntry &entry) override;
161};
162
163/**
164 A diagnostic location, part of an RLogEntry.
165 */
167 std::string fFile;
168 std::string fFuncName;
169 int fLine; // C++11 forbids "= 0" for braced-init-list initialization.
170};
171
172/**
173 A diagnostic that can be emitted by the RLogManager.
174 One can construct a RLogEntry through RLogBuilder, including streaming into
175 the diagnostic message and automatic emission.
176 */
177
179public:
181 std::string fMessage;
184
185 RLogEntry(ELogLevel level, RLogChannel &channel) : fChannel(&channel), fLevel(level) {}
186 RLogEntry(ELogLevel level, RLogChannel &channel, const RLogLocation &loc)
187 : fLocation(loc), fChannel(&channel), fLevel(level)
188 {
189 }
190
191 bool IsDebug() const { return fLevel >= ELogLevel::kDebug; }
192 bool IsInfo() const { return fLevel == ELogLevel::kInfo; }
193 bool IsWarning() const { return fLevel == ELogLevel::kWarning; }
194 bool IsError() const { return fLevel == ELogLevel::kError; }
195 bool IsFatal() const { return fLevel == ELogLevel::kFatal; }
196};
197
198namespace Detail {
199/**
200 Builds a diagnostic entry, emitted by the static RLogManager upon destruction of this builder,
201 where - by definition - the RLogEntry has been completely built.
202
203 This builder can be used through the utility preprocessor macros R__LOG_ERROR,
204 R__LOG_WARNING etc like this:
205 ```c++
206 R__LOG_INFO(ROOT::Experimental::HistLog()) << "all we know is " << 42;
207 const int decreasedInfoLevel = 5;
208 R__LOG_XDEBUG(ROOT::Experimental::WebGUILog(), decreasedInfoLevel) << "nitty-gritty details";
209 ```
210 This will automatically capture the current class and function name, the file and line number.
211 */
212
213class RLogBuilder : public std::ostringstream {
214 /// The log entry to be built.
215 RLogEntry fEntry;
216
217public:
218 RLogBuilder(ELogLevel level, RLogChannel &channel) : fEntry(level, channel) {}
219 RLogBuilder(ELogLevel level, RLogChannel &channel, const std::string &filename, int line,
220 const std::string &funcname)
221 : fEntry(level, channel, {filename, funcname, line})
222 {
223 }
224
225 /// Emit the log entry through the static log manager.
226 ~RLogBuilder()
227 {
228 fEntry.fMessage = str();
229 RLogManager::Get().Emit(fEntry);
230 }
231};
232} // namespace Detail
233
234/**
235 Change the verbosity level (global or specific to the RLogChannel passed to the
236 constructor) for the lifetime of this object.
237 Example:
238 ```c++
239 RLogScopedVerbosity debugThis(gFooLog, ELogLevel::kDebug);
240 Foo::SomethingToDebug();
241 ```
242 */
243class RLogScopedVerbosity {
244 RLogChannel *fChannel;
245 ELogLevel fPrevLevel;
246
247public:
248 RLogScopedVerbosity(RLogChannel &channel, ELogLevel verbosity)
249 : fChannel(&channel), fPrevLevel(channel.SetVerbosity(verbosity))
250 {
251 }
252 explicit RLogScopedVerbosity(ELogLevel verbosity) : RLogScopedVerbosity(RLogManager::Get(), verbosity) {}
253 ~RLogScopedVerbosity() { fChannel->SetVerbosity(fPrevLevel); }
254};
255
256/**
257 Object to count the number of warnings and errors emitted by a section of code,
258 after construction of this type.
259 */
260class RLogScopedDiagCount {
261 RLogDiagCount *fCounter = nullptr;
262 /// The number of the RLogDiagCount's emitted warnings at construction time of *this.
263 long long fInitialWarnings = 0;
264 /// The number of the RLogDiagCount's emitted errors at construction time.
265 long long fInitialErrors = 0;
266 /// The number of the RLogDiagCount's emitted fatal errors at construction time.
267 long long fInitialFatalErrors = 0;
268
269public:
270 /// Construct the scoped count given a counter (e.g. a channel or RLogManager).
271 /// The counter's lifetime must exceed the lifetime of this object!
272 explicit RLogScopedDiagCount(RLogDiagCount &cnt)
273 : fCounter(&cnt), fInitialWarnings(cnt.GetNumWarnings()), fInitialErrors(cnt.GetNumErrors()),
274 fInitialFatalErrors(cnt.GetNumFatalErrors())
275 {
276 }
277
278 /// Construct the scoped count for any diagnostic, whatever its channel.
279 RLogScopedDiagCount() : RLogScopedDiagCount(RLogManager::Get()) {}
280
281 /// Get the number of warnings that the RLogDiagCount has emitted since construction of *this.
282 long long GetAccumulatedWarnings() const { return fCounter->GetNumWarnings() - fInitialWarnings; }
283
284 /// Get the number of errors that the RLogDiagCount has emitted since construction of *this.
285 long long GetAccumulatedErrors() const { return fCounter->GetNumErrors() - fInitialErrors; }
286
287 /// Get the number of errors that the RLogDiagCount has emitted since construction of *this.
288 long long GetAccumulatedFatalErrors() const { return fCounter->GetNumFatalErrors() - fInitialFatalErrors; }
289
290 /// Whether the RLogDiagCount has emitted a warnings since construction time of *this.
291 bool HasWarningOccurred() const { return GetAccumulatedWarnings(); }
292
293 /// Whether the RLogDiagCount has emitted an error (fatal or not) since construction time of *this.
294 bool HasErrorOccurred() const { return GetAccumulatedErrors() + GetAccumulatedFatalErrors(); }
295
296 /// Whether the RLogDiagCount has emitted an error or a warning since construction time of *this.
297 bool HasErrorOrWarningOccurred() const { return HasWarningOccurred() || HasErrorOccurred(); }
298};
299
300namespace Internal {
301
302inline RLogChannel &GetChannelOrManager()
303{
304 return RLogManager::Get();
305}
306inline RLogChannel &GetChannelOrManager(RLogChannel &channel)
307{
308 return channel;
309}
310
311} // namespace Internal
312
313inline ELogLevel RLogChannel::GetEffectiveVerbosity(const RLogManager &mgr) const
314{
316 return mgr.GetVerbosity();
317 return fVerbosity;
318}
319
320} // namespace Experimental
321} // namespace ROOT
322
323#if defined(_MSC_VER)
324#define R__LOG_PRETTY_FUNCTION __FUNCSIG__
325#else
326#define R__LOG_PRETTY_FUNCTION __PRETTY_FUNCTION__
327#endif
328
329/*
330 Some implementation details:
331
332 - The conditional `RLogBuilder` use prevents stream operators from being called if
333 verbosity is too low, i.e.:
334 ````
335 RLogScopedVerbosity silence(RLogLevel::kFatal);
336 R__LOG_DEBUG(7) << WillNotBeCalled();
337 ```
338 - To update counts of warnings / errors / fatal errors, those RLogEntries must
339 always be created, even if in the end their emission will be silenced. This
340 should be fine, performance-wise, as they should not happen frequently.
341 - Use `(condition) && RLogBuilder(...)` instead of `if (condition) RLogBuilder(...)`
342 to prevent "ambiguous else" in invocations such as `if (something) R__LOG_DEBUG()...`.
343 */
344#define R__LOG_TO_CHANNEL(SEVERITY, CHANNEL) \
345 ((SEVERITY < ROOT::Experimental::ELogLevel::kInfo + 0) || \
346 ROOT::Experimental::Internal::GetChannelOrManager(CHANNEL).GetEffectiveVerbosity( \
347 ROOT::Experimental::RLogManager::Get()) >= SEVERITY) && \
348 ROOT::Experimental::Detail::RLogBuilder(SEVERITY, ROOT::Experimental::Internal::GetChannelOrManager(CHANNEL), \
349 __FILE__, __LINE__, R__LOG_PRETTY_FUNCTION)
350
351/// \name LogMacros
352/// Macros to log diagnostics.
353/// ```c++
354/// R__LOG_INFO(ROOT::Experimental::HistLog()) << "all we know is " << 42;
355///
356/// RLogScopedVerbosity verbose(kDebug + 5);
357/// const int decreasedInfoLevel = 5;
358/// R__LOG_DEBUG(decreasedInfoLevel, ROOT::Experimental::WebGUILog()) << "nitty-gritty details";
359/// ```
360///\{
361#define R__LOG_FATAL(...) R__LOG_TO_CHANNEL(ROOT::Experimental::ELogLevel::kFatal, __VA_ARGS__)
362#define R__LOG_ERROR(...) R__LOG_TO_CHANNEL(ROOT::Experimental::ELogLevel::kError, __VA_ARGS__)
363#define R__LOG_WARNING(...) R__LOG_TO_CHANNEL(ROOT::Experimental::ELogLevel::kWarning, __VA_ARGS__)
364#define R__LOG_INFO(...) R__LOG_TO_CHANNEL(ROOT::Experimental::ELogLevel::kInfo, __VA_ARGS__)
365#define R__LOG_DEBUG(DEBUGLEVEL, ...) R__LOG_TO_CHANNEL(ROOT::Experimental::ELogLevel::kDebug + DEBUGLEVEL, __VA_ARGS__)
366///\}
367
368#endif
char name[80]
Definition TGX11.cxx:110
ELogLevel
Definition TSystem.h:55
A log configuration for a channel, e.g.
Definition RLogger.hxx:101
RLogChannel(const std::string &name)
Construct a log channel given its name, which is part of the diagnostics.
Definition RLogger.hxx:116
ELogLevel fVerbosity
Verbosity of this channel. By default, use the global verbosity.
Definition RLogger.hxx:106
RLogChannel()=default
Construct an anonymous channel.
ELogLevel GetEffectiveVerbosity(const RLogManager &mgr) const
std::string fName
Name as shown in diagnostics.
Definition RLogger.hxx:103
ELogLevel GetVerbosity() const
Definition RLogger.hxx:123
ELogLevel SetVerbosity(ELogLevel verbosity)
Definition RLogger.hxx:118
const std::string & GetName() const
Definition RLogger.hxx:126
RLogChannel(ELogLevel verbosity)
Construct an anonymous channel with a default vebosity.
Definition RLogger.hxx:113
Keep track of emitted errors and warnings.
Definition RLogger.hxx:53
std::atomic< long long > fNumFatalErrors
Number of errors.
Definition RLogger.hxx:57
std::atomic< long long > fNumWarnings
Definition RLogger.hxx:55
void Increment(ELogLevel severity)
Increase warning or error count.
Definition RLogger.hxx:70
long long GetNumWarnings() const
Number of fatal errors.
Definition RLogger.hxx:61
std::atomic< long long > fNumErrors
Number of warnings.
Definition RLogger.hxx:56
long long GetNumFatalErrors() const
Returns the current number of fatal errors.
Definition RLogger.hxx:67
long long GetNumErrors() const
Returns the current number of errors.
Definition RLogger.hxx:64
A diagnostic that can be emitted by the RLogManager.
Definition RLogger.hxx:178
RLogEntry(ELogLevel level, RLogChannel &channel, const RLogLocation &loc)
Definition RLogger.hxx:186
RLogEntry(ELogLevel level, RLogChannel &channel)
Definition RLogger.hxx:185
Abstract RLogHandler base class.
Definition RLogger.hxx:85
virtual bool Emit(const RLogEntry &entry)=0
Emit a log entry.
A RLogHandler that multiplexes diagnostics to different client RLogHandlers and keeps track of the su...
Definition RLogger.hxx:136
std::list< std::unique_ptr< RLogHandler > > fHandlers
Definition RLogger.hxx:138
std::unique_ptr< RLogHandler > Remove(RLogHandler *handler)
Remove and return the given log handler. Returns nullptr if not found.
Definition RLogger.cxx:68
static RLogManager & Get()
Definition RLogger.cxx:62
RLogManager(std::unique_ptr< RLogHandler > lh)
Initialize taking a RLogHandler.
Definition RLogger.hxx:142
bool Emit(const RLogEntry &entry) override
Emit a log entry.
Definition RLogger.cxx:82
void PushFront(std::unique_ptr< RLogHandler > handler)
Add a RLogHandler in the front - to be called before all others.
Definition RLogger.hxx:150
void PushBack(std::unique_ptr< RLogHandler > handler)
Add a RLogHandler in the back - to be called after all others.
Definition RLogger.hxx:153
TLine * line
ELogLevel operator+(ELogLevel severity, int offset)
Definition RLogger.hxx:45
ELogLevel
Kinds of diagnostics.
Definition RLogger.hxx:36
@ kInfo
Informational messages; used for instance for tracing.
@ kDebug
Debug information; only useful for developers; can have added verbosity up to 255-kDebug.
@ kFatal
An error which causes further processing to be unreliable.
@ kWarning
Warnings about likely unexpected behavior.
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
const char * cnt
Definition TXMLSetup.cxx:75
A diagnostic location, part of an RLogEntry.
Definition RLogger.hxx:166