The Battle for Wesnoth  1.15.6+dev
log.cpp
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 (implementation).
19  * See also the command line switches --logdomains and --log-@<level@>="domain".
20  */
21 
22 #include "log.hpp"
23 
24 #include <boost/date_time.hpp>
25 
26 #include <map>
27 #include <sstream>
28 #include <ctime>
29 #include <mutex>
30 
31 #include "global.hpp"
32 
33 namespace {
34 
35 class null_streambuf : public std::streambuf
36 {
37  virtual int overflow(int c) { return std::char_traits< char >::not_eof(c); }
38 public:
39  null_streambuf() {}
40 };
41 
42 } // end anonymous namespace
43 
44 static std::ostream null_ostream(new null_streambuf);
45 static int indent = 0;
46 static bool timestamp = true;
47 static bool precise_timestamp = false;
48 static std::mutex log_mutex;
49 
50 static std::ostream *output_stream = nullptr;
51 
52 static std::ostream& output()
53 {
54  if(output_stream) {
55  return *output_stream;
56  }
57  return std::cerr;
58 }
59 
60 namespace lg {
61 
62 redirect_output_setter::redirect_output_setter(std::ostream& stream)
63  : old_stream_(output_stream)
64 {
65  output_stream = &stream;
66 }
67 
69 {
71 }
72 
73 typedef std::map<std::string, int> domain_map;
74 static domain_map *domains;
75 static int strict_level_ = -1;
76 void timestamps(bool t) { timestamp = t; }
77 void precise_timestamps(bool pt) { precise_timestamp = pt; }
78 
80 {
81  static logger lg("error", 0);
82  return lg;
83 }
84 
86 {
87  static logger lg("warning", 1);
88  return lg;
89 }
90 
92 {
93  static logger lg("info", 2);
94  return lg;
95 }
96 
98 {
99  static logger lg("debug", 3);
100  return lg;
101 }
102 
103 static log_domain dom("general");
104 
106 {
107  return dom;
108 }
109 
110 log_domain::log_domain(char const *name, int severity)
111  : domain_(nullptr)
112 {
113  // Indirection to prevent initialization depending on link order.
114  if (!domains) domains = new domain_map;
115  domain_ = &*domains->insert(logd(name, severity)).first;
116  domain_->second = severity;
117 }
118 
119 bool set_log_domain_severity(const std::string& name, int severity)
120 {
121  std::string::size_type s = name.size();
122  if (name == "all") {
123  for(logd &l : *domains) {
124  l.second = severity;
125  }
126  } else if (s > 2 && name.compare(s - 2, 2, "/*") == 0) {
127  for(logd &l : *domains) {
128  if (l.first.compare(0, s - 1, name, 0, s - 1) == 0)
129  l.second = severity;
130  }
131  } else {
132  domain_map::iterator it = domains->find(name);
133  if (it == domains->end())
134  return false;
135  it->second = severity;
136  }
137  return true;
138 }
140  return set_log_domain_severity(name, lg.get_severity());
141 }
142 
143 bool get_log_domain_severity(const std::string& name, int &severity)
144 {
145  domain_map::iterator it = domains->find(name);
146  if (it == domains->end())
147  return false;
148  severity = it->second;
149  return true;
150 }
151 
153 {
154  std::ostringstream res;
155  for(logd &l : *domains) {
156  if(l.first.find(filter) != std::string::npos)
157  res << l.first << "\n";
158  }
159  return res.str();
160 }
161 
162 void set_strict_severity(int severity) {
163  strict_level_ = severity;
164 }
165 
168 }
169 
170 static bool strict_threw_ = false;
171 
172 bool broke_strict() {
173  return strict_threw_;
174 }
175 
176 std::string get_timestamp(const std::time_t& t, const std::string& format) {
177  std::ostringstream ss;
178 
179  ss << std::put_time(std::localtime(&t), format.c_str());
180 
181  return ss.str();
182 }
183 std::string get_timespan(const std::time_t& t) {
184  std::ostringstream sout;
185  // There doesn't seem to be any library function for this
186  const std::time_t minutes = t / 60;
187  const std::time_t days = minutes / 60 / 24;
188  if(t <= 0) {
189  sout << "expired";
190  } else if(minutes == 0) {
191  sout << t << " seconds";
192  } else if(days == 0) {
193  sout << minutes / 60 << " hours, " << minutes % 60 << " minutes";
194  } else {
195  sout << days << " days, " << (minutes / 60) % 24 << " hours, " << minutes % 60 << " minutes";
196  }
197  return sout.str();
198 }
199 
200 static void print_precise_timestamp(std::ostream& out) noexcept
201 {
202  try {
203  int64_t micros = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
204  std::time_t seconds = micros/1'000'000;
205  int fractional = micros-(seconds*1'000'000);
206  char c = out.fill('0');
207  out << std::put_time(std::localtime(&seconds), "%Y%m%d %H:%M:%S") << "." << std::setw(6) << fractional << ' ';
208  out.fill(c);
209  } catch(...) {}
210 }
211 
212 log_in_progress logger::operator()(const log_domain& domain, bool show_names, bool do_indent) const
213 {
214  if (severity_ > domain.domain_->second) {
215  return null_ostream;
216  } else {
217  if (!strict_threw_ && (severity_ <= strict_level_)) {
218  std::stringstream ss;
219  ss << "Error (strict mode, strict_level = " << strict_level_ << "): wesnoth reported on channel " << name_ << " " << domain.domain_->first;
220  std::cerr << ss.str() << std::endl;
221  strict_threw_ = true;
222  }
223  log_in_progress stream = output();
224  if(do_indent) {
225  stream.set_indent(indent);
226  }
227  if (timestamp) {
228  stream.enable_timestamp();
229  }
230  if (show_names) {
231  stream.set_prefix(formatter() << name_ << ' ' << domain.domain_->first << ": ");
232  }
233  return stream;
234  }
235 }
236 
237 log_in_progress::log_in_progress(std::ostream& stream)
238  : stream_(stream)
239 {}
240 
242 {
243  std::lock_guard<std::mutex> lock(log_mutex);
244  for(int i = 0; i < indent; ++i)
245  stream_ << " ";
246  if(timestamp_) {
247  if(precise_timestamp) {
249  } else {
250  stream_ << get_timestamp(std::time(nullptr));
251  }
252  }
253  stream_ << prefix_ << message.str();
254 }
255 
257  indent_ = level;
258 }
259 
261  timestamp_ = true;
262 }
263 
265  prefix_ = prefix;
266 }
267 
269 {
270  str_ = str;
271  try {
272  ticks_ = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
273  } catch(...) {}
274  debug()(domain_, false, true) | formatter() << "{ BEGIN: " << str_ << "\n";
275  ++indent;
276 }
277 
279 {
280  long ticks = 0;
281  try {
282  ticks = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count() - ticks_;
283  } catch(...) {}
284  --indent;
285  auto output = debug()(domain_, false, true);
286  output.set_indent(indent);
287  if(timestamp) output.enable_timestamp();
288  output | formatter() << "} END: " << str_ << " (took " << ticks << "ms)\n";
289 }
290 
291 std::stringstream& wml_error()
292 {
293  static std::stringstream lg;
294  return lg;
295 }
296 
297 } // end namespace lg
298 
static log_domain dom("general")
static int strict_level_
Definition: log.cpp:75
std::string get_timestamp(const std::time_t &t, const std::string &format)
Definition: log.cpp:176
static std::mutex log_mutex
Definition: log.cpp:48
static domain_map * domains
Definition: log.cpp:74
std::string get_timespan(const std::time_t &t)
Definition: log.cpp:183
void do_log_exit() noexcept
Definition: log.cpp:278
logger & info()
Definition: log.cpp:91
void timestamps(bool t)
Definition: log.cpp:76
log_in_progress(std::ostream &stream)
Definition: log.cpp:237
std::string str
Definition: statement.cpp:110
log_domain(char const *name, int severity=1)
Definition: log.cpp:110
static std::ostream * output_stream
Definition: log.cpp:50
std::pair< const std::string, int > logd
Definition: log.hpp:94
bool broke_strict()
Definition: log.cpp:172
static std::ostream & output()
Definition: log.cpp:52
bool get_log_domain_severity(const std::string &name, int &severity)
Definition: log.cpp:143
std::ostringstream wrapper.
Definition: formatter.hpp:38
log_in_progress operator()(const log_domain &domain, bool show_names=true, bool do_indent=false) const
Definition: log.cpp:212
static bool precise_timestamp
Definition: log.cpp:47
logger & debug()
Definition: log.cpp:97
static int indent
Definition: log.cpp:45
log_domain & general()
Definition: log.cpp:105
void do_log_entry(const std::string &str) noexcept
Definition: log.cpp:268
std::map< std::string, int > domain_map
Definition: log.cpp:73
Definition: pump.hpp:39
std::ostream * old_stream_
The previously set redirection.
Definition: log.hpp:91
std::size_t i
Definition: function.cpp:933
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:291
logger & err()
Definition: log.cpp:79
static void print_precise_timestamp(std::ostream &out) noexcept
Definition: log.cpp:200
void set_strict_severity(int severity)
Definition: log.cpp:162
static map_location::DIRECTION s
std::string name
Definition: sdl_ttf.cpp:70
bool set_log_domain_severity(const std::string &name, int severity)
Definition: log.cpp:119
void operator|(formatter &&message)
Definition: log.cpp:241
static bool strict_threw_
Definition: log.cpp:170
logger & warn()
Definition: log.cpp:85
double t
Definition: astarsearch.cpp:64
void enable_timestamp()
Definition: log.cpp:260
static bool timestamp
Definition: log.cpp:46
std::string list_logdomains(const std::string &filter)
Definition: log.cpp:152
std::string prefix_
Definition: log.hpp:125
Standard logging facilities (interface).
static std::ostream null_ostream(new null_streambuf)
void set_prefix(const std::string &prefix)
Definition: log.cpp:264
void set_indent(int level)
Definition: log.cpp:256
mock_char c
int get_severity() const
Definition: log.hpp:147
std::ostream & stream_
Definition: log.hpp:122
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
void precise_timestamps(bool pt)
Definition: log.cpp:77
logd * domain_
Definition: log.hpp:99
auto * ss
Definition: result_set.cpp:281