Simulant  21.12-1292
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
logging.h
1 #pragma once
2 
3 #include <chrono>
4 #include <string>
5 #include <fstream>
6 #include <iostream>
7 #include <memory>
8 #include <vector>
9 #include <sstream>
10 #include <unordered_set>
11 #include <unordered_map>
12 #include <iomanip>
13 
14 #include "utils/string.h"
15 #include "utils/formatter.h"
16 #include "threads/mutex.h"
17 #include "threads/thread.h"
18 
19 #include "compat.h"
20 
21 namespace smlt {
22 
23 enum LogLevel {
24  LOG_LEVEL_NONE = 0,
25  LOG_LEVEL_ERROR = 1,
26  LOG_LEVEL_WARN = 2,
27  LOG_LEVEL_INFO = 3,
28  LOG_LEVEL_DEBUG = 4,
29  LOG_LEVEL_VERBOSE = 5
30 };
31 
32 class Logger;
33 
34 typedef std::chrono::time_point<std::chrono::system_clock> DateTime;
35 
36 class Handler {
37 public:
38  typedef std::shared_ptr<Handler> ptr;
39 
40  virtual ~Handler() {}
41  void write_message(Logger* logger,
42  const DateTime& time,
43  const std::string& level,
44  const std::string& message);
45 
46 private:
47  virtual void do_write_message(Logger* logger,
48  const DateTime& time,
49  const std::string& level,
50  const std::string& message) = 0;
51 };
52 
53 class StdIOHandler : public Handler {
54 public:
55  StdIOHandler();
56  ~StdIOHandler();
57 
58 private:
59 
60  void do_write_message(Logger* logger,
61  const DateTime& time,
62  const std::string& level,
63  const std::string& message) override;
64 
65  thread::Mutex lock_;
66 };
67 
68 class FileHandler : public Handler {
69 public:
70  FileHandler(const std::string& filename);
71 
72 private:
73  void do_write_message(Logger* logger,
74  const DateTime& time,
75  const std::string& level,
76  const std::string& message);
77  std::string filename_;
78  std::ofstream stream_;
79 };
80 
81 class Logger {
82 public:
83  typedef std::shared_ptr<Logger> ptr;
84 
85  /* WARNING: Do not add a destructor - it won't get called! */
86 
87  Logger(const std::string& name):
88  name_(name),
89  level_(LOG_LEVEL_DEBUG) {
90 
91  }
92 
93  void add_handler(Handler::ptr handler) {
94  //FIXME: check it doesn't exist already
95  handlers_.push_back(handler);
96  }
97 
98  void verbose(const std::string& text, const std::string& file="None", int32_t line=-1) {
99  if(level_ < LOG_LEVEL_VERBOSE) return;
100 
101  write_message("VERBOSE", "\x1b[97m" + text + "\x1b[0m", file, line);
102  }
103 
104  void debug(const std::string& text, const std::string& file="None", int32_t line=-1) {
105  if(level_ < LOG_LEVEL_DEBUG) return;
106 
107  write_message("DEBUG", text, file, line);
108  }
109 
110  void info(const std::string& text, const std::string& file="None", int32_t line=-1) {
111  if(level_ < LOG_LEVEL_INFO) return;
112 
113  write_message("INFO", "\x1b[36m" + text + "\x1b[0m", file, line);
114  }
115 
116  void warn(const std::string& text, const std::string& file="None", int32_t line=-1) {
117  if(level_ < LOG_LEVEL_WARN) return;
118 
119  write_message("WARN", "\x1b[33m" + text + "\x1b[0m", file, line);
120  }
121 
122  void error(const std::string& text, const std::string& file="None", int32_t line=-1) {
123  if(level_ < LOG_LEVEL_ERROR) return;
124 
125  write_message("ERROR", "\x1b[31m" + text + "\x1b[0m", file, line);
126  }
127 
128  void set_level(LogLevel level) {
129  level_ = level;
130  }
131 
132  LogLevel level() const {
133  return level_;
134  }
135 
136 private:
137  void write_message(const std::string& level, const std::string& text,
138  const std::string& file, int32_t line) {
139 
140  std::stringstream s;
141  s << thread::this_thread_id() << ": ";
142 
143  if(line > -1) {
144  s << text << " (" << file << ":" << line << ")";
145  } else {
146  s << text;
147  }
148 
149  for(uint32_t i = 0; i < handlers_.size(); ++i) {
150  handlers_[i]->write_message(this, std::chrono::system_clock::now(), level, s.str());
151  }
152  }
153 
154  std::string name_;
155  std::vector<Handler::ptr> handlers_;
156 
157  LogLevel level_;
158 };
159 
160 Logger* get_logger(const std::string& name);
161 
162 void verbose(const std::string& text, const std::string& file="None", int32_t line=-1);
163 void debug(const std::string& text, const std::string& file="None", int32_t line=-1);
164 void info(const std::string& text, const std::string& file="None", int32_t line=-1);
165 void warn(const std::string& text, const std::string& file="None", int32_t line=-1);
166 void error(const std::string& text, const std::string& file="None", int32_t line=-1);
167 
168 
170 public:
171  DebugScopedLog(const std::string& text, const std::string& file, uint32_t line):
172  text_(text) {
173 
174  debug(smlt::Formatter("Enter: {0} ({1}, {2})").format(text, file, line));
175  }
176 
177  ~DebugScopedLog() {
178  debug(smlt::Formatter("Exit: {0}").format(text_));
179  }
180 
181 private:
182  std::string text_;
183 };
184 
185 }
186 
187 #ifndef NDEBUG
188 
189 #define S_VERBOSE(str, ...) \
190  smlt::verbose(_F(str).format(__VA_ARGS__), __FILE__, __LINE__)
191 
192 #define S_DEBUG(str, ...) \
193  smlt::debug(_F(str).format(__VA_ARGS__), __FILE__, __LINE__)
194 
195 #define S_INFO(str, ...) \
196  smlt::info(_F(str).format(__VA_ARGS__), __FILE__, __LINE__)
197 
198 #define S_WARN(str, ...) \
199  smlt::warn(_F(str).format(__VA_ARGS__), __FILE__, __LINE__)
200 
201 #define S_ERROR(str, ...) \
202  smlt::error(_F(str).format(__VA_ARGS__), __FILE__, __LINE__)
203 
204 #define S_DEBUG_ONCE(str, ...) \
205  do { static char _done = 0; if(!_done++) smlt::debug(_F(str).format(__VA_ARGS__)); } while(0)
206 
207 #define S_INFO_ONCE(str, ...) \
208  do { static char _done = 0; if(!_done++) smlt::info(_F(str).format(__VA_ARGS__)); } while(0)
209 
210 #define S_WARN_ONCE(str, ...) \
211  do { static char _done = 0; if(!_done++) smlt::warn(_F(str).format(__VA_ARGS__)); } while(0)
212 
213 #define S_ERROR_ONCE(str, ...) \
214  do { static char _done = 0; if(!_done++) smlt::error(_F(str).format(__VA_ARGS__)); } while(0)
215 
216 #else
217 
218 #define S_VERBOSE(str, ...) \
219  smlt::verbose(_F(str).format(__VA_ARGS__))
220 
221 #define S_DEBUG(str, ...) \
222  smlt::debug(_F(str).format(__VA_ARGS__))
223 
224 #define S_INFO(str, ...) \
225  smlt::info(_F(str).format(__VA_ARGS__))
226 
227 #define S_WARN(str, ...) \
228  smlt::warn(_F(str).format(__VA_ARGS__))
229 
230 #define S_ERROR(str, ...) \
231  smlt::error(_F(str).format(__VA_ARGS__))
232 
233 #define S_DEBUG_ONCE(str, ...) \
234  do { static char _done = 0; if(!_done++) smlt::debug(_F(str).format(__VA_ARGS__)); } while(0)
235 
236 #define S_INFO_ONCE(str, ...) \
237  do { static char _done = 0; if(!_done++) smlt::info(_F(str).format(__VA_ARGS__)); } while(0)
238 
239 #define S_WARN_ONCE(str, ...) \
240  do { static char _done = 0; if(!_done++) smlt::warn(_F(str).format(__VA_ARGS__)); } while(0)
241 
242 #define S_ERROR_ONCE(str, ...) \
243  do { static char _done = 0; if(!_done++) smlt::error(_F(str).format(__VA_ARGS__)); } while(0)
244 
245 #endif
smlt::FileHandler
Definition: logging.h:68
smlt::DebugScopedLog
Definition: logging.h:169
smlt
Definition: animation.cpp:25
smlt::StdIOHandler
Definition: logging.h:53
smlt::Formatter
Definition: formatter.h:12
smlt::Logger
Definition: logging.h:81
smlt::Handler
Definition: logging.h:36
smlt::thread::Mutex
Definition: mutex.h:35