Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RLogger.hxx
Go to the documentation of this file.
1 /// \file ROOT/TLogger.h
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-2015, 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 <array>
20 #include <memory>
21 #include <sstream>
22 #include <vector>
23 
24 #include "ROOT/RStringView.hxx"
25 
26 namespace ROOT {
27 namespace Experimental {
28 
29 /**
30  Kinds of diagnostics.
31  */
32 enum class ELogLevel {
33  kDebug, ///< Debug information; only useful for developers
34  kInfo, ///< Informational messages; used for instance for tracing
35  kWarning, ///< Warnings about likely unexpected behavior
36  kError,
37  kFatal
38 };
39 
40 class RLogEntry;
41 
42 /**
43  Abstract RLogHandler base class. ROOT logs everything from info to error
44  to entities of this class.
45  */
46 class RLogHandler {
47 public:
48  virtual ~RLogHandler();
49  /// Emit a log entry.
50  /// \param entry - the RLogEntry to be emitted.
51  /// \returns false if further emission of this Log should be suppressed.
52  ///
53  /// \note This function is called concurrently; log emission must be locked
54  /// if needed. (The default log handler using ROOT's DefaultErrorHandler is locked.)
55  virtual bool Emit(const RLogEntry &entry) = 0;
56 };
57 
58 
59 /**
60  A RLogHandler that multiplexes diagnostics to different client `RLogHandler`s.
61  `RLogHandler::Get()` returns the process's (static) log manager.
62  */
63 
64 class RLogManager: public RLogHandler {
65 private:
66  std::vector<std::unique_ptr<RLogHandler>> fHandlers;
67 
68  long long fNumWarnings{0};
69  long long fNumErrors{0};
70 
71  /// Initialize taking a RLogHandlerDefault.
72  RLogManager(std::unique_ptr<RLogHandler> &&lh) { fHandlers.emplace_back(std::move(lh)); }
73 
74 public:
75  static RLogManager &Get();
76 
77  /// Add a RLogHandler in the front - to be called before all others.
78  void PushFront(std::unique_ptr<RLogHandler> handler) { fHandlers.insert(fHandlers.begin(), std::move(handler)); }
79 
80  /// Add a RLogHandler in the back - to be called after all others.
81  void PushBack(std::unique_ptr<RLogHandler> handler) { fHandlers.emplace_back(std::move(handler)); }
82 
83  // Emit a `RLogEntry` to the RLogHandlers.
84  // Returns false if further emission of this Log should be suppressed.
85  bool Emit(const RLogEntry &entry) override
86  {
87  for (auto &&handler: fHandlers)
88  if (!handler->Emit(entry))
89  return false;
90  return true;
91  }
92 
93  /// Returns the current number of warnings seen by this log manager.
94  long long GetNumWarnings() const { return fNumWarnings; }
95 
96  /// Returns the current number of errors seen by this log manager.
97  long long GetNumErrors() const { return fNumErrors; }
98 };
99 
100 /**
101  Object to count the number of warnings and errors emitted by a section of code,
102  after construction of this type.
103  */
104 class RLogDiagCounter {
105 private:
106  /// The number of the RLogManager's emitted warnings at construction time of *this.
107  long long fInitialWarnings{RLogManager::Get().GetNumWarnings()};
108  /// The number of the RLogManager's emitted errors at construction time.
109  long long fInitialErrors{RLogManager::Get().GetNumErrors()};
110 
111 public:
112  /// Get the number of warnings that the RLogManager has emitted since construction of *this.
113  long long GetAccumulatedWarnings() const { return RLogManager::Get().GetNumWarnings() - fInitialWarnings; }
114 
115  /// Get the number of errors that the RLogManager has emitted since construction of *this.
116  long long GetAccumulatedErrors() const { return RLogManager::Get().GetNumErrors() - fInitialErrors; }
117 
118  /// Whether the RLogManager has emitted a warnings since construction time of *this.
119  bool HasWarningOccurred() const { return GetAccumulatedWarnings(); }
120 
121  /// Whether the RLogManager has emitted an error since construction time of *this.
122  bool HasErrorOccurred() const { return GetAccumulatedErrors(); }
123 
124  /// Whether the RLogManager has emitted an error or a warning since construction time of *this.
125  bool HasErrorOrWarningOccurred() const { return HasWarningOccurred() || HasErrorOccurred(); }
126 };
127 
128 /**
129  A diagnostic, emitted by the RLogManager upon destruction of the RLogEntry.
130  One can construct a RLogEntry through the utility preprocessor macros R__ERROR_HERE, R__WARNING_HERE etc
131  like this:
132  R__INFO_HERE("CodeGroupForInstanceLibrary") << "All we know is " << 42;
133  This will automatically capture the current class and function name, the file and line number.
134  */
135 
136 class RLogEntry: public std::ostringstream {
137 public:
138  std::string fGroup;
139  std::string fFile;
140  std::string fFuncName;
141  int fLine = 0;
142  ELogLevel fLevel;
143 
144 public:
145  RLogEntry() = default;
146  RLogEntry(ELogLevel level, std::string_view group): fGroup(group), fLevel(level) {}
147  RLogEntry(ELogLevel level, std::string_view group, std::string_view filename, int line, std::string_view funcname)
148  : fGroup(group), fFile(filename), fFuncName(funcname), fLine(line), fLevel(level)
149  {}
150 
151  RLogEntry &SetFile(const std::string &file)
152  {
153  fFile = file;
154  return *this;
155  }
156  RLogEntry &SetFunction(const std::string &func)
157  {
158  fFuncName = func;
159  return *this;
160  }
161  RLogEntry &SetLine(int line)
162  {
163  fLine = line;
164  return *this;
165  }
166 
167  ~RLogEntry() { RLogManager::Get().Emit(*this); }
168 };
169 
170 } // namespace Experimental
171 } // namespace ROOT
172 
173 #if defined(_MSC_VER)
174 #define R__LOG_PRETTY_FUNCTION __FUNCSIG__
175 #else
176 #define R__LOG_PRETTY_FUNCTION __PRETTY_FUNCTION__
177 #endif
178 
179 #define R__LOG_HERE(LEVEL, GROUP) \
180  ROOT::Experimental::RLogEntry(LEVEL, GROUP).SetFile(__FILE__).SetLine(__LINE__).SetFunction(R__LOG_PRETTY_FUNCTION)
181 
182 #define R__FATAL_HERE(GROUP) R__LOG_HERE(ROOT::Experimental::ELogLevel::kFatal, GROUP)
183 #define R__ERROR_HERE(GROUP) R__LOG_HERE(ROOT::Experimental::ELogLevel::kError, GROUP)
184 #define R__WARNING_HERE(GROUP) R__LOG_HERE(ROOT::Experimental::ELogLevel::kWarning, GROUP)
185 #define R__INFO_HERE(GROUP) R__LOG_HERE(ROOT::Experimental::ELogLevel::kInfo, GROUP)
186 #define R__DEBUG_HERE(GROUP) R__LOG_HERE(ROOT::Experimental::ELogLevel::kDebug, GROUP)
187 
188 #endif