Hammer  1.0.0
Helicity Amplitude Module for Matrix Element Reweighting
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Logging.cc
Go to the documentation of this file.
1 ///
2 /// @file Logging.cc
3 /// @brief Message logging routines
4 /// @brief based on Logging from Rivet v.2.1.1
5 ///
6 
7 //**** This file is a part of the HAMMER library
8 //**** Copyright (C) 2016 - 2020 The HAMMER Collaboration
9 //**** HAMMER is licensed under version 3 of the GPL; see COPYING for details
10 //**** Please note the MCnet academic guidelines; see GUIDELINES for details
11 
12 // -*- C++ -*-
13 #include <ctime>
14 #include <unistd.h>
15 #include "Hammer/Tools/Logging.hh"
16 
17 using namespace std;
18 
19 namespace Hammer {
20 
21 #pragma clang diagnostic push
22 #pragma clang diagnostic ignored "-Wexit-time-destructors"
23 
24  Log::LogMap& Log::existingLogs() {
25  static Log::LogMap x;
26  return x;
27  }
28 
29  Log::LevelMap& Log::defaultLevels() {
30  static Log::LevelMap x;
31  return x;
32  }
33 
34  Log::WarningCountMap& Log::defaultMaxWarnings() {
35  static Log::WarningCountMap x;
36  return x;
37  }
38 
39  Log::ColorCodes& Log::colorCodes() {
40  static Log::ColorCodes x;
41  return x;
42  }
43 
44  string& Log::endColorCode() {
45  static string x;
46  return x;
47  }
48 
49  mutex& Log::lock() {
50  static mutex x;
51  return x;
52  }
53 
54  mutex& Log::displayLock() {
55  static mutex x;
56  return x;
57  }
58 
59 #pragma clang diagnostic pop
60 
61  bool Log::showTimestamp = false;
62  bool Log::showLogLevel = true;
63  bool Log::showLoggerName = true;
64  bool Log::useShellColors = true;
65 
66  void Log::updateLevels() {
67  for (LevelMap::const_iterator lev = defaultLevels().begin(); lev != defaultLevels().end(); ++lev) {
68  for (LogMap::iterator log = existingLogs().begin(); log != existingLogs().end(); ++log) {
69  if (log->first.find(lev->first) == 0) {
70  log->second->setLevel(lev->second);
71  }
72  }
73  }
74  }
75 
76  void Log::updateCounters() {
77  if(defaultMaxWarnings().size() == 0) {
78  defaultMaxWarnings()["Default"] = 10;
79  }
80  for (WarningCountMap::const_iterator lev = defaultMaxWarnings().begin(); lev != defaultMaxWarnings().end(); ++lev) {
81  if (lev->first.find("Default") == 0) {
82  continue;
83  }
84  for (LogMap::iterator log = existingLogs().begin(); log != existingLogs().end(); ++log) {
85  if (log->first.find(lev->first) == 0) {
86  log->second->setWarnCount(lev->second);
87  }
88  else {
89  log->second->setWarnCount(10);
90  }
91  }
92  }
93  }
94 
95  Log::Log(const string& name)
96  : _nostream(new ostream(nullptr)), _level(INFO), _warnCounter(0), _maxWarning(10), _name(name) { }
97 
98 
99  Log::Log(const string& name, int level)
100  : _nostream(new ostream(nullptr)), _level(level), _warnCounter(0), _maxWarning(10), _name(name) { }
101 
102  Log::Log(const string& name, int level, int maxCount)
103  : _nostream(new ostream(nullptr)), _level(level), _warnCounter(0), _maxWarning(maxCount), _name(name) { }
104 
105  void Log::setLevel(const string& name, int level) {
106  {
107  lock_guard<mutex> guard(lock());
108  defaultLevels()[name] = level;
109  }
110  updateLevels();
111  }
112 
113  void Log::setLevels(const LevelMap& logLevels) {
114  {
115  lock_guard<mutex> guard(lock());
116  for (LevelMap::const_iterator lev = logLevels.begin(); lev != logLevels.end(); ++lev) {
117  defaultLevels()[lev->first] = lev->second;
118  }
119  }
120  updateLevels();
121  }
122 
123 
124  void Log::setWarningMaxCount(const std::string& name, int maxCount) {
125  {
126  lock_guard<mutex> guard(lock());
127  defaultMaxWarnings()[name] = maxCount;
128  }
129  updateCounters();
130  }
131 
133  lock_guard<mutex> guard(lock());
134  for (Log::LogMap::iterator log = existingLogs().begin(); log != existingLogs().end(); ++log) {
135  log->second->_warnCounter = 0;
136  }
137  }
138 
139  Log& Log::getLog(const string& name) {
140  if (existingLogs().find(name) == existingLogs().end()) {
141  int level = INFO;
142  // Try running through all parent classes to find an existing level
143  string tmpname = name;
144  bool triedAllParents = false;
145 
146  while (! triedAllParents) {
147  // Is there a default level?
148  if (defaultLevels().find(tmpname) != defaultLevels().end()) {
149  level = defaultLevels().find(tmpname)->second;
150  break;
151  }
152 
153  // Is there already such a logger? (NB. tmpname != name)
154  if (existingLogs().find(tmpname) != existingLogs().end()) {
155  level = existingLogs().find(tmpname)->second->getLevel();
156  break;
157  }
158 
159  // Crop the string back to the next parent level
160  size_t lastDot = tmpname.find_last_of(".");
161 
162  if (lastDot != string::npos) {
163  tmpname = tmpname.substr(0, lastDot);
164  }
165  else {
166  triedAllParents = true;
167  }
168  }
169  int maxCount = 10;
170  // now update data
171  lock_guard<mutex> guard(lock());
172  if (defaultMaxWarnings().find(tmpname) == defaultMaxWarnings().end()) {
173  defaultMaxWarnings()[tmpname] = maxCount;
174  }
175  else {
176  maxCount = defaultMaxWarnings()[tmpname];
177  }
178 
179  // for (LevelMap::const_iterator l = defaultLevels().begin(); l != defaultLevels().end(); ++l) {
180  //
181  // }
182  existingLogs().insert(make_pair(name, unique_ptr<Log>(new Log(name, level, maxCount))));
183 
184  }
185 
186  return *existingLogs()[name];
187  }
188 
189 
190  string Log::getLevelName(int level) {
191  /// @todo Do the map::upper_limit thing to find nearest level...
192  switch(level) {
193  case TRACE:
194  return "TRACE";
195 
196  case DEBUG:
197  return "DEBUG";
198 
199  case INFO:
200  return "INFO";
201 
202  case WARN:
203  return "WARN";
204 
205  case ERROR:
206  return "ERROR";
207 
208  default:
209  return "";
210  }
211 
212  //throw Error("Enum value was not a valid log level. How did that happen?");
213  }
214 
215 
216  string Log::getColorCode(int level) {
217  if (!useShellColors) {
218  return "";
219  }
220 
221  // If the codes haven't been initialized, do so now.
222  if (colorCodes().empty()) {
223  lock_guard<mutex> guard(lock());
224  // If stdout is a valid tty, try to use the appropriate codes.
225  if (isatty(1)) {
226  /// @todo Test for VT100 compliance?
227  colorCodes()[TRACE] = "\033[0;36m";
228  colorCodes()[DEBUG] = "\033[0;34m";
229  colorCodes()[INFO] = "\033[0;32m";
230  colorCodes()[WARN] = "\033[0;33m";
231  colorCodes()[ERROR] = "\033[0;31m";
232  endColorCode() = "\033[0m";
233  }
234  else {
235  colorCodes()[TRACE] = "";
236  colorCodes()[DEBUG] = "";
237  colorCodes()[INFO] = "";
238  colorCodes()[WARN] = "";
239  colorCodes()[ERROR] = "";
240  }
241  }
242 
243  // Return the appropriate code from the colour map.
244  /// @todo Do the map::upper_limit thing to find nearest level...
245  return colorCodes()[level];
246  }
247 
248 
249  Log::Level Log::getLevelFromName(const string& level) {
250  if (level == "TRACE") {
251  return TRACE;
252  }
253 
254  if (level == "DEBUG") {
255  return DEBUG;
256  }
257 
258  if (level == "INFO") {
259  return INFO;
260  }
261 
262  if (level == "WARN") {
263  return WARN;
264  }
265 
266  if (level == "ERROR") {
267  return ERROR;
268  }
269 
270  throw Error("Couldn't create a log level from string '" + level + "'");
271  }
272 
273 
274  string Log::formatMessage(int level, const string& message) {
275  string out;
276 
277  if (useShellColors) {
278  out += getColorCode(level);
279  }
280 
281  if (showLoggerName) {
282  out += getName();
283  out += ": ";
284  }
285 
286  if (showLogLevel) {
287  out += getLevelName(level);
288  out += " ";
289  }
290 
291  if (showTimestamp) {
292  time_t rawtime;
293  time(&rawtime);
294  char* timestr = ctime(&rawtime);
295  timestr[24] = ' ';
296  out += timestr;
297  out += " ";
298  }
299 
300  if (useShellColors) {
301  out += endColorCode();
302  }
303 
304  out += " ";
305  out += message;
306  return out;
307  }
308 
309 
310  void Log::log(int level, const string& message) {
311  if (isActive(level)) {
312  int max_warning = getMaxWarning();
313  if(level == WARN) {
314  if(_warnCounter <= max_warning + 2) {
315  lock_guard<mutex> guard(lock());
316  ++_warnCounter;
317  }
318  if(_warnCounter > max_warning) {
319  return;
320  }
321  }
322  std::string tmp = formatMessage(level, message);
323  {
324  lock_guard<mutex> guard(displayLock());
325  cout << tmp << endl;
326  if(level == WARN && _warnCounter == max_warning) {
327  cout << formatMessage(level, "Maximum number of warnings reached. Further warning output will be suppressed for this class.") << endl;
328  }
329  }
330  }
331  }
332 
333 
334  ostream& operator<<(Log& log, int level) {
335  if (log.isActive(level)) {
336  int max_warning = log.getMaxWarning();
337  if(level == Log::WARN) {
338  if(log._warnCounter <= max_warning + 2) {
339  lock_guard<mutex> guard(log.lock());
340  ++log._warnCounter;
341  }
342  if(log._warnCounter > max_warning) {
343  if(log._warnCounter == max_warning + 1) {
344  lock_guard<mutex> guard(log.displayLock());
345  cout << log.formatMessage(level, "Maximum number of warnings reached. Further warning output will be suppressed for this class.") << endl;
346  }
347  return *(log._nostream);
348  }
349  }
350  {
351  lock_guard<mutex> guard(log.displayLock());
352  cout << log.formatMessage(level, "");
353  }
354  return cout;
355  }
356  else {
357  return *(log._nostream);
358  }
359  }
360 
361 }
static std::string & endColorCode()
Shell color code for the end of the log levels.
Definition: Logging.cc:44
static WarningCountMap & defaultMaxWarnings()
A static map for counting how many warnings have been issued for each logger.
Definition: Logging.cc:34
std::map< std::string, std::unique_ptr< Log >> LogMap
Typedef for a collection of named logs.
Definition: Logging.hh:50
std::unique_ptr< std::ostream > const _nostream
A null output stream, used for piping discarded output to nowhere.
Definition: Logging.hh:321
YAML::Emitter & operator<<(YAML::Emitter &out, const ProcessDefinitions &s)
static bool showTimestamp
Show timestamp?
Definition: Logging.hh:89
static void updateLevels()
updates the verbosity levels of all the loggers
Definition: Logging.cc:66
static void resetWarningCounters()
reset the warning counters for all loggers
Definition: Logging.cc:132
Message logging routines.
std::string getColorCode(int level)
provide the escape string for the color associated to a give log level
Definition: Logging.cc:216
static LevelMap & defaultLevels()
A static map of default log levels.
Definition: Logging.cc:29
static Level getLevelFromName(const std::string &level)
Get a log level enum from a string.
Definition: Logging.cc:249
std::string getName() const
Get the name of this logger.
Definition: Logging.hh:244
bool isActive(int level) const
Will this log level produce output on this logger at the moment?
Definition: Logging.hh:276
static Log & getLog(const std::string &name)
Get a logger with the given name.
Definition: Logging.cc:139
auto begin(reversion_wrapper< T > w)
Definition: Tools/Utils.hh:79
int getMaxWarning() const
Get the maximum number of warnings for this logger.
Definition: Logging.hh:210
static bool showLogLevel
Show log level?
Definition: Logging.hh:92
int _warnCounter
number of warnings issued by this logger.
Definition: Logging.hh:332
std::map< std::string, int > LevelMap
Typedef for a collection of named log levels.
Definition: Logging.hh:53
Logging class.
Definition: Logging.hh:33
std::string formatMessage(int level, const std::string &message)
Turn a message string into the current log format.
Definition: Logging.cc:274
static void updateCounters()
updates the max warning numbers of all the loggers
Definition: Logging.cc:76
Generic error class.
Definition: Exceptions.hh:23
void log(int level, const std::string &message)
Write a message at a particular level.
Definition: Logging.cc:310
static std::mutex & lock()
Mutex to modify global elements (protected because external streaming operator uses it) ...
Definition: Logging.cc:49
std::map< int, std::string > ColorCodes
Typedef for a collection of shell color codes, accessed by log level.
Definition: Logging.hh:59
static void setLevels(const LevelMap &logLevels)
Set the log levels all at once.
Definition: Logging.cc:113
static std::string getLevelName(int level)
Get the std::string representation of a log level.
Definition: Logging.cc:190
std::map< std::string, int > WarningCountMap
Typedef for a counting the number of warnings in order to turn off warnings above a certain threshold...
Definition: Logging.hh:56
Level
Log priority levels.
Definition: Logging.hh:45
static void setWarningMaxCount(const std::string &name, int maxCount)
set the maximum number of warnings for a given logger
Definition: Logging.cc:124
static bool useShellColors
Use shell colour escape codes?
Definition: Logging.hh:98
static ColorCodes & colorCodes()
A static map of shell color codes for the log levels.
Definition: Logging.cc:39
static LogMap & existingLogs()
A static map of existing logs: we don&#39;t make more loggers than necessary.
Definition: Logging.cc:24
auto end(reversion_wrapper< T > w)
Definition: Tools/Utils.hh:84
static bool showLoggerName
Show logger name?
Definition: Logging.hh:95
static std::mutex & displayLock()
Mutex to access screen (protected because external streaming operator uses it)
Definition: Logging.cc:54
static void setLevel(const std::string &name, int level)
Set the log levels.
Definition: Logging.cc:105
Log(const std::string &name)
Constructor by name.
Definition: Logging.cc:95