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