The Battle for Wesnoth  1.15.1+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 
60 #include <boost/date_time/posix_time/posix_time_types.hpp>
61 
62 using boost::posix_time::ptime;
63 
64 namespace lg {
65 
66 /**
67  * Helper class to redirect the output of the logger in a certain scope.
68  *
69  * The main usage of the redirection is for the unit tests to validate the
70  * output on the logger with the expected output.
71  */
73 {
74 public:
75 
76  /**
77  * Constructor.
78  *
79  * @param stream The stream to direct the output to.
80  */
81  explicit redirect_output_setter(std::ostream& stream);
82 
84 
85 private:
86 
87  /**
88  * The previously set redirection.
89  *
90  * This value is stored here to be restored in this destructor.
91  */
92  std::ostream* old_stream_;
93 };
94 
95 class logger;
96 
97 typedef std::pair<const std::string, int> logd;
98 
99 class log_domain {
100  logd *domain_;
101 public:
102  log_domain(char const *name, int severity = 1);
103  friend class logger;
104 };
105 
106 bool set_log_domain_severity(const std::string& name, int severity);
107 bool set_log_domain_severity(const std::string& name, const logger &lg);
108 bool get_log_domain_severity(const std::string& name, int &severity);
109 std::string list_logdomains(const std::string& filter);
110 
111 void set_strict_severity(int severity);
112 void set_strict_severity(const logger &lg);
113 bool broke_strict();
114 
115 class logger {
116  char const *name_;
118 public:
119  logger(char const *name, int severity): name_(name), severity_(severity) {}
120  std::ostream &operator()(const log_domain& domain,
121  bool show_names = true, bool do_indent = false) const;
122 
123  bool dont_log(const log_domain& domain) const
124  {
125  return severity_ > domain.domain_->second;
126  }
127 
128  int get_severity() const
129  {
130  return severity_;
131  }
132 
133  std::string get_name() const
134  {
135  return name_;
136  }
137 };
138 
139 void timestamps(bool);
140 void precise_timestamps(bool);
141 std::string get_timestamp(const std::time_t& t, const std::string& format="%Y%m%d %H:%M:%S ");
142 std::string get_timespan(const std::time_t& t);
143 
144 logger &err(), &warn(), &info(), &debug();
146 
148 {
149  ptime ticks_;
150  std::ostream *output_;
151  std::string str_;
152 public:
153  scope_logger(const log_domain& domain, const char* str) :
154  output_(nullptr)
155  {
156  if (!debug().dont_log(domain)) do_log_entry(domain, str);
157  }
158  scope_logger(const log_domain& domain, const std::string& str) :
159  output_(nullptr)
160  {
161  if (!debug().dont_log(domain)) do_log_entry(domain, str);
162  }
164  {
165  if (output_) do_log_exit();
166  }
167  void do_indent() const;
168 private:
169  void do_log_entry(const log_domain& domain, const std::string& str) noexcept;
170  void do_log_exit() noexcept;
171 };
172 
173 /**
174  * Use this logger to send errors due to deprecated WML.
175  * The preferred format is:
176  * xxx is deprecated; support will be removed in version X. or
177  * xxx is deprecated; support has been removed in version X.
178  *
179  * After every wml-event the errors are shown to the user,
180  * so they can inform the campaign maintainer.
181  */
182 std::stringstream& wml_error();
183 
184 } // namespace lg
185 
186 #define log_scope(description) lg::scope_logger scope_logging_object__(lg::general(), description);
187 #define log_scope2(domain,description) lg::scope_logger scope_logging_object__(domain, description);
188 
189 #define LOG_STREAM(level, domain) if (lg::level().dont_log(domain)) ; else lg::level()(domain)
190 
191 // When using log_scope/log_scope2 it is nice to have all output indented.
192 #define LOG_STREAM_INDENT(level,domain) if (lg::level().dont_log(domain)) ; else lg::level()(domain, true, true)
std::string get_timestamp(const std::time_t &t, const std::string &format)
Definition: log.cpp:175
char const * name_
Definition: log.hpp:116
std::string get_timespan(const std::time_t &t)
Definition: log.cpp:182
logger(char const *name, int severity)
Definition: log.hpp:119
logger & info()
Definition: log.cpp:90
void timestamps(bool t)
Definition: log.cpp:75
std::string str_
Definition: log.hpp:151
redirect_output_setter(std::ostream &stream)
Constructor.
Definition: log.cpp:61
Helper class to redirect the output of the logger in a certain scope.
Definition: log.hpp:72
std::pair< const std::string, int > logd
Definition: log.hpp:95
bool broke_strict()
Definition: log.cpp:171
scope_logger(const log_domain &domain, const char *str)
Definition: log.hpp:153
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
bool get_log_domain_severity(const std::string &name, int &severity)
Definition: log.cpp:142
int severity_
Definition: log.hpp:117
ptime ticks_
Definition: log.hpp:149
std::ostream * output_
Definition: log.hpp:150
logger & debug()
Definition: log.cpp:96
bool dont_log(const log_domain &domain) const
Definition: log.hpp:123
log_domain & general()
Definition: log.cpp:104
Definition: pump.hpp:39
std::ostream * old_stream_
The previously set redirection.
Definition: log.hpp:92
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:269
logger & err()
Definition: log.cpp:78
void set_strict_severity(int severity)
Definition: log.cpp:161
std::string get_name() const
Definition: log.hpp:133
bool set_log_domain_severity(const std::string &name, int severity)
Definition: log.cpp:118
logger & warn()
Definition: log.cpp:84
double t
Definition: astarsearch.cpp:64
std::string list_logdomains(const std::string &filter)
Definition: log.cpp:151
int get_severity() const
Definition: log.hpp:128
scope_logger(const log_domain &domain, const std::string &str)
Definition: log.hpp:158
void precise_timestamps(bool pt)
Definition: log.cpp:76
logd * domain_
Definition: log.hpp:100