The Battle for Wesnoth  1.15.6+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 #include "global.hpp"
48 
49 #ifndef __func__
50  #ifdef __FUNCTION__
51  #define __func__ __FUNCTION__
52  #endif
53 #endif
54 
55 #include <iostream> // needed else all files including log.hpp need to do it.
56 #include <sstream> // as above. iostream (actually, iosfwd) declares stringstream as an incomplete type, but does not define it
57 #include <string>
58 #include <utility>
59 #include <ctime>
60 
61 #include "formatter.hpp"
62 
63 namespace lg {
64 
65 /**
66  * Helper class to redirect the output of the logger in a certain scope.
67  *
68  * The main usage of the redirection is for the unit tests to validate the
69  * output on the logger with the expected output.
70  */
72 {
73 public:
74 
75  /**
76  * Constructor.
77  *
78  * @param stream The stream to direct the output to.
79  */
80  explicit redirect_output_setter(std::ostream& stream);
81 
83 
84 private:
85 
86  /**
87  * The previously set redirection.
88  *
89  * This value is stored here to be restored in this destructor.
90  */
91  std::ostream* old_stream_;
92 };
93 
94 class logger;
95 
96 typedef std::pair<const std::string, int> logd;
97 
98 class log_domain {
99  logd *domain_;
100 public:
101  log_domain(char const *name, int severity = 1);
102  friend class logger;
103 };
104 
105 bool set_log_domain_severity(const std::string& name, int severity);
106 bool set_log_domain_severity(const std::string& name, const logger &lg);
107 bool get_log_domain_severity(const std::string& name, int &severity);
109 
110 void set_strict_severity(int severity);
111 void set_strict_severity(const logger &lg);
112 bool broke_strict();
113 
114 // A little "magic" to surround the logging operation in a mutex.
115 // This works by capturing the output first to a stringstream formatter, then
116 // locking a mutex and dumping it to the stream all in one go.
117 // By doing this we can avoid rare deadlocks if a function whose output is streamed
118 // calls logging of its own.
119 // We overload operator| only because it has lower precedence than operator<<
120 // Any other lower-precedence operator would have worked just as well.
122  std::ostream& stream_;
123  int indent_ = 0;
124  bool timestamp_ = false;
126 public:
127  log_in_progress(std::ostream& stream);
128  void operator|(formatter&& message);
129  void set_indent(int level);
130  void enable_timestamp();
131  void set_prefix(const std::string& prefix);
132 };
133 
134 class logger {
135  char const *name_;
137 public:
138  logger(char const *name, int severity): name_(name), severity_(severity) {}
139  log_in_progress operator()(const log_domain& domain,
140  bool show_names = true, bool do_indent = false) const;
141 
142  bool dont_log(const log_domain& domain) const
143  {
144  return severity_ > domain.domain_->second;
145  }
146 
147  int get_severity() const
148  {
149  return severity_;
150  }
151 
153  {
154  return name_;
155  }
156 };
157 
158 void timestamps(bool);
159 void precise_timestamps(bool);
160 std::string get_timestamp(const std::time_t& t, const std::string& format="%Y%m%d %H:%M:%S ");
161 std::string get_timespan(const std::time_t& t);
162 
163 logger &err(), &warn(), &info(), &debug();
165 
167 {
168  int64_t ticks_;
171 public:
172  scope_logger(const log_domain& domain, const char* str) :
173  domain_(domain)
174  {
175  if (!debug().dont_log(domain)) do_log_entry(str);
176  }
177  scope_logger(const log_domain& domain, const std::string& str) :
178  domain_(domain)
179  {
180  if (!debug().dont_log(domain)) do_log_entry(str);
181  }
183  {
184  if (!str_.empty()) do_log_exit();
185  }
186 private:
187  void do_log_entry(const std::string& str) noexcept;
188  void do_log_exit() noexcept;
189 };
190 
191 /**
192  * Use this logger to send errors due to deprecated WML.
193  * The preferred format is:
194  * xxx is deprecated; support will be removed in version X. or
195  * xxx is deprecated; support has been removed in version X.
196  *
197  * After every wml-event the errors are shown to the user,
198  * so they can inform the campaign maintainer.
199  */
200 std::stringstream& wml_error();
201 
202 } // namespace lg
203 
204 #define log_scope(description) lg::scope_logger scope_logging_object__(lg::general(), description);
205 #define log_scope2(domain,description) lg::scope_logger scope_logging_object__(domain, description);
206 
207 #define LOG_STREAM(level, domain) if (lg::level().dont_log(domain)) ; else lg::level()(domain) | formatter()
208 
209 // Don't prefix the logdomain to messages on this stream
210 #define LOG_STREAM_NAMELESS(level, domain) if (lg::level().dont_log(domain)) ; else lg::level()(domain, false) | formatter()
211 
212 // When using log_scope/log_scope2 it is nice to have all output indented.
213 #define LOG_STREAM_INDENT(level,domain) if (lg::level().dont_log(domain)) ; else lg::level()(domain, true, true) | formatter()
214 
215 // If you have an explicit logger object and want to ignore the logging level, use this.
216 // Meant for cases where you explicitly call dont_log to avoid an expensive operation if the logging is disabled.
217 #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:176
char const * name_
Definition: log.hpp:135
int64_t ticks_
Definition: log.hpp:168
std::string get_timespan(const std::time_t &t)
Definition: log.cpp:183
logger(char const *name, int severity)
Definition: log.hpp:138
logger & info()
Definition: log.cpp:91
void timestamps(bool t)
Definition: log.cpp:76
std::string str_
Definition: log.hpp:170
redirect_output_setter(std::ostream &stream)
Constructor.
Definition: log.cpp:62
std::string str
Definition: statement.cpp:110
Helper class to redirect the output of the logger in a certain scope.
Definition: log.hpp:71
std::pair< const std::string, int > logd
Definition: log.hpp:94
bool broke_strict()
Definition: log.cpp:172
scope_logger(const log_domain &domain, const char *str)
Definition: log.hpp:172
bool get_log_domain_severity(const std::string &name, int &severity)
Definition: log.cpp:143
std::ostringstream wrapper.
Definition: formatter.hpp:38
int severity_
Definition: log.hpp:136
logger & debug()
Definition: log.cpp:97
bool dont_log(const log_domain &domain) const
Definition: log.hpp:142
log_domain & general()
Definition: log.cpp:105
Definition: pump.hpp:39
const log_domain & domain_
Definition: log.hpp:169
std::ostream * old_stream_
The previously set redirection.
Definition: log.hpp:91
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:291
logger & err()
Definition: log.cpp:79
void set_strict_severity(int severity)
Definition: log.cpp:162
terrain_code operator|(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:73
std::string get_name() const
Definition: log.hpp:152
std::string name
Definition: sdl_ttf.cpp:70
bool set_log_domain_severity(const std::string &name, int severity)
Definition: log.cpp:119
logger & warn()
Definition: log.cpp:85
double t
Definition: astarsearch.cpp:64
std::string list_logdomains(const std::string &filter)
Definition: log.cpp:152
std::string prefix_
Definition: log.hpp:125
int get_severity() const
Definition: log.hpp:147
std::ostream & stream_
Definition: log.hpp:122
scope_logger(const log_domain &domain, const std::string &str)
Definition: log.hpp:177
void precise_timestamps(bool pt)
Definition: log.cpp:77
logd * domain_
Definition: log.hpp:99