The Battle for Wesnoth  1.15.10+dev
log.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 by David White <dave@whitevine.net>
3  2004 - 2015 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Standard logging facilities (interface).
19  *
20  * To use one of the standard log channels, put something like the following at the start
21  * of your .cpp file:
22  *
23  * static lg::log_domain log_display("display");
24  * \#define ERR_DP LOG_STREAM(err, log_display)
25  * \#define LOG_DP LOG_STREAM(info, log_display)
26  *
27  * Then stream logging info to ERR_DP, or LOG_DP, as if it were an ostream like std::cerr.
28  * (In general it will actually be std::cerr at runtime when logging is enabled.)
29  *
30  * LOG_DP << "Found a window resize event: ...\n";
31  *
32  * Please do not use iomanip features like std::hex directly on the logger. Because of the
33  * design of the logger, this will result in all of the loggers (in fact std::cerr) being
34  * imbued with std::hex. Please use a formatter instead.
35  *
36  * \#include "formatter.hpp"
37  *
38  * LOG_DP << (formatter() << "The random seed is: '" << std::hex << seed << "'\n").str();
39  *
40  * It might be nice if somehow the logger class / macros could support using iomanip
41  * things directly, but right now it doesn't, and it seems that it would complicate the
42  * design greatly enough that it doesn't seem worth it.
43  */
44 
45 #pragma once
46 
47 #ifndef __func__
48  #ifdef __FUNCTION__
49  #define __func__ __FUNCTION__
50  #endif
51 #endif
52 
53 #include <iostream> // needed else all files including log.hpp need to do it.
54 #include <sstream> // as above. iostream (actually, iosfwd) declares stringstream as an incomplete type, but does not define it
55 #include <string>
56 #include <utility>
57 #include <ctime>
58 
59 #include "formatter.hpp"
60 
61 namespace lg {
62 
63 /**
64  * Helper class to redirect the output of the logger in a certain scope.
65  *
66  * The main usage of the redirection is for the unit tests to validate the
67  * output on the logger with the expected output.
68  */
70 {
71 public:
72 
73  /**
74  * Constructor.
75  *
76  * @param stream The stream to direct the output to.
77  */
78  explicit redirect_output_setter(std::ostream& stream);
79 
81 
82 private:
83 
84  /**
85  * The previously set redirection.
86  *
87  * This value is stored here to be restored in this destructor.
88  */
89  std::ostream* old_stream_;
90 };
91 
92 class logger;
93 
94 typedef std::pair<const std::string, int> logd;
95 
96 class log_domain {
97  logd *domain_;
98 public:
99  log_domain(char const *name, int severity = 1);
100  friend class logger;
101 };
102 
103 bool set_log_domain_severity(const std::string& name, int severity);
104 bool set_log_domain_severity(const std::string& name, const logger &lg);
105 bool get_log_domain_severity(const std::string& name, int &severity);
106 std::string list_logdomains(const std::string& filter);
107 
108 void set_strict_severity(int severity);
109 void set_strict_severity(const logger &lg);
110 bool broke_strict();
111 
112 // A little "magic" to surround the logging operation in a mutex.
113 // This works by capturing the output first to a stringstream formatter, then
114 // locking a mutex and dumping it to the stream all in one go.
115 // By doing this we can avoid rare deadlocks if a function whose output is streamed
116 // calls logging of its own.
117 // We overload operator| only because it has lower precedence than operator<<
118 // Any other lower-precedence operator would have worked just as well.
120  std::ostream& stream_;
121  int indent_ = 0;
122  bool timestamp_ = false;
123  std::string prefix_;
124 public:
125  log_in_progress(std::ostream& stream);
126  void operator|(formatter&& message);
127  void set_indent(int level);
128  void enable_timestamp();
129  void set_prefix(const std::string& prefix);
130 };
131 
132 class logger {
133  char const *name_;
135 public:
136  logger(char const *name, int severity): name_(name), severity_(severity) {}
137  log_in_progress operator()(const log_domain& domain,
138  bool show_names = true, bool do_indent = false) const;
139 
140  bool dont_log(const log_domain& domain) const
141  {
142  return severity_ > domain.domain_->second;
143  }
144 
145  int get_severity() const
146  {
147  return severity_;
148  }
149 
150  std::string get_name() const
151  {
152  return name_;
153  }
154 };
155 
156 void timestamps(bool);
157 void precise_timestamps(bool);
158 std::string get_timestamp(const std::time_t& t, const std::string& format="%Y%m%d %H:%M:%S ");
159 std::string get_timespan(const std::time_t& t);
160 
161 logger &err(), &warn(), &info(), &debug();
163 
165 {
166  int64_t ticks_;
168  std::string str_;
169 public:
170  scope_logger(const log_domain& domain, const char* str)
171  : ticks_(0)
172  , domain_(domain)
173  , str_()
174  {
175  if (!debug().dont_log(domain)) do_log_entry(str);
176  }
177  scope_logger(const log_domain& domain, const std::string& str)
178  : ticks_(0)
179  , domain_(domain)
180  , str_()
181  {
182  if (!debug().dont_log(domain)) do_log_entry(str);
183  }
185  {
186  if (!str_.empty()) do_log_exit();
187  }
188 private:
189  void do_log_entry(const std::string& str) noexcept;
190  void do_log_exit() noexcept;
191 };
192 
193 /**
194  * Use this logger to send errors due to deprecated WML.
195  * The preferred format is:
196  * xxx is deprecated; support will be removed in version X. or
197  * xxx is deprecated; support has been removed in version X.
198  *
199  * After every wml-event the errors are shown to the user,
200  * so they can inform the campaign maintainer.
201  */
202 std::stringstream& wml_error();
203 
204 } // namespace lg
205 
206 #define log_scope(description) lg::scope_logger scope_logging_object__(lg::general(), description);
207 #define log_scope2(domain,description) lg::scope_logger scope_logging_object__(domain, description);
208 
209 #define LOG_STREAM(level, domain) if (lg::level().dont_log(domain)) ; else lg::level()(domain) | formatter()
210 
211 // Don't prefix the logdomain to messages on this stream
212 #define LOG_STREAM_NAMELESS(level, domain) if (lg::level().dont_log(domain)) ; else lg::level()(domain, false) | formatter()
213 
214 // When using log_scope/log_scope2 it is nice to have all output indented.
215 #define LOG_STREAM_INDENT(level,domain) if (lg::level().dont_log(domain)) ; else lg::level()(domain, true, true) | formatter()
216 
217 // If you have an explicit logger object and want to ignore the logging level, use this.
218 // Meant for cases where you explicitly call dont_log to avoid an expensive operation if the logging is disabled.
219 #define FORCE_LOG_TO(logger, domain) logger(domain) | formatter()
std::string get_timestamp(const std::time_t &t, const std::string &format)
Definition: log.cpp:173
char const * name_
Definition: log.hpp:133
int64_t ticks_
Definition: log.hpp:166
std::string get_timespan(const std::time_t &t)
Definition: log.cpp:180
logger(char const *name, int severity)
Definition: log.hpp:136
logger & info()
Definition: log.cpp:88
void timestamps(bool t)
Definition: log.cpp:73
std::string str_
Definition: log.hpp:168
redirect_output_setter(std::ostream &stream)
Constructor.
Definition: log.cpp:59
Helper class to redirect the output of the logger in a certain scope.
Definition: log.hpp:69
std::pair< const std::string, int > logd
Definition: log.hpp:92
bool broke_strict()
Definition: log.cpp:169
scope_logger(const log_domain &domain, const char *str)
Definition: log.hpp:170
bool get_log_domain_severity(const std::string &name, int &severity)
Definition: log.cpp:140
std::ostringstream wrapper.
Definition: formatter.hpp:38
int severity_
Definition: log.hpp:134
logger & debug()
Definition: log.cpp:94
bool dont_log(const log_domain &domain) const
Definition: log.hpp:140
log_domain & general()
Definition: log.cpp:102
Definition: pump.hpp:39
const log_domain & domain_
Definition: log.hpp:167
std::ostream * old_stream_
The previously set redirection.
Definition: log.hpp:89
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:288
logger & err()
Definition: log.cpp:76
void set_strict_severity(int severity)
Definition: log.cpp:159
terrain_code operator|(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:72
std::string get_name() const
Definition: log.hpp:150
std::string name
Definition: sdl_ttf.cpp:70
bool set_log_domain_severity(const std::string &name, int severity)
Definition: log.cpp:116
logger & warn()
Definition: log.cpp:82
double t
Definition: astarsearch.cpp:64
std::string list_logdomains(const std::string &filter)
Definition: log.cpp:149
std::string prefix_
Definition: log.hpp:123
int get_severity() const
Definition: log.hpp:145
std::ostream & stream_
Definition: log.hpp:120
scope_logger(const log_domain &domain, const std::string &str)
Definition: log.hpp:177
void precise_timestamps(bool pt)
Definition: log.cpp:74
logd * domain_
Definition: log.hpp:97