vsg: include/vsg/io/Logger.h Source File

vsg 1.1.13 VulkanSceneGraph library

Loading...
Searching...
No Matches
Logger.h
1#pragma once
2
3/* <editor-fold desc="MIT License">
4
5Copyright(c) 2022 Robert Osfield
6
7Permission 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
9The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
11THE 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
22namespace 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
47 static ref_ptr<Logger>& instance();
48
50 virtual void redirect_std();
51
52 virtual void flush() {}
53
54 inline void debug(char* message) { debug(std::string_view(message)); }
55 inline void debug(const char* message) { debug(std::string_view(message)); }
56 inline void debug(std::string& message) { debug(std::string_view(message)); }
57 inline void debug(const std::string& message) { debug(std::string_view(message)); }
58
59 void debug(const std::string_view& str)
60 {
61 if (level > LOGGER_DEBUG) return;
62
63 std::scoped_lock<std::mutex> lock(_mutex);
64 debug_implementation(str);
65 }
66
67 template<typename... Args>
68 void debug(Args&&... args)
69 {
70 if (level > LOGGER_DEBUG) return;
71
72 std::scoped_lock<std::mutex> lock(_mutex);
73 _stream.str({});
74 _stream.clear();
75 (_stream << ... << args);
76
77 debug_implementation(_stream.str());
78 }
79
80 inline void info(char* message) { info(std::string_view(message)); }
81 inline void info(const char* message) { info(std::string_view(message)); }
82 inline void info(std::string& message) { info(std::string_view(message)); }
83 inline void info(const std::string& message) { info(std::string_view(message)); }
84
85 void info(const std::string_view& str)
86 {
87 if (level > LOGGER_INFO) return;
88
89 std::scoped_lock<std::mutex> lock(_mutex);
90 info_implementation(str);
91 }
92
93 template<typename... Args>
94 void info(Args&&... args)
95 {
96 if (level > LOGGER_INFO) return;
97
98 std::scoped_lock<std::mutex> lock(_mutex);
99 _stream.str({});
100 _stream.clear();
101 (_stream << ... << args);
102
103 info_implementation(_stream.str());
104 }
105
106 inline void warn(char* message) { warn(std::string_view(message)); }
107 inline void warn(const char* message) { warn(std::string_view(message)); }
108 inline void warn(std::string& message) { warn(std::string_view(message)); }
109 inline void warn(const std::string& message) { warn(std::string_view(message)); }
110
111 void warn(const std::string_view& str)
112 {
113 if (level > LOGGER_WARN) return;
114
115 std::scoped_lock<std::mutex> lock(_mutex);
116 warn_implementation(str);
117 }
118
119 template<typename... Args>
120 void warn(Args&&... args)
121 {
122 if (level > LOGGER_WARN) return;
123
124 std::scoped_lock<std::mutex> lock(_mutex);
125 _stream.str({});
126 _stream.clear();
127 (_stream << ... << args);
128
129 warn_implementation(_stream.str());
130 }
131
132 inline void error(char* message) { error(std::string_view(message)); }
133 inline void error(const char* message) { error(std::string_view(message)); }
134 inline void error(std::string& message) { error(std::string_view(message)); }
135 inline void error(const std::string& message) { error(std::string_view(message)); }
136
137 void error(const std::string_view& str)
138 {
139 if (level > LOGGER_ERROR) return;
140
141 std::scoped_lock<std::mutex> lock(_mutex);
142 error_implementation(str);
143 }
144
145 template<typename... Args>
146 void error(Args&&... args)
147 {
148 if (level > LOGGER_ERROR) return;
149
150 std::scoped_lock<std::mutex> lock(_mutex);
151 _stream.str({});
152 _stream.clear();
153 (_stream << ... << args);
154
155 error_implementation(_stream.str());
156 }
157
158 inline void fatal(char* message) { fatal(std::string_view(message)); }
159 inline void fatal(const char* message) { fatal(std::string_view(message)); }
160 inline void fatal(std::string& message) { fatal(std::string_view(message)); }
161 inline void fatal(const std::string& message) { fatal(std::string_view(message)); }
162
163 void fatal(const std::string_view& str)
164 {
165 if (level > LOGGER_FATAL) return;
166
167 std::scoped_lock<std::mutex> lock(_mutex);
168 fatal_implementation(str);
169 }
170
171 template<typename... Args>
172 void fatal(Args&&... args)
173 {
174 if (level > LOGGER_FATAL) return;
175
176 std::scoped_lock<std::mutex> lock(_mutex);
177 _stream.str({});
178 _stream.clear();
179 (_stream << ... << args);
180
181 fatal_implementation(_stream.str());
182 }
183
184 using PrintToStreamFunction = std::function<void(std::ostream&)>;
185
187 void debug_stream(PrintToStreamFunction print);
188
190 void info_stream(PrintToStreamFunction print);
191
193 void warn_stream(PrintToStreamFunction print);
194
196 void error_stream(PrintToStreamFunction print);
197
199 void fatal_stream(PrintToStreamFunction print);
200
202 inline void log(Level msg_level, char* message) { log(msg_level, std::string_view(message)); }
203 inline void log(Level msg_level, const char* message) { log(msg_level, std::string_view(message)); }
204 inline void log(Level msg_level, std::string& message) { log(msg_level, std::string_view(message)); }
205 inline void log(Level msg_level, const std::string& message) { log(msg_level, std::string_view(message)); }
206
207 void log(Level msg_level, const std::string_view& message);
208
210 template<typename... Args>
211 void log(Level msg_level, Args... args)
212 {
213 if (level > msg_level) return;
214
215 std::scoped_lock<std::mutex> lock(_mutex);
216 _stream.str({});
217 _stream.clear();
218 (_stream << ... << args);
219
220 switch (msg_level)
221 {
222 case (LOGGER_DEBUG): debug_implementation(_stream.str()); break;
223 case (LOGGER_INFO): info_implementation(_stream.str()); break;
224 case (LOGGER_WARN): warn_implementation(_stream.str()); break;
225 case (LOGGER_ERROR): error_implementation(_stream.str()); break;
226 case (LOGGER_FATAL): fatal_implementation(_stream.str()); break;
227 default: break;
228 }
229 }
230
232 void log_stream(Level msg_level, PrintToStreamFunction print);
233
234 protected:
235 virtual ~Logger();
236
237 std::mutex _mutex;
238 std::ostringstream _stream;
239
240 std::unique_ptr<std::streambuf> _override_cout;
241 std::unique_ptr<std::streambuf> _override_cerr;
242 std::streambuf* _original_cout = nullptr;
243 std::streambuf* _original_cerr = nullptr;
244
245 virtual void debug_implementation(const std::string_view& message) = 0;
246 virtual void info_implementation(const std::string_view& message) = 0;
247 virtual void warn_implementation(const std::string_view& message) = 0;
248 virtual void error_implementation(const std::string_view& message) = 0;
249 virtual void fatal_implementation(const std::string_view& message) = 0;
250 };
251 VSG_type_name(vsg::Logger);
252
255 template<typename... Args>
256 void debug(Args&&... args)
257 {
258 Logger::instance()->debug(std::forward<Args>(args)...);
259 }
260
262 inline void debug_stream(Logger::PrintToStreamFunction print)
263 {
264 Logger::instance()->debug_stream(print);
265 }
266
269 template<typename... Args>
270 void info(Args&&... args)
271 {
272 Logger::instance()->info(std::forward<Args>(args)...);
273 }
274
276 inline void info_stream(Logger::PrintToStreamFunction print)
277 {
278 Logger::instance()->info_stream(print);
279 }
280
282 template<typename... Args>
283 void warn(Args&&... args)
284 {
285 Logger::instance()->warn(std::forward<Args>(args)...);
286 }
287
289 inline void warn_stream(Logger::PrintToStreamFunction print)
290 {
291 Logger::instance()->warn_stream(print);
292 }
293
295 template<typename... Args>
296 void error(Args&&... args)
297 {
298 Logger::instance()->error(std::forward<Args>(args)...);
299 }
300
302 inline void error_stream(Logger::PrintToStreamFunction print)
303 {
304 Logger::instance()->error_stream(print);
305 }
306
308 template<typename... Args>
309 void fatal(Args&&... args)
310 {
311 Logger::instance()->fatal(std::forward<Args>(args)...);
312 }
313
315 inline void fatal_stream(Logger::PrintToStreamFunction print)
316 {
317 Logger::instance()->fatal_stream(print);
318 }
319
321 template<typename... Args>
322 void log(Logger::Level msg_level, Args&&... args)
323 {
324 Logger::instance()->log(msg_level, std::forward<Args>(args)...);
325 }
326
328 inline void log_stream(Logger::Level msg_level, Logger::PrintToStreamFunction print)
329 {
330 Logger::instance()->log_stream(msg_level, print);
331 }
332
334 class VSG_DECLSPEC StdLogger : public Inherit<Logger, StdLogger>
335 {
336 public:
337 StdLogger();
338
339 std::string debugPrefix = "debug: ";
340 std::string infoPrefix = "info: ";
341 std::string warnPrefix = "Warning: ";
342 std::string errorPrefix = "ERROR: ";
343 std::string fatalPrefix = "FATAL: ";
344
345 void flush() override;
346
347 protected:
348 void debug_implementation(const std::string_view& message) override;
349 void info_implementation(const std::string_view& message) override;
350 void warn_implementation(const std::string_view& message) override;
351 void error_implementation(const std::string_view& message) override;
352 void fatal_implementation(const std::string_view& message) override;
353 };
354 VSG_type_name(vsg::StdLogger);
355
359 class VSG_DECLSPEC ThreadLogger : public vsg::Inherit<vsg::Logger, ThreadLogger>
360 {
361 public:
362 ThreadLogger();
363
365 void setThreadPrefix(std::thread::id id, const std::string& str);
366
367 std::string debugPrefix = "debug: ";
368 std::string infoPrefix = "info: ";
369 std::string warnPrefix = "Warning: ";
370 std::string errorPrefix = "ERROR: ";
371 std::string fatalPrefix = "FATAL: ";
372
373 void flush() override;
374
375 protected:
376 void print_id(FILE* out, std::thread::id id);
377
378 void debug_implementation(const std::string_view& message) override;
379 void info_implementation(const std::string_view& message) override;
380 void warn_implementation(const std::string_view& message) override;
381 void error_implementation(const std::string_view& message) override;
382 void fatal_implementation(const std::string_view& message) override;
383
384 std::map<std::thread::id, std::string> _threadPrefixes;
385 };
386 VSG_type_name(vsg::ThreadLogger);
387
391 class VSG_DECLSPEC NullLogger : public Inherit<Logger, NullLogger>
392 {
393 public:
394 NullLogger();
395
396 protected:
397 void debug_implementation(const std::string_view&) override;
398 void info_implementation(const std::string_view&) override;
399 void warn_implementation(const std::string_view&) override;
400 void error_implementation(const std::string_view&) override;
401 void fatal_implementation(const std::string_view&) override;
402 };
403 VSG_type_name(vsg::NullLogger);
404
406 struct LogOutput
407 {
408 ref_ptr<Logger> logger;
409 Logger::Level level = Logger::LOGGER_INFO;
410 indentation indent;
411 int step = 4;
412
413 template<typename... Args>
414 void operator()(Args... args) const
415 {
416 if (logger)
417 logger->log(level, indent, (args)...);
418 else
419 Logger::instance()->log(level, indent, (args)...);
420 }
421
422 void in() { indent += step; }
423 void out() { indent -= step; }
424
425 template<typename... Args>
426 void enter(Args... args)
427 {
428 operator()(args...);
429 in();
430 }
431
432 void enter()
433 {
434 operator()("{");
435 in();
436 }
437
438 template<typename... Args>
439 void leave(Args... args)
440 {
441 out();
442 operator()(args...);
443 }
444
445 void leave()
446 {
447 out();
448 operator()("}");
449 }
450 };
451 VSG_type_name(vsg::LogOutput);
452
453} // namespace vsg
vsg::Inherit
Definition Inherit.h:28
vsg::Logger
thread safe, pure virtual Logger base class that provides extensible message logging facilities
Definition Logger.h:27
vsg::Logger::error_stream
void error_stream(PrintToStreamFunction print)
thread safe access to stream for writing error output.
vsg::Logger::debug_stream
void debug_stream(PrintToStreamFunction print)
thread safe access to stream for writing debug output.
vsg::Logger::instance
static ref_ptr< Logger > & instance()
Logger singleton, defaults to using vsg::StdLogger.
vsg::Logger::log
void log(Level msg_level, Args... args)
pass message to debug()/info()/warn()/error() based on specified level
Definition Logger.h:211
vsg::Logger::fatal_stream
void fatal_stream(PrintToStreamFunction print)
thread safe access to stream for writing fatal output and throwing vsg::Exception
vsg::Logger::info_stream
void info_stream(PrintToStreamFunction print)
thread safe access to stream for writing info output.
vsg::Logger::log
void log(Level msg_level, char *message)
pass message to debug()/info()/warn()/error() based on specified level
Definition Logger.h:202
vsg::Logger::warn_stream
void warn_stream(PrintToStreamFunction print)
thread safe access to stream for writing warn output.
vsg::Logger::log_stream
void log_stream(Level msg_level, PrintToStreamFunction print)
thread safe access to stream for writing error output.
vsg::Logger::redirect_std
virtual void redirect_std()
redirect std::cout and std::cerr output to vsg::Logger at level LOGGER_INFO and LOGGER_ERROR respecti...
vsg::NullLogger
Definition Logger.h:392
vsg::StdLogger
default Logger that sends debug and info messages to std:cout, and warn and error messages to std::ce...
Definition Logger.h:335
vsg::ThreadLogger
Definition Logger.h:360
vsg::ThreadLogger::setThreadPrefix
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....
vsg::ref_ptr
Definition ref_ptr.h:22
vsg::LogOutput
Helper class for recording a set of indented log output.
Definition Logger.h:407
vsg::indentation
helper class for inserting indentation into streams useful for formatting output.
Definition stream.h:39