vsg  1.1.0
VulkanSceneGraph library
Logger.h
1 #pragma once
2 
3 /* <editor-fold desc="MIT License">
4 
5 Copyright(c) 2022 Robert Osfield
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 
9 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 
13 </editor-fold> */
14 
15 #include <vsg/core/Inherit.h>
16 #include <vsg/io/stream.h>
17 
18 #include <mutex>
19 #include <string_view>
20 #include <thread>
21 
22 namespace vsg
23 {
24 
26  class VSG_DECLSPEC Logger : public Object
27  {
28  public:
29  Logger();
30 
31  Logger(const Logger& rhs);
32 
33  enum Level
34  {
35  LOGGER_ALL = 0,
36  LOGGER_DEBUG = 1,
37  LOGGER_INFO = 2,
38  LOGGER_WARN = 3,
39  LOGGER_ERROR = 4,
40  LOGGER_FATAL = 5,
41  LOGGER_OFF = 6
42  };
43 
44  Level level = LOGGER_INFO;
45 
48 
49  virtual void flush() {}
50 
51  inline void debug(char* message) { debug(std::string_view(message)); }
52  inline void debug(const char* message) { debug(std::string_view(message)); }
53  inline void debug(std::string& message) { debug(std::string_view(message)); }
54  inline void debug(const std::string& message) { debug(std::string_view(message)); }
55 
56  void debug(const std::string_view& str)
57  {
58  if (level > LOGGER_DEBUG) return;
59 
60  std::scoped_lock<std::mutex> lock(_mutex);
61  debug_implementation(str);
62  }
63 
64  template<typename... Args>
65  void debug(Args&&... args)
66  {
67  if (level > LOGGER_DEBUG) return;
68 
69  std::scoped_lock<std::mutex> lock(_mutex);
70  _stream.str({});
71  _stream.clear();
72  (_stream << ... << args);
73 
74  debug_implementation(_stream.str());
75  }
76 
77  inline void info(char* message) { info(std::string_view(message)); }
78  inline void info(const char* message) { info(std::string_view(message)); }
79  inline void info(std::string& message) { info(std::string_view(message)); }
80  inline void info(const std::string& message) { info(std::string_view(message)); }
81 
82  void info(const std::string_view& str)
83  {
84  if (level > LOGGER_INFO) return;
85 
86  std::scoped_lock<std::mutex> lock(_mutex);
87  info_implementation(str);
88  }
89 
90  template<typename... Args>
91  void info(Args&&... args)
92  {
93  if (level > LOGGER_INFO) return;
94 
95  std::scoped_lock<std::mutex> lock(_mutex);
96  _stream.str({});
97  _stream.clear();
98  (_stream << ... << args);
99 
100  info_implementation(_stream.str());
101  }
102 
103  inline void warn(char* message) { warn(std::string_view(message)); }
104  inline void warn(const char* message) { warn(std::string_view(message)); }
105  inline void warn(std::string& message) { warn(std::string_view(message)); }
106  inline void warn(const std::string& message) { warn(std::string_view(message)); }
107 
108  void warn(const std::string_view& str)
109  {
110  if (level > LOGGER_WARN) return;
111 
112  std::scoped_lock<std::mutex> lock(_mutex);
113  warn_implementation(str);
114  }
115 
116  template<typename... Args>
117  void warn(Args&&... args)
118  {
119  if (level > LOGGER_WARN) return;
120 
121  std::scoped_lock<std::mutex> lock(_mutex);
122  _stream.str({});
123  _stream.clear();
124  (_stream << ... << args);
125 
126  warn_implementation(_stream.str());
127  }
128 
129  inline void error(char* message) { error(std::string_view(message)); }
130  inline void error(const char* message) { error(std::string_view(message)); }
131  inline void error(std::string& message) { error(std::string_view(message)); }
132  inline void error(const std::string& message) { error(std::string_view(message)); }
133 
134  void error(const std::string_view& str)
135  {
136  if (level > LOGGER_DEBUG) return;
137 
138  std::scoped_lock<std::mutex> lock(_mutex);
139  error_implementation(str);
140  }
141 
142  template<typename... Args>
143  void error(Args&&... args)
144  {
145  if (level > LOGGER_ERROR) return;
146 
147  std::scoped_lock<std::mutex> lock(_mutex);
148  _stream.str({});
149  _stream.clear();
150  (_stream << ... << args);
151 
152  error_implementation(_stream.str());
153  }
154 
155  inline void fatal(char* message) { fatal(std::string_view(message)); }
156  inline void fatal(const char* message) { fatal(std::string_view(message)); }
157  inline void fatal(std::string& message) { fatal(std::string_view(message)); }
158  inline void fatal(const std::string& message) { fatal(std::string_view(message)); }
159 
160  void fatal(const std::string_view& str)
161  {
162  if (level > LOGGER_DEBUG) return;
163 
164  std::scoped_lock<std::mutex> lock(_mutex);
165  fatal_implementation(str);
166  }
167 
168  template<typename... Args>
169  void fatal(Args&&... args)
170  {
171  if (level > LOGGER_ERROR) return;
172 
173  std::scoped_lock<std::mutex> lock(_mutex);
174  _stream.str({});
175  _stream.clear();
176  (_stream << ... << args);
177 
178  fatal_implementation(_stream.str());
179  }
180 
181  using PrintToStreamFunction = std::function<void(std::ostream&)>;
182 
184  void debug_stream(PrintToStreamFunction print);
185 
187  void info_stream(PrintToStreamFunction print);
188 
190  void warn_stream(PrintToStreamFunction print);
191 
193  void error_stream(PrintToStreamFunction print);
194 
196  void fatal_stream(PrintToStreamFunction print);
197 
199  inline void log(Level msg_level, char* message) { log(msg_level, std::string_view(message)); }
200  inline void log(Level msg_level, const char* message) { log(msg_level, std::string_view(message)); }
201  inline void log(Level msg_level, std::string& message) { log(msg_level, std::string_view(message)); }
202  inline void log(Level msg_level, const std::string& message) { log(msg_level, std::string_view(message)); }
203 
204  void log(Level msg_level, const std::string_view& message);
205 
207  template<typename... Args>
208  void log(Level msg_level, Args... args)
209  {
210  if (level > msg_level) return;
211 
212  std::scoped_lock<std::mutex> lock(_mutex);
213  _stream.str({});
214  _stream.clear();
215  (_stream << ... << args);
216 
217  switch (msg_level)
218  {
219  case (LOGGER_DEBUG): debug_implementation(_stream.str()); break;
220  case (LOGGER_INFO): info_implementation(_stream.str()); break;
221  case (LOGGER_WARN): warn_implementation(_stream.str()); break;
222  case (LOGGER_ERROR): error_implementation(_stream.str()); break;
223  case (LOGGER_FATAL): fatal_implementation(_stream.str()); break;
224  default: break;
225  }
226  }
227 
229  void log_stream(Level msg_level, PrintToStreamFunction print);
230 
231  protected:
232  virtual ~Logger();
233 
234  std::mutex _mutex;
235  std::ostringstream _stream;
236 
237  virtual void debug_implementation(const std::string_view& message) = 0;
238  virtual void info_implementation(const std::string_view& message) = 0;
239  virtual void warn_implementation(const std::string_view& message) = 0;
240  virtual void error_implementation(const std::string_view& message) = 0;
241  virtual void fatal_implementation(const std::string_view& message) = 0;
242  };
243  VSG_type_name(vsg::Logger);
244 
247  template<typename... Args>
248  void debug(Args&&... args)
249  {
250  Logger::instance()->debug(args...);
251  }
252 
254  inline void debug_stream(Logger::PrintToStreamFunction print)
255  {
256  Logger::instance()->debug_stream(print);
257  }
258 
261  template<typename... Args>
262  void info(Args&&... args)
263  {
264  Logger::instance()->info(args...);
265  }
266 
268  inline void info_stream(Logger::PrintToStreamFunction print)
269  {
270  Logger::instance()->info_stream(print);
271  }
272 
274  template<typename... Args>
275  void warn(Args&&... args)
276  {
277  Logger::instance()->warn(args...);
278  }
279 
281  inline void warn_stream(Logger::PrintToStreamFunction print)
282  {
283  Logger::instance()->warn_stream(print);
284  }
285 
287  template<typename... Args>
288  void error(Args&&... args)
289  {
290  Logger::instance()->error(args...);
291  }
292 
294  inline void error_stream(Logger::PrintToStreamFunction print)
295  {
296  Logger::instance()->error_stream(print);
297  }
298 
300  template<typename... Args>
301  void fatal(Args&&... args)
302  {
303  Logger::instance()->fatal(args...);
304  }
305 
307  inline void fatal_stream(Logger::PrintToStreamFunction print)
308  {
309  Logger::instance()->fatal_stream(print);
310  }
311 
313  template<typename... Args>
314  void log(Logger::Level msg_level, Args&&... args)
315  {
316  Logger::instance()->log(msg_level, args...);
317  }
318 
320  inline void log_stream(Logger::Level msg_level, Logger::PrintToStreamFunction print)
321  {
322  Logger::instance()->log_stream(msg_level, print);
323  }
324 
326  class VSG_DECLSPEC StdLogger : public Inherit<Logger, StdLogger>
327  {
328  public:
329  StdLogger();
330 
331  std::string debugPrefix = "debug: ";
332  std::string infoPrefix = "info: ";
333  std::string warnPrefix = "Warning: ";
334  std::string errorPrefix = "ERROR: ";
335  std::string fatalPrefix = "FATAL: ";
336 
337  void flush() override;
338 
339  protected:
340  void debug_implementation(const std::string_view& message) override;
341  void info_implementation(const std::string_view& message) override;
342  void warn_implementation(const std::string_view& message) override;
343  void error_implementation(const std::string_view& message) override;
344  void fatal_implementation(const std::string_view& message) override;
345  };
346  VSG_type_name(vsg::StdLogger);
347 
351  class VSG_DECLSPEC ThreadLogger : public vsg::Inherit<vsg::Logger, ThreadLogger>
352  {
353  public:
354  ThreadLogger();
355 
357  void setThreadPrefix(std::thread::id id, const std::string& str);
358 
359  std::string debugPrefix = "debug: ";
360  std::string infoPrefix = "info: ";
361  std::string warnPrefix = "Warning: ";
362  std::string errorPrefix = "ERROR: ";
363  std::string fatalPrefix = "FATAL: ";
364 
365  void flush() override;
366 
367  protected:
368  void print_id(std::ostream& out, std::thread::id id);
369 
370  void debug_implementation(const std::string_view& message) override;
371  void info_implementation(const std::string_view& message) override;
372  void warn_implementation(const std::string_view& message) override;
373  void error_implementation(const std::string_view& message) override;
374  void fatal_implementation(const std::string_view& message) override;
375 
376  std::map<std::thread::id, std::string> _threadPrefixes;
377  };
378  VSG_type_name(vsg::ThreadLogger);
379 
383  class VSG_DECLSPEC NullLogger : public Inherit<Logger, NullLogger>
384  {
385  public:
386  NullLogger();
387 
388  protected:
389  void debug_implementation(const std::string_view&) override;
390  void info_implementation(const std::string_view&) override;
391  void warn_implementation(const std::string_view&) override;
392  void error_implementation(const std::string_view&) override;
393  void fatal_implementation(const std::string_view&) override;
394  };
395  VSG_type_name(vsg::NullLogger);
396 
397 } // namespace vsg
Definition: Inherit.h:28
thread safe, pure virtual Logger base class that provides extensible message logging facilities
Definition: Logger.h:27
void error_stream(PrintToStreamFunction print)
thread safe access to stream for writing error output.
void debug_stream(PrintToStreamFunction print)
thread safe access to stream for writing debug output.
void log(Level msg_level, Args... args)
pass message to debug()/info()/warn()/error() based on specified level
Definition: Logger.h:208
void fatal_stream(PrintToStreamFunction print)
thread safe access to stream for writing fatal output and throwing vsg::Exception
void info_stream(PrintToStreamFunction print)
thread safe access to stream for writing info output.
static ref_ptr< Logger > & instance()
Logger singleton, defaults to using vsg::StdLogger.
void log(Level msg_level, char *message)
pass message to debug()/info()/warn()/error() based on specified level
Definition: Logger.h:199
void warn_stream(PrintToStreamFunction print)
thread safe access to stream for writing warn output.
void log_stream(Level msg_level, PrintToStreamFunction print)
thread safe access to stream for writing error output.
Definition: Logger.h:384
Definition: Object.h:42
default Logger that sends debug and info messages to std:cout, and warn and error messages to std::ce...
Definition: Logger.h:327
Definition: Logger.h:352
void setThreadPrefix(std::thread::id id, const std::string &str)
assign prefix for std::thread::id. The id can be obtained from std::thread::get_id() i....
Definition: ref_ptr.h:22