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