1 /*
2 Loguru logging library for C++, by Emil Ernerfeldt.
3 www.github.com/emilk/loguru
4 If you find Loguru useful, please let me know on twitter or in a mail!
5 Twitter: @ernerfeldt
6 Mail:    emil.ernerfeldt@gmail.com
7 Website: www.ilikebigbits.com
8 
9 # License
10 	This software is in the public domain. Where that dedication is not
11 	recognized, you are granted a perpetual, irrevocable license to copy
12 	and modify this file as you see fit.
13 
14 # Inspiration
15 	Much of Loguru was inspired by GLOG, https://code.google.com/p/google-glog/.
16 	The whole "single header" and public domain is fully due Sean T. Barrett
17 	and his wonderful stb libraries at https://github.com/nothings/stb.
18 
19 # Version history
20 	* Version 0.1.0 - 2015-03-22 - Works great on Mac.
21 	* Version 0.2.0 - 2015-09-17 - Removed the only dependency.
22 	* Version 0.3.0 - 2015-10-02 - Drop-in replacement for most of GLOG
23 	* Version 0.4.0 - 2015-10-07 - Single-file!
24 	* Version 0.5.0 - 2015-10-17 - Improved file logging
25 	* Version 0.6.0 - 2015-10-24 - Add stack traces
26 	* Version 0.7.0 - 2015-10-27 - Signals
27 	* Version 0.8.0 - 2015-10-30 - Color logging.
28 	* Version 0.9.0 - 2015-11-26 - ABORT_S and proper handling of FATAL
29 	* Version 1.0.0 - 2016-02-14 - ERROR_CONTEXT
30 	* Version 1.1.0 - 2016-02-19 - -v OFF, -v INFO etc
31 	* Version 1.1.1 - 2016-02-20 - textprintf vs strprintf
32 	* Version 1.1.2 - 2016-02-22 - Remove g_alsologtostderr
33 	* Version 1.1.3 - 2016-02-29 - ERROR_CONTEXT as linked list
34 	* Version 1.2.0 - 2016-03-19 - Add get_thread_name()
35 	* Version 1.2.1 - 2016-03-20 - Minor fixes
36 	* Version 1.2.2 - 2016-03-29 - Fix issues with set_fatal_handler throwing an exception
37 	* Version 1.2.3 - 2016-05-16 - Log current working directory in loguru::init().
38 	* Version 1.2.4 - 2016-05-18 - Custom replacement for -v in loguru::init() by bjoernpollex
39 	* Version 1.2.5 - 2016-05-18 - Add ability to print ERROR_CONTEXT of parent thread.
40 	* Version 1.2.6 - 2016-05-19 - Bug fix regarding VLOG verbosity argument lacking ().
41 	* Version 1.2.7 - 2016-05-23 - Fix PATH_MAX problem.
42 	* Version 1.2.8 - 2016-05-26 - Add shutdown() and remove_all_callbacks()
43 	* Version 1.2.9 - 2016-06-09 - Use a monotonic clock for uptime.
44 	* Version 1.3.0 - 2016-07-20 - Fix issues with callback flush/close not being called.
45 	* Version 1.3.1 - 2016-07-20 - Add LOGURU_UNSAFE_SIGNAL_HANDLER to toggle stacktrace on signals.
46 	* Version 1.3.2 - 2016-07-20 - Add loguru::arguments()
47 	* Version 1.4.0 - 2016-09-15 - Semantic versioning + add loguru::create_directories
48 	* Version 1.4.1 - 2016-09-29 - Customize formating with LOGURU_FILENAME_WIDTH
49 	* Version 1.5.0 - 2016-12-22 - LOGURU_USE_FMTLIB by kolis and LOGURU_WITH_FILEABS by scinart
50 	* Version 1.5.1 - 2017-08-08 - Terminal colors on Windows 10 thanks to looki
51 	* Version 1.6.0 - 2018-01-03 - Add LOGURU_RTTI and LOGURU_STACKTRACES settings
52 	* Version 1.7.0 - 2018-01-03 - Add ability to turn off the preamble with loguru::g_preamble
53 	* Version 1.7.1 - 2018-04-05 - Add function get_fatal_handler
54 
55 # Compiling
56 	Just include <loguru.hpp> where you want to use Loguru.
57 	Then, in one .cpp file:
58 		#define LOGURU_IMPLEMENTATION 1
59 		#include <loguru.hpp>
60 	Make sure you compile with -std=c++11 -lstdc++ -lpthread -ldl
61 
62 # Usage
63 	#include <loguru.hpp>
64 
65 	// Optional, but useful to time-stamp the start of the log.
66 	// Will also detect verbosity level on command line as -v.
67 	loguru::init(argc, argv);
68 
69 	// Put every log message in "everything.log":
70 	loguru::add_file("everything.log", loguru::Append, loguru::Verbosity_MAX);
71 
72 	// Only log INFO, WARNING, ERROR and FATAL to "latest_readable.log":
73 	loguru::add_file("latest_readable.log", loguru::Truncate, loguru::Verbosity_INFO);
74 
75 	// Only show most relevant things on stderr:
76 	loguru::g_stderr_verbosity = 1;
77 
78 	// Or just go with what Loguru suggests:
79 	char log_path[PATH_MAX];
80 	loguru::suggest_log_path("~/loguru/", log_path, sizeof(log_path));
81 	loguru::add_file(log_path, loguru::FileMode::Truncate, loguru::Verbosity_MAX);
82 
83 	LOG_SCOPE_F(INFO, "Will indent all log messages within this scope.");
84 	LOG_F(INFO, "I'm hungry for some %.3f!", 3.14159);
85 	LOG_F(2, "Will only show if verbosity is 2 or higher");
86 	VLOG_F(get_log_level(), "Use vlog for dynamic log level (integer in the range 0-9, inclusive)");
87 	LOG_IF_F(ERROR, badness, "Will only show if badness happens");
88 	auto fp = fopen(filename, "r");
89 	CHECK_F(fp != nullptr, "Failed to open file '%s'", filename);
90 	CHECK_GT_F(length, 0); // Will print the value of `length` on failure.
91 	CHECK_EQ_F(a, b, "You can also supply a custom message, like to print something: %d", a + b);
92 
93 	// Each function also comes with a version prefixed with D for Debug:
94 	DCHECK_F(expensive_check(x)); // Only checked #if LOGURU_DEBUG_CHECKS
95 	DLOG_F("Only written in debug-builds");
96 
97 	// Turn off writing to stderr:
98 	loguru::g_stderr_verbosity = loguru::Verbosity_OFF;
99 
100 	// Turn off writing err/warn in red:
101 	loguru::g_colorlogtostderr = false;
102 
103 	// Throw exceptions instead of aborting on CHECK fails:
104 	loguru::set_fatal_handler([](const loguru::Message& message){
105 		throw std::runtime_error(std::string(message.prefix) + message.message);
106 	});
107 
108 	If you prefer logging with streams:
109 
110 	#define LOGURU_WITH_STREAMS 1
111 	#include <loguru.hpp>
112 	...
113 	LOG_S(INFO) << "Look at my custom object: " << a.cross(b);
114 	CHECK_EQ_S(pi, 3.14) << "Maybe it is closer to " << M_PI;
115 
116 	Before including <loguru.hpp> you may optionally want to define the following to 1:
117 
118 	LOGURU_DEBUG_LOGGING (default 1 #if !NDEBUG, else 0):
119 		Enables debug versions of logging statements.
120 
121 	LOGURU_DEBUG_CHECKS (default 1 #if !NDEBUG, else 0):
122 		Enables debug versions of checks.
123 
124 	LOGURU_REDEFINE_ASSERT (default 0):
125 		Redefine "assert" call Loguru version (!NDEBUG only).
126 
127 	LOGURU_WITH_STREAMS (default 0):
128 		Add support for _S versions for all LOG and CHECK functions:
129 			LOG_S(INFO) << "My vec3: " << x.cross(y);
130 			CHECK_EQ_S(a, b) << "I expected a and b to be the same!";
131 		This is off by default to keep down compilation times.
132 
133 	LOGURU_REPLACE_GLOG (default 0):
134 		Make Loguru mimic GLOG as close as possible,
135 		including #defining LOG, CHECK, VLOG_IS_ON etc.
136 		LOGURU_REPLACE_GLOG implies LOGURU_WITH_STREAMS.
137 
138 	LOGURU_UNSAFE_SIGNAL_HANDLER (default 1):
139 		Make Loguru try to do unsafe but useful things,
140 		like printing a stack trace, when catching signals.
141 		This may lead to bad things like deadlocks in certain situations.
142 
143 	LOGURU_USE_FMTLIB (default 0):
144 		Use fmtlib formatting. See https://github.com/fmtlib/fmt
145 		This will make loguru.hpp depend on <fmt/format.h>
146 		You will need to link against `fmtlib` or use the `FMT_HEADER_ONLY` preprocessor definition.
147 		Feature by kolis (https://github.com/emilk/loguru/pull/22)
148 
149 	LOGURU_WITH_FILEABS (default 0):
150 		When LOGURU_WITH_FILEABS is defined, a check of file change will be performed on every call to file_log.
151 		If the file is moved, or inode changes, file is reopened using the same FileMode as is done by add_file.
152 		Such a scheme is useful if you have a daemon program that moves the log file every 24 hours and expects new file to be created.
153 		Feature by scinart (https://github.com/emilk/loguru/pull/23).
154 
155 	LOGURU_STACKTRACES (default 1 on supported platforms):
156 		Print stack traces on abort.
157 
158 	LOGURU_RTTI (try to detect automatically by default):
159 		Set to 0 if your platform does not support runtime type information (-fno-rtti).
160 
161 	You can also configure:
162 	loguru::g_flush_interval_ms:
163 		If set to zero Loguru will flush on every line (unbuffered mode).
164 		Else Loguru will flush outputs every g_flush_interval_ms milliseconds (buffered mode).
165 		The default is g_flush_interval_ms=0, i.e. unbuffered mode.
166 
167 # Notes:
168 	* Any arguments to CHECK:s are only evaluated once.
169 	* Any arguments to LOG functions or LOG_SCOPE are only evaluated iff the verbosity test passes.
170 	* Any arguments to LOG_IF functions are only evaluated if the test passes.
171 */
172 
173 // Disable all warnings from gcc/clang:
174 #if defined(__clang__)
175 	#pragma clang system_header
176 #elif defined(__GNUC__)
177 	#pragma GCC system_header
178 #endif
179 
180 #ifndef LOGURU_HAS_DECLARED_FORMAT_HEADER
181 #define LOGURU_HAS_DECLARED_FORMAT_HEADER
182 
183 #if defined(_MSC_VER)
184 #include <sal.h>	// Needed for _In_z_ etc annotations
185 #endif
186 
187 // ----------------------------------------------------------------------------
188 
189 #ifndef LOGURU_SCOPE_TEXT_SIZE
190 	// Maximum length of text that can be printed by a LOG_SCOPE.
191 	// This should be long enough to get most things, but short enough not to clutter the stack.
192 	#define LOGURU_SCOPE_TEXT_SIZE 196
193 #endif
194 
195 #ifndef LOGURU_FILENAME_WIDTH
196 	// Width of the column containing the file name
197 	#define LOGURU_FILENAME_WIDTH 23
198 #endif
199 
200 #ifndef LOGURU_THREADNAME_WIDTH
201 	// Width of the column containing the thread name
202 	#define LOGURU_THREADNAME_WIDTH 16
203 #endif
204 
205 #ifndef LOGURU_CATCH_SIGABRT
206 	// Should Loguru catch SIGABRT to print stack trace etc?
207 	#define LOGURU_CATCH_SIGABRT 1
208 #endif
209 
210 #ifndef LOGURU_REDEFINE_ASSERT
211 	#define LOGURU_REDEFINE_ASSERT 0
212 #endif
213 
214 #ifndef LOGURU_WITH_STREAMS
215 	#define LOGURU_WITH_STREAMS 0
216 #endif
217 
218 #ifndef LOGURU_REPLACE_GLOG
219 	#define LOGURU_REPLACE_GLOG 0
220 #endif
221 
222 #if LOGURU_REPLACE_GLOG
223 	#undef LOGURU_WITH_STREAMS
224 	#define LOGURU_WITH_STREAMS 1
225 #endif
226 
227 #ifndef LOGURU_UNSAFE_SIGNAL_HANDLER
228 	#define LOGURU_UNSAFE_SIGNAL_HANDLER 1
229 #endif
230 
231 #if LOGURU_IMPLEMENTATION
232 	#undef LOGURU_WITH_STREAMS
233 	#define LOGURU_WITH_STREAMS 1
234 #endif
235 
236 #ifndef LOGURU_USE_FMTLIB
237 	#define LOGURU_USE_FMTLIB 0
238 #endif
239 
240 #ifndef LOGURU_WITH_FILEABS
241 	#define LOGURU_WITH_FILEABS 0
242 #endif
243 
244 #ifndef LOGURU_RTTI
245 #if defined(__clang__)
246 	#if __has_feature(cxx_rtti)
247 		#define LOGURU_RTTI 1
248 	#endif
249 #elif defined(__GNUG__)
250 	#if defined(__GXX_RTTI)
251 		#define LOGURU_RTTI 1
252 	#endif
253 #elif defined(_MSC_VER)
254 	#if defined(_CPPRTTI)
255 		#define LOGURU_RTTI 1
256 	#endif
257 #endif
258 #endif
259 
260 // --------------------------------------------------------------------
261 // Utility macros
262 
263 #define LOGURU_CONCATENATE_IMPL(s1, s2) s1 ## s2
264 #define LOGURU_CONCATENATE(s1, s2) LOGURU_CONCATENATE_IMPL(s1, s2)
265 
266 #ifdef __COUNTER__
267 #   define LOGURU_ANONYMOUS_VARIABLE(str) LOGURU_CONCATENATE(str, __COUNTER__)
268 #else
269 #   define LOGURU_ANONYMOUS_VARIABLE(str) LOGURU_CONCATENATE(str, __LINE__)
270 #endif
271 
272 #if defined(__clang__) || defined(__GNUC__)
273 	// Helper macro for declaring functions as having similar signature to printf.
274 	// This allows the compiler to catch format errors at compile-time.
275 	#define LOGURU_PRINTF_LIKE(fmtarg, firstvararg) __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
276 	#define LOGURU_FORMAT_STRING_TYPE const char*
277 #elif defined(_MSC_VER)
278 	#define LOGURU_PRINTF_LIKE(fmtarg, firstvararg)
279 	#define LOGURU_FORMAT_STRING_TYPE _In_z_ _Printf_format_string_ const char*
280 #else
281 	#define LOGURU_PRINTF_LIKE(fmtarg, firstvararg)
282 	#define LOGURU_FORMAT_STRING_TYPE const char*
283 #endif
284 
285 // Used to mark log_and_abort for the benefit of the static analyzer and optimizer.
286 #if defined(_MSC_VER)
287 #define LOGURU_NORETURN __declspec(noreturn)
288 #else
289 #define LOGURU_NORETURN __attribute__((noreturn))
290 #endif
291 
292 #if defined(_MSC_VER)
293 #define LOGURU_PREDICT_FALSE(x) (x)
294 #define LOGURU_PREDICT_TRUE(x)  (x)
295 #else
296 #define LOGURU_PREDICT_FALSE(x) (__builtin_expect(x,     0))
297 #define LOGURU_PREDICT_TRUE(x)  (__builtin_expect(!!(x), 1))
298 #endif
299 
300 #if LOGURU_USE_FMTLIB
301 	#include <fmt/format.h>
302 #endif
303 
304 // --------------------------------------------------------------------
305 
306 namespace loguru
307 {
308 	// Simple RAII ownership of a char*.
309 	class Text
310 	{
311 	public:
Text(char * owned_str)312 		explicit Text(char* owned_str) : _str(owned_str) {}
313 		~Text();
Text(Text && t)314 		Text(Text&& t)
315 		{
316 			_str = t._str;
317 			t._str = nullptr;
318 		}
319 		Text(Text& t) = delete;
320 		Text& operator=(Text& t) = delete;
321 		void operator=(Text&& t) = delete;
322 
c_str() const323 		const char* c_str() const { return _str; }
empty() const324 		bool empty() const { return _str == nullptr || *_str == '\0'; }
325 
release()326 		char* release()
327 		{
328 			auto result = _str;
329 			_str = nullptr;
330 			return result;
331 		}
332 
333 	private:
334 		char* _str;
335 	};
336 
337 	// Like printf, but returns the formated text.
338 	Text textprintf(LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(1, 2);
339 
340 	// Overloaded for variadic template matching.
341 	Text textprintf();
342 
343 	using Verbosity = int;
344 
345 #undef FATAL
346 #undef ERROR
347 #undef WARNING
348 #undef INFO
349 #undef MAX
350 
351 	enum NamedVerbosity : Verbosity
352 	{
353 		// You may use Verbosity_OFF on g_stderr_verbosity, but for nothing else!
354 		Verbosity_OFF     = -9, // Never do LOG_F(OFF)
355 
356 		// Prefer to use ABORT_F or ABORT_S over LOG_F(FATAL) or LOG_S(FATAL).
357 		Verbosity_FATAL   = -3,
358 		Verbosity_ERROR   = -2,
359 		Verbosity_WARNING = -1,
360 
361 		// Normal messages. By default written to stderr.
362 		Verbosity_INFO    =  0,
363 
364 		// Same as Verbosity_INFO in every way.
365 		Verbosity_0       =  0,
366 
367 		// Verbosity levels 1-9 are generally not written to stderr, but are written to file.
368 		Verbosity_1       = +1,
369 		Verbosity_2       = +2,
370 		Verbosity_3       = +3,
371 		Verbosity_4       = +4,
372 		Verbosity_5       = +5,
373 		Verbosity_6       = +6,
374 		Verbosity_7       = +7,
375 		Verbosity_8       = +8,
376 		Verbosity_9       = +9,
377 
378 		// Don not use higher verbosity levels, as that will make grepping log files harder.
379 		Verbosity_MAX     = +9,
380 	};
381 
382 	struct Message
383 	{
384 		// You would generally print a Message by just concating the buffers without spacing.
385 		// Optionally, ignore preamble and indentation.
386 		Verbosity   verbosity;   // Already part of preamble
387 		const char* filename;    // Already part of preamble
388 		unsigned    line;        // Already part of preamble
389 		const char* preamble;    // Date, time, uptime, thread, file:line, verbosity.
390 		const char* indentation; // Just a bunch of spacing.
391 		const char* prefix;      // Assertion failure info goes here (or "").
392 		const char* message;     // User message goes here.
393 	};
394 
395 	/* Everything with a verbosity equal or greater than g_stderr_verbosity will be
396 	written to stderr. You can set this in code or via the -v argument.
397 	Set to logurur::Verbosity_OFF to write nothing to stderr.
398 	Default is 0, i.e. only log ERROR, WARNING and INFO are written to stderr.
399 	*/
400 	extern Verbosity g_stderr_verbosity;
401 	extern bool      g_colorlogtostderr; // True by default.
402 	extern unsigned  g_flush_interval_ms; // 0 (unbuffered) by default.
403 	extern bool      g_preamble; // Prefix each log line with date, time etc? True by default.
404 
405 	// Turn off individual parts of the preamble
406 	extern bool      g_preamble_date; // The date field
407 	extern bool      g_preamble_time; // The time of the current day
408 	extern bool      g_preamble_uptime; // The time since init call
409 	extern bool      g_preamble_thread; // The logging thread
410 	extern bool      g_preamble_file; // The file from which the log originates from
411 	extern bool      g_preamble_verbose; // The verbosity field
412 	extern bool      g_preamble_pipe; // The pipe symbol right before the message
413 
414 	// May not throw!
415 	typedef void (*log_handler_t)(void* user_data, const Message& message);
416 	typedef void (*close_handler_t)(void* user_data);
417 	typedef void (*flush_handler_t)(void* user_data);
418 
419 	// May throw if that's how you'd like to handle your errors.
420 	typedef void (*fatal_handler_t)(const Message& message);
421 
422 	/*  Should be called from the main thread.
423 		You don't *need* to call this, but if you do you get:
424 			* Signal handlers installed
425 			* Program arguments logged
426 			* Working dir logged
427 			* Optional -v verbosity flag parsed
428 			* Main thread name set to "main thread"
429 			* Explanation of the preamble (date, threanmae etc) logged
430 
431 		loguru::init() will look for arguments meant for loguru and remove them.
432 		Arguments meant for loguru are:
433 			-v n   Set loguru::g_stderr_verbosity level. Examples:
434 				-v 3        Show verbosity level 3 and lower.
435 				-v 0        Only show INFO, WARNING, ERROR, FATAL (default).
436 				-v INFO     Only show INFO, WARNING, ERROR, FATAL (default).
437 				-v WARNING  Only show WARNING, ERROR, FATAL.
438 				-v ERROR    Only show ERROR, FATAL.
439 				-v FATAL    Only show FATAL.
440 				-v OFF      Turn off logging to stderr.
441 
442 		Tip: You can set g_stderr_verbosity before calling loguru::init.
443 		That way you can set the default but have the user override it with the -v flag.
444 		Note that -v does not affect file logging (see loguru::add_file).
445 
446 		You can use something else instead of "-v" via verbosity_flag.
447 		You can also set verbosity_flag to nullptr.
448 	*/
449 	void init(int& argc, char* argv[], const char* verbosity_flag = "-v");
450 
451 	// Will call remove_all_callbacks(). After calling this, logging will still go to stderr.
452 	// You generally don't need to call this.
453 	void shutdown();
454 
455 	// What ~ will be replaced with, e.g. "/home/your_user_name/"
456 	const char* home_dir();
457 
458 	/* Returns the name of the app as given in argv[0] but without leading path.
459 	   That is, if argv[0] is "../foo/app" this will return "app".
460 	*/
461 	const char* argv0_filename();
462 
463 	// Returns all arguments given to loguru::init(), but escaped with a single space as separator.
464 	const char* arguments();
465 
466 	// Returns the path to the current working dir when loguru::init() was called.
467 	const char* current_dir();
468 
469 	// Returns the part of the path after the last / or \ (if any).
470 	const char* filename(const char* path);
471 
472 	// e.g. "foo/bar/baz.ext" will create the directories "foo/" and "foo/bar/"
473 	bool create_directories(const char* file_path_const);
474 
475 	// Writes date and time with millisecond precision, e.g. "20151017_161503.123"
476 	void write_date_time(char* buff, unsigned buff_size);
477 
478 	// Helper: thread-safe version strerror
479 	Text errno_as_text();
480 
481 	/* Given a prefix of e.g. "~/loguru/" this might return
482 	   "/home/your_username/loguru/app_name/20151017_161503.123.log"
483 
484 	   where "app_name" is a sanitized version of argv[0].
485 	*/
486 	void suggest_log_path(const char* prefix, char* buff, unsigned buff_size);
487 
488 	enum FileMode { Truncate, Append };
489 
490 	/*  Will log to a file at the given path.
491 		Any logging message with a verbosity lower or equal to
492 		the given verbosity will be included.
493 		The function will create all directories in 'path' if needed.
494 		If path starts with a ~, it will be replaced with loguru::home_dir()
495 		To stop the file logging, just call loguru::remove_callback(path) with the same path.
496 	*/
497 	bool add_file(const char* path, FileMode mode, Verbosity verbosity);
498 
499 	/*  Will be called right before abort().
500 		You can for instance use this to print custom error messages, or throw an exception.
501 		Feel free to call LOG:ing function from this, but not FATAL ones! */
502 	void set_fatal_handler(fatal_handler_t handler);
503 
504 	// Get the current fatal handler, if any. Default value is nullptr.
505 	fatal_handler_t get_fatal_handler();
506 
507 	/*  Will be called on each log messages with a verbosity less or equal to the given one.
508 		Useful for displaying messages on-screen in a game, for example.
509 		The given on_close is also expected to flush (if desired).
510 	*/
511 	void add_callback(
512 		const char*     id,
513 		log_handler_t   callback,
514 		void*           user_data,
515 		Verbosity       verbosity,
516 		close_handler_t on_close = nullptr,
517 		flush_handler_t on_flush = nullptr);
518 
519 	// Returns true iff the callback was found (and removed).
520 	bool remove_callback(const char* id);
521 
522 	// Shut down all file logging and any other callback hooks installed.
523 	void remove_all_callbacks();
524 
525 	// Returns the maximum of g_stderr_verbosity and all file/custom outputs.
526 	Verbosity current_verbosity_cutoff();
527 
528 #if LOGURU_USE_FMTLIB
529 	// Actual logging function. Use the LOG macro instead of calling this directly.
530 	void log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, fmt::ArgList args);
531 	FMT_VARIADIC(void, log, Verbosity, const char*, unsigned, LOGURU_FORMAT_STRING_TYPE)
532 
533 	// Log without any preamble or indentation.
534 	void raw_log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, fmt::ArgList args);
535 	FMT_VARIADIC(void, raw_log, Verbosity, const char*, unsigned, LOGURU_FORMAT_STRING_TYPE)
536 #else // LOGURU_USE_FMTLIB?
537 	// Actual logging function. Use the LOG macro instead of calling this directly.
538 	void log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(4, 5);
539 
540 	// Log without any preamble or indentation.
541 	void raw_log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(4, 5);
542 #endif // !LOGURU_USE_FMTLIB
543 
544 	// Helper class for LOG_SCOPE_F
545 	class LogScopeRAII
546 	{
547 	public:
LogScopeRAII()548 		LogScopeRAII() : _file(nullptr) {} // No logging
549 		LogScopeRAII(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(5, 6);
550 		~LogScopeRAII();
551 
552 		LogScopeRAII(LogScopeRAII&& other) = default;
553 
554 	private:
555 		LogScopeRAII(const LogScopeRAII&) = delete;
556 		LogScopeRAII& operator=(const LogScopeRAII&) = delete;
557 		void operator=(LogScopeRAII&&) = delete;
558 
559 		Verbosity   _verbosity;
560 		const char* _file; // Set to null if we are disabled due to verbosity
561 		unsigned    _line;
562 		bool        _indent_stderr; // Did we?
563 		long long   _start_time_ns;
564 		char        _name[LOGURU_SCOPE_TEXT_SIZE];
565 	};
566 
567 	// Marked as 'noreturn' for the benefit of the static analyzer and optimizer.
568 	// stack_trace_skip is the number of extrace stack frames to skip above log_and_abort.
569 	LOGURU_NORETURN void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(5, 6);
570 	LOGURU_NORETURN void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line);
571 
572 	// Flush output to stderr and files.
573 	// If g_flush_interval_ms is set to non-zero, this will be called automatically this often.
574 	// If not set, you do not need to call this at all.
575 	void flush();
576 
format_value(const T &)577 	template<class T> inline Text format_value(const T&)                    { return textprintf("N/A");     }
format_value(const char & v)578 	template<>        inline Text format_value(const char& v)               { return textprintf("%c",   v); }
format_value(const int & v)579 	template<>        inline Text format_value(const int& v)                { return textprintf("%d",   v); }
format_value(const unsigned int & v)580 	template<>        inline Text format_value(const unsigned int& v)       { return textprintf("%u",   v); }
format_value(const long & v)581 	template<>        inline Text format_value(const long& v)               { return textprintf("%lu",  v); }
format_value(const unsigned long & v)582 	template<>        inline Text format_value(const unsigned long& v)      { return textprintf("%ld",  v); }
format_value(const long long & v)583 	template<>        inline Text format_value(const long long& v)          { return textprintf("%llu", v); }
format_value(const unsigned long long & v)584 	template<>        inline Text format_value(const unsigned long long& v) { return textprintf("%lld", v); }
format_value(const float & v)585 	template<>        inline Text format_value(const float& v)              { return textprintf("%f",   v); }
format_value(const double & v)586 	template<>        inline Text format_value(const double& v)             { return textprintf("%f",   v); }
587 
588 	/* Thread names can be set for the benefit of readable logs.
589 	   If you do not set the thread name, a hex id will be shown instead.
590 	   These thread names may or may not be the same as the system thread names,
591 	   depending on the system.
592 	   Try to limit the thread name to 15 characters or less. */
593 	void set_thread_name(const char* name);
594 
595 	/* Returns the thread name for this thread.
596 	   On OSX this will return the system thread name (settable from both within and without Loguru).
597 	   On other systems it will return whatever you set in set_thread_name();
598 	   If no thread name is set, this will return a hexadecimal thread id.
599 	   length should be the number of bytes available in the buffer.
600 	   17 is a good number for length.
601 	   right_align_hext_id means any hexadecimal thread id will be written to the end of buffer.
602 	*/
603 	void get_thread_name(char* buffer, unsigned long long length, bool right_align_hext_id);
604 
605 	/* Generates a readable stacktrace as a string.
606 	   'skip' specifies how many stack frames to skip.
607 	   For instance, the default skip (1) means:
608 	   don't include the call to loguru::stacktrace in the stack trace. */
609 	Text stacktrace(int skip = 1);
610 
611 	/*  Add a string to be replaced with something else in the stack output.
612 
613 		For instance, instead of having a stack trace look like this:
614 			0x41f541 some_function(std::basic_ofstream<char, std::char_traits<char> >&)
615 		You can clean it up with:
616 			auto verbose_type_name = loguru::demangle(typeid(std::ofstream).name());
617 			loguru::add_stack_cleanup(verbose_type_name.c_str(); "std::ofstream");
618 		So the next time you will instead see:
619 			0x41f541 some_function(std::ofstream&)
620 
621 		`replace_with_this` must be shorter than `find_this`.
622 	*/
623 	void add_stack_cleanup(const char* find_this, const char* replace_with_this);
624 
625 	// Example: demangle(typeid(std::ofstream).name()) -> "std::basic_ofstream<char, std::char_traits<char> >"
626 	Text demangle(const char* name);
627 
628 	// ------------------------------------------------------------------------
629 	/*
630 	Not all terminals support colors, but if they do, and g_colorlogtostderr
631 	is set, Loguru will write them to stderr to make errors in red, etc.
632 
633 	You also have the option to manually use them, via the function below.
634 
635 	Note, however, that if you do, the color codes could end up in your logfile!
636 
637 	This means if you intend to use them functions you should either:
638 		* Use them on the stderr/stdout directly (bypass Loguru).
639 		* Don't add file outputs to Loguru.
640 		* Expect some \e[1m things in your logfile.
641 
642 	Usage:
643 		printf("%sRed%sGreen%sBold green%sClear again\n",
644 			   loguru::terminal_red(), loguru::terminal_green(),
645 			   loguru::terminal_bold(), loguru::terminal_reset());
646 
647 	If the terminal at hand does not support colors the above output
648 	will just not have funky \e[1m things showing.
649 	*/
650 
651 	// Do the output terminal support colors?
652 	bool terminal_has_color();
653 
654 	// Colors
655 	const char* terminal_black();
656 	const char* terminal_red();
657 	const char* terminal_green();
658 	const char* terminal_yellow();
659 	const char* terminal_blue();
660 	const char* terminal_purple();
661 	const char* terminal_cyan();
662 	const char* terminal_light_gray();
663 	const char* terminal_light_red();
664 	const char* terminal_white();
665 
666 	// Formating
667 	const char* terminal_bold();
668 	const char* terminal_underline();
669 
670 	// You should end each line with this!
671 	const char* terminal_reset();
672 
673 	// --------------------------------------------------------------------
674 	// Error context related:
675 
676 	struct StringStream;
677 
678 	// Use this in your EcEntryBase::print_value overload.
679 	void stream_print(StringStream& out_string_stream, const char* text);
680 
681 	class EcEntryBase
682 	{
683 	public:
684 		EcEntryBase(const char* file, unsigned line, const char* descr);
685 		~EcEntryBase();
686 		EcEntryBase(const EcEntryBase&) = delete;
687 		EcEntryBase(EcEntryBase&&) = delete;
688 		EcEntryBase& operator=(const EcEntryBase&) = delete;
689 		EcEntryBase& operator=(EcEntryBase&&) = delete;
690 
691 		virtual void print_value(StringStream& out_string_stream) const = 0;
692 
previous() const693 		EcEntryBase* previous() const { return _previous; }
694 
695 	// private:
696 		const char*  _file;
697 		unsigned     _line;
698 		const char*  _descr;
699 		EcEntryBase* _previous;
700 	};
701 
702 	template<typename T>
703 	class EcEntryData : public EcEntryBase
704 	{
705 	public:
706 		using Printer = Text(*)(T data);
707 
EcEntryData(const char * file,unsigned line,const char * descr,T data,Printer && printer)708 		EcEntryData(const char* file, unsigned line, const char* descr, T data, Printer&& printer)
709 			: EcEntryBase(file, line, descr), _data(data), _printer(printer) {}
710 
print_value(StringStream & out_string_stream) const711 		virtual void print_value(StringStream& out_string_stream) const override
712 		{
713 			const auto str = _printer(_data);
714 			stream_print(out_string_stream, str.c_str());
715 		}
716 
717 	private:
718 		T   _data;
719 		Printer _printer;
720 	};
721 
722 	// template<typename Printer>
723 	// class EcEntryLambda : public EcEntryBase
724 	// {
725 	// public:
726 	// 	EcEntryLambda(const char* file, unsigned line, const char* descr, Printer&& printer)
727 	// 		: EcEntryBase(file, line, descr), _printer(std::move(printer)) {}
728 
729 	// 	virtual void print_value(StringStream& out_string_stream) const override
730 	// 	{
731 	// 		const auto str = _printer();
732 	// 		stream_print(out_string_stream, str.c_str());
733 	// 	}
734 
735 	// private:
736 	// 	Printer _printer;
737 	// };
738 
739 	// template<typename Printer>
740 	// EcEntryLambda<Printer> make_ec_entry_lambda(const char* file, unsigned line, const char* descr, Printer&& printer)
741 	// {
742 	// 	return {file, line, descr, std::move(printer)};
743 	// }
744 
745 	template <class T>
746 	struct decay_char_array { using type = T; };
747 
748 	template <unsigned long long  N>
749 	struct decay_char_array<const char(&)[N]> { using type = const char*; };
750 
751 	template <class T>
752 	struct make_const_ptr { using type = T; };
753 
754 	template <class T>
755 	struct make_const_ptr<T*> { using type = const T*; };
756 
757 	template <class T>
758 	struct make_ec_type { using type = typename make_const_ptr<typename decay_char_array<T>::type>::type; };
759 
760 	/* 	A stack trace gives you the names of the function at the point of a crash.
761 		With ERROR_CONTEXT, you can also get the values of select local variables.
762 		Usage:
763 
764 		void process_customers(const std::string& filename)
765 		{
766 			ERROR_CONTEXT("Processing file", filename.c_str());
767 			for (int customer_index : ...)
768 			{
769 				ERROR_CONTEXT("Customer index", customer_index);
770 				...
771 			}
772 		}
773 
774 		The context is in effect during the scope of the ERROR_CONTEXT.
775 		Use loguru::get_error_context() to get the contents of the active error contexts.
776 
777 		Example result:
778 
779 		------------------------------------------------
780 		[ErrorContext]                main.cpp:416   Processing file:    "customers.json"
781 		[ErrorContext]                main.cpp:417   Customer index:     42
782 		------------------------------------------------
783 
784 		Error contexts are printed automatically on crashes, and only on crashes.
785 		This makes them much faster than logging the value of a variable.
786 	*/
787 	#define ERROR_CONTEXT(descr, data)                                             \
788 		const loguru::EcEntryData<loguru::make_ec_type<decltype(data)>::type>      \
789 			LOGURU_ANONYMOUS_VARIABLE(error_context_scope_)(                       \
790 				__FILE__, __LINE__, descr, data,                                   \
791 				static_cast<loguru::EcEntryData<loguru::make_ec_type<decltype(data)>::type>::Printer>(loguru::ec_to_text) ) // For better error messages
792 
793 /*
794 	#define ERROR_CONTEXT(descr, data)                                 \
795 		const auto LOGURU_ANONYMOUS_VARIABLE(error_context_scope_)(    \
796 			loguru::make_ec_entry_lambda(__FILE__, __LINE__, descr,    \
797 				[=](){ return loguru::ec_to_text(data); }))
798 */
799 
800 	using EcHandle = const EcEntryBase*;
801 
802 	/*
803 		Get a light-weight handle to the error context stack on this thread.
804 		The handle is valid as long as the current thread has no changes to its error context stack.
805 		You can pass the handle to loguru::get_error_context on another thread.
806 		This can be very useful for when you have a parent thread spawning several working threads,
807 		and you want the error context of the parent thread to get printed (too) when there is an
808 		error on the child thread. You can accomplish this thusly:
809 
810 		void foo(const char* parameter)
811 		{
812 			ERROR_CONTEXT("parameter", parameter)
813 			const auto parent_ec_handle = loguru::get_thread_ec_handle();
814 
815 			std::thread([=]{
816 				loguru::set_thread_name("child thread");
817 				ERROR_CONTEXT("parent context", parent_ec_handle);
818 				dangerous_code();
819 			}.join();
820 		}
821 
822 	*/
823 	EcHandle get_thread_ec_handle();
824 
825 	// Get a string describing the current stack of error context. Empty string if there is none.
826 	Text get_error_context();
827 
828 	// Get a string describing the error context of the given thread handle.
829 	Text get_error_context_for(EcHandle ec_handle);
830 
831 	// ------------------------------------------------------------------------
832 
833 	Text ec_to_text(const char* data);
834 	Text ec_to_text(char data);
835 	Text ec_to_text(int data);
836 	Text ec_to_text(unsigned int data);
837 	Text ec_to_text(long data);
838 	Text ec_to_text(unsigned long data);
839 	Text ec_to_text(long long data);
840 	Text ec_to_text(unsigned long long data);
841 	Text ec_to_text(float data);
842 	Text ec_to_text(double data);
843 	Text ec_to_text(long double data);
844 	Text ec_to_text(EcHandle);
845 
846 	/*
847 	You can add ERROR_CONTEXT support for your own types by overloading ec_to_text. Here's how:
848 
849 	some.hpp:
850 		namespace loguru {
851 			Text ec_to_text(MySmallType data)
852 			Text ec_to_text(const MyBigType* data)
853 		} // namespace loguru
854 
855 	some.cpp:
856 		namespace loguru {
857 			Text ec_to_text(MySmallType small_value)
858 			{
859 				// Called only when needed, i.e. on a crash.
860 				std::string str = small_value.as_string(); // Format 'small_value' here somehow.
861 				return Text{strdup(str.c_str())};
862 			}
863 
864 			Text ec_to_text(const MyBigType* big_value)
865 			{
866 				// Called only when needed, i.e. on a crash.
867 				std::string str = big_value->as_string(); // Format 'big_value' here somehow.
868 				return Text{strdup(str.c_str())};
869 			}
870 		} // namespace loguru
871 
872 	Any file that include some.hpp:
873 		void foo(MySmallType small, const MyBigType& big)
874 		{
875 			ERROR_CONTEXT("Small", small); // Copy ´small` by value.
876 			ERROR_CONTEXT("Big",   &big);  // `big` should not change during this scope!
877 			....
878 		}
879 	*/
880 } // namespace loguru
881 
882 // --------------------------------------------------------------------
883 // Logging macros
884 
885 // LOG_F(2, "Only logged if verbosity is 2 or higher: %d", some_number);
886 #define VLOG_F(verbosity, ...)                                                                     \
887 	((verbosity) > loguru::current_verbosity_cutoff()) ? (void)0                                   \
888 									  : loguru::log(verbosity, __FILE__, __LINE__, __VA_ARGS__)
889 
890 // LOG_F(INFO, "Foo: %d", some_number);
891 #define LOG_F(verbosity_name, ...) VLOG_F(loguru::Verbosity_ ## verbosity_name, __VA_ARGS__)
892 
893 #define VLOG_IF_F(verbosity, cond, ...)                                                            \
894 	((verbosity) > loguru::current_verbosity_cutoff() || (cond) == false)                          \
895 		? (void)0                                                                                  \
896 		: loguru::log(verbosity, __FILE__, __LINE__, __VA_ARGS__)
897 
898 #define LOG_IF_F(verbosity_name, cond, ...)                                                        \
899 	VLOG_IF_F(loguru::Verbosity_ ## verbosity_name, cond, __VA_ARGS__)
900 
901 #define VLOG_SCOPE_F(verbosity, ...)                                                               \
902 	loguru::LogScopeRAII LOGURU_ANONYMOUS_VARIABLE(error_context_RAII_) =                          \
903 	((verbosity) > loguru::current_verbosity_cutoff()) ? loguru::LogScopeRAII() :                  \
904 	loguru::LogScopeRAII(verbosity, __FILE__, __LINE__, __VA_ARGS__)
905 
906 // Raw logging - no preamble, no indentation. Slightly faster than full logging.
907 #define RAW_VLOG_F(verbosity, ...)                                                                 \
908 	((verbosity) > loguru::current_verbosity_cutoff()) ? (void)0                                   \
909 									  : loguru::raw_log(verbosity, __FILE__, __LINE__, __VA_ARGS__)
910 
911 #define RAW_LOG_F(verbosity_name, ...) RAW_VLOG_F(loguru::Verbosity_ ## verbosity_name, __VA_ARGS__)
912 
913 // Use to book-end a scope. Affects logging on all threads.
914 #define LOG_SCOPE_F(verbosity_name, ...)                                                           \
915 	VLOG_SCOPE_F(loguru::Verbosity_ ## verbosity_name, __VA_ARGS__)
916 
917 #define LOG_SCOPE_FUNCTION(verbosity_name) LOG_SCOPE_F(verbosity_name, __func__)
918 
919 // -----------------------------------------------
920 // ABORT_F macro. Usage:  ABORT_F("Cause of error: %s", error_str);
921 
922 // Message is optional
923 #define ABORT_F(...) loguru::log_and_abort(0, "ABORT: ", __FILE__, __LINE__, __VA_ARGS__)
924 
925 // --------------------------------------------------------------------
926 // CHECK_F macros:
927 
928 #define CHECK_WITH_INFO_F(test, info, ...)                                                         \
929 	LOGURU_PREDICT_TRUE((test) == true) ? (void)0 : loguru::log_and_abort(0, "CHECK FAILED:  " info "  ", __FILE__,      \
930 													   __LINE__, ##__VA_ARGS__)
931 
932 /* Checked at runtime too. Will print error, then call fatal_handler (if any), then 'abort'.
933    Note that the test must be boolean.
934    CHECK_F(ptr); will not compile, but CHECK_F(ptr != nullptr); will. */
935 #define CHECK_F(test, ...) CHECK_WITH_INFO_F(test, #test, ##__VA_ARGS__)
936 
937 #define CHECK_NOTNULL_F(x, ...) CHECK_WITH_INFO_F((x) != nullptr, #x " != nullptr", ##__VA_ARGS__)
938 
939 #define CHECK_OP_F(expr_left, expr_right, op, ...)                                                 \
940 	do                                                                                             \
941 	{                                                                                              \
942 		auto val_left = expr_left;                                                                 \
943 		auto val_right = expr_right;                                                               \
944 		if (! LOGURU_PREDICT_TRUE(val_left op val_right))                                          \
945 		{                                                                                          \
946 			auto str_left = loguru::format_value(val_left);                                        \
947 			auto str_right = loguru::format_value(val_right);                                      \
948 			auto fail_info = loguru::textprintf("CHECK FAILED:  %s %s %s  (%s %s %s)  ",           \
949 				#expr_left, #op, #expr_right, str_left.c_str(), #op, str_right.c_str());           \
950 			auto user_msg = loguru::textprintf(__VA_ARGS__);                                       \
951 			loguru::log_and_abort(0, fail_info.c_str(), __FILE__, __LINE__,                        \
952 			                      "%s", user_msg.c_str());                                         \
953 		}                                                                                          \
954 	} while (false)
955 
956 #ifndef LOGURU_DEBUG_LOGGING
957 	#ifndef NDEBUG
958 		#define LOGURU_DEBUG_LOGGING 1
959 	#else
960 		#define LOGURU_DEBUG_LOGGING 0
961 	#endif
962 #endif
963 
964 #if LOGURU_DEBUG_LOGGING
965 	// Debug logging enabled:
966 	#define DLOG_F(verbosity_name, ...)     LOG_F(verbosity_name, __VA_ARGS__)
967 	#define DVLOG_F(verbosity, ...)         VLOG_F(verbosity, __VA_ARGS__)
968 	#define DLOG_IF_F(verbosity_name, ...)  LOG_IF_F(verbosity_name, __VA_ARGS__)
969 	#define DVLOG_IF_F(verbosity, ...)      VLOG_IF_F(verbosity, __VA_ARGS__)
970 	#define DRAW_LOG_F(verbosity_name, ...) RAW_LOG_F(verbosity_name, __VA_ARGS__)
971 	#define DRAW_VLOG_F(verbosity, ...)     RAW_VLOG_F(verbosity, __VA_ARGS__)
972 #else
973 	// Debug logging disabled:
974 	#define DLOG_F(verbosity_name, ...)
975 	#define DVLOG_F(verbosity, ...)
976 	#define DLOG_IF_F(verbosity_name, ...)
977 	#define DVLOG_IF_F(verbosity, ...)
978 	#define DRAW_LOG_F(verbosity_name, ...)
979 	#define DRAW_VLOG_F(verbosity, ...)
980 #endif
981 
982 #define CHECK_EQ_F(a, b, ...) CHECK_OP_F(a, b, ==, ##__VA_ARGS__)
983 #define CHECK_NE_F(a, b, ...) CHECK_OP_F(a, b, !=, ##__VA_ARGS__)
984 #define CHECK_LT_F(a, b, ...) CHECK_OP_F(a, b, < , ##__VA_ARGS__)
985 #define CHECK_GT_F(a, b, ...) CHECK_OP_F(a, b, > , ##__VA_ARGS__)
986 #define CHECK_LE_F(a, b, ...) CHECK_OP_F(a, b, <=, ##__VA_ARGS__)
987 #define CHECK_GE_F(a, b, ...) CHECK_OP_F(a, b, >=, ##__VA_ARGS__)
988 
989 #ifndef LOGURU_DEBUG_CHECKS
990 	#ifndef NDEBUG
991 		#define LOGURU_DEBUG_CHECKS 1
992 	#else
993 		#define LOGURU_DEBUG_CHECKS 0
994 	#endif
995 #endif
996 
997 #if LOGURU_DEBUG_CHECKS
998 	// Debug checks enabled:
999 	#define DCHECK_F(test, ...)             CHECK_F(test, ##__VA_ARGS__)
1000 	#define DCHECK_NOTNULL_F(x, ...)        CHECK_NOTNULL_F(x, ##__VA_ARGS__)
1001 	#define DCHECK_EQ_F(a, b, ...)          CHECK_EQ_F(a, b, ##__VA_ARGS__)
1002 	#define DCHECK_NE_F(a, b, ...)          CHECK_NE_F(a, b, ##__VA_ARGS__)
1003 	#define DCHECK_LT_F(a, b, ...)          CHECK_LT_F(a, b, ##__VA_ARGS__)
1004 	#define DCHECK_LE_F(a, b, ...)          CHECK_LE_F(a, b, ##__VA_ARGS__)
1005 	#define DCHECK_GT_F(a, b, ...)          CHECK_GT_F(a, b, ##__VA_ARGS__)
1006 	#define DCHECK_GE_F(a, b, ...)          CHECK_GE_F(a, b, ##__VA_ARGS__)
1007 #else
1008 	// Debug checks disabled:
1009 	#define DCHECK_F(test, ...)
1010 	#define DCHECK_NOTNULL_F(x, ...)
1011 	#define DCHECK_EQ_F(a, b, ...)
1012 	#define DCHECK_NE_F(a, b, ...)
1013 	#define DCHECK_LT_F(a, b, ...)
1014 	#define DCHECK_LE_F(a, b, ...)
1015 	#define DCHECK_GT_F(a, b, ...)
1016 	#define DCHECK_GE_F(a, b, ...)
1017 #endif // NDEBUG
1018 
1019 
1020 #ifdef LOGURU_REDEFINE_ASSERT
1021 	#undef assert
1022 	#ifndef NDEBUG
1023 		// Debug:
1024 		#define assert(test) CHECK_WITH_INFO_F(!!(test), #test) // HACK
1025 	#else
1026 		#define assert(test)
1027 	#endif
1028 #endif // LOGURU_REDEFINE_ASSERT
1029 
1030 #endif // LOGURU_HAS_DECLARED_FORMAT_HEADER
1031 
1032 // ----------------------------------------------------------------------------
1033 // .dP"Y8 888888 88""Yb 888888    db    8b    d8 .dP"Y8
1034 // `Ybo."   88   88__dP 88__     dPYb   88b  d88 `Ybo."
1035 // o.`Y8b   88   88"Yb  88""    dP__Yb  88YbdP88 o.`Y8b
1036 // 8bodP'   88   88  Yb 888888 dP""""Yb 88 YY 88 8bodP'
1037 
1038 #if LOGURU_WITH_STREAMS
1039 #ifndef LOGURU_HAS_DECLARED_STREAMS_HEADER
1040 #define LOGURU_HAS_DECLARED_STREAMS_HEADER
1041 
1042 /* This file extends loguru to enable std::stream-style logging, a la Glog.
1043    It's an optional feature behind the LOGURU_WITH_STREAMS settings
1044    because including it everywhere will slow down compilation times.
1045 */
1046 
1047 #include <cstdarg>
1048 #include <sstream> // Adds about 38 kLoC on clang.
1049 #include <string>
1050 
1051 namespace loguru
1052 {
1053 	// Like sprintf, but returns the formated text.
1054 	std::string strprintf(LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(1, 2);
1055 
1056 	// Like vsprintf, but returns the formated text.
1057 	std::string vstrprintf(LOGURU_FORMAT_STRING_TYPE format, va_list) LOGURU_PRINTF_LIKE(1, 0);
1058 
1059 	class StreamLogger
1060 	{
1061 	public:
StreamLogger(Verbosity verbosity,const char * file,unsigned line)1062 		StreamLogger(Verbosity verbosity, const char* file, unsigned line) : _verbosity(verbosity), _file(file), _line(line) {}
1063 		~StreamLogger() noexcept(false);
1064 
1065 		template<typename T>
operator <<(const T & t)1066 		StreamLogger& operator<<(const T& t)
1067 		{
1068 			_ss << t;
1069 			return *this;
1070 		}
1071 
1072 		// std::endl and other iomanip:s.
operator <<(std::ostream & (* f)(std::ostream &))1073 		StreamLogger& operator<<(std::ostream&(*f)(std::ostream&))
1074 		{
1075 			f(_ss);
1076 			return *this;
1077 		}
1078 
1079 	private:
1080 		Verbosity   _verbosity;
1081 		const char* _file;
1082 		unsigned    _line;
1083 		std::ostringstream _ss;
1084 	};
1085 
1086 	class AbortLogger
1087 	{
1088 	public:
AbortLogger(const char * expr,const char * file,unsigned line)1089 		AbortLogger(const char* expr, const char* file, unsigned line) : _expr(expr), _file(file), _line(line) { }
1090 		LOGURU_NORETURN ~AbortLogger() noexcept(false);
1091 
1092 		template<typename T>
operator <<(const T & t)1093 		AbortLogger& operator<<(const T& t)
1094 		{
1095 			_ss << t;
1096 			return *this;
1097 		}
1098 
1099 		// std::endl and other iomanip:s.
operator <<(std::ostream & (* f)(std::ostream &))1100 		AbortLogger& operator<<(std::ostream&(*f)(std::ostream&))
1101 		{
1102 			f(_ss);
1103 			return *this;
1104 		}
1105 
1106 	private:
1107 		const char*        _expr;
1108 		const char*        _file;
1109 		unsigned           _line;
1110 		std::ostringstream _ss;
1111 	};
1112 
1113 	class Voidify
1114 	{
1115 	public:
Voidify()1116 		Voidify() {}
1117 		// This has to be an operator with a precedence lower than << but higher than ?:
operator &(const StreamLogger &)1118 		void operator&(const StreamLogger&) { }
operator &(const AbortLogger &)1119 		void operator&(const AbortLogger&)  { }
1120 	};
1121 
1122 	/*  Helper functions for CHECK_OP_S macro.
1123 		GLOG trick: The (int, int) specialization works around the issue that the compiler
1124 		will not instantiate the template version of the function on values of unnamed enum type. */
1125 	#define DEFINE_CHECK_OP_IMPL(name, op)                                                             \
1126 		template <typename T1, typename T2>                                                            \
1127 		inline std::string* name(const char* expr, const T1& v1, const char* op_str, const T2& v2)     \
1128 		{                                                                                              \
1129 			if (LOGURU_PREDICT_TRUE(v1 op v2)) { return NULL; }                                        \
1130 			std::ostringstream ss;                                                                     \
1131 			ss << "CHECK FAILED:  " << expr << "  (" << v1 << " " << op_str << " " << v2 << ")  ";     \
1132 			return new std::string(ss.str());                                                          \
1133 		}                                                                                              \
1134 		inline std::string* name(const char* expr, int v1, const char* op_str, int v2)                 \
1135 		{                                                                                              \
1136 			return name<int, int>(expr, v1, op_str, v2);                                               \
1137 		}
1138 
1139 	DEFINE_CHECK_OP_IMPL(check_EQ_impl, ==)
1140 	DEFINE_CHECK_OP_IMPL(check_NE_impl, !=)
1141 	DEFINE_CHECK_OP_IMPL(check_LE_impl, <=)
1142 	DEFINE_CHECK_OP_IMPL(check_LT_impl, < )
1143 	DEFINE_CHECK_OP_IMPL(check_GE_impl, >=)
1144 	DEFINE_CHECK_OP_IMPL(check_GT_impl, > )
1145 	#undef DEFINE_CHECK_OP_IMPL
1146 
1147 	/*  GLOG trick: Function is overloaded for integral types to allow static const integrals
1148 		declared in classes and not defined to be used as arguments to CHECK* macros. */
1149 	template <class T>
referenceable_value(const T & t)1150 	inline const T&           referenceable_value(const T&           t) { return t; }
referenceable_value(char t)1151 	inline char               referenceable_value(char               t) { return t; }
referenceable_value(unsigned char t)1152 	inline unsigned char      referenceable_value(unsigned char      t) { return t; }
referenceable_value(signed char t)1153 	inline signed char        referenceable_value(signed char        t) { return t; }
referenceable_value(short t)1154 	inline short              referenceable_value(short              t) { return t; }
referenceable_value(unsigned short t)1155 	inline unsigned short     referenceable_value(unsigned short     t) { return t; }
referenceable_value(int t)1156 	inline int                referenceable_value(int                t) { return t; }
referenceable_value(unsigned int t)1157 	inline unsigned int       referenceable_value(unsigned int       t) { return t; }
referenceable_value(long t)1158 	inline long               referenceable_value(long               t) { return t; }
referenceable_value(unsigned long t)1159 	inline unsigned long      referenceable_value(unsigned long      t) { return t; }
referenceable_value(long long t)1160 	inline long long          referenceable_value(long long          t) { return t; }
referenceable_value(unsigned long long t)1161 	inline unsigned long long referenceable_value(unsigned long long t) { return t; }
1162 } // namespace loguru
1163 
1164 // -----------------------------------------------
1165 // Logging macros:
1166 
1167 // usage:  LOG_STREAM(INFO) << "Foo " << std::setprecision(10) << some_value;
1168 #define VLOG_IF_S(verbosity, cond)                                                                 \
1169 	((verbosity) > loguru::current_verbosity_cutoff() || (cond) == false)                          \
1170 		? (void)0                                                                                  \
1171 		: loguru::Voidify() & loguru::StreamLogger(verbosity, __FILE__, __LINE__)
1172 #define LOG_IF_S(verbosity_name, cond) VLOG_IF_S(loguru::Verbosity_ ## verbosity_name, cond)
1173 #define VLOG_S(verbosity)              VLOG_IF_S(verbosity, true)
1174 #define LOG_S(verbosity_name)          VLOG_S(loguru::Verbosity_ ## verbosity_name)
1175 
1176 // -----------------------------------------------
1177 // ABORT_S macro. Usage:  ABORT_S() << "Causo of error: " << details;
1178 
1179 #define ABORT_S() loguru::Voidify() & loguru::AbortLogger("ABORT: ", __FILE__, __LINE__)
1180 
1181 // -----------------------------------------------
1182 // CHECK_S macros:
1183 
1184 #define CHECK_WITH_INFO_S(cond, info)                                                              \
1185 	LOGURU_PREDICT_TRUE((cond) == true)                                                            \
1186 		? (void)0                                                                                  \
1187 		: loguru::Voidify() & loguru::AbortLogger("CHECK FAILED:  " info "  ", __FILE__, __LINE__)
1188 
1189 #define CHECK_S(cond) CHECK_WITH_INFO_S(cond, #cond)
1190 #define CHECK_NOTNULL_S(x) CHECK_WITH_INFO_S((x) != nullptr, #x " != nullptr")
1191 
1192 #define CHECK_OP_S(function_name, expr1, op, expr2)                                                \
1193 	while (auto error_string = loguru::function_name(#expr1 " " #op " " #expr2,                    \
1194 													 loguru::referenceable_value(expr1), #op,      \
1195 													 loguru::referenceable_value(expr2)))          \
1196 		loguru::AbortLogger(error_string->c_str(), __FILE__, __LINE__)
1197 
1198 #define CHECK_EQ_S(expr1, expr2) CHECK_OP_S(check_EQ_impl, expr1, ==, expr2)
1199 #define CHECK_NE_S(expr1, expr2) CHECK_OP_S(check_NE_impl, expr1, !=, expr2)
1200 #define CHECK_LE_S(expr1, expr2) CHECK_OP_S(check_LE_impl, expr1, <=, expr2)
1201 #define CHECK_LT_S(expr1, expr2) CHECK_OP_S(check_LT_impl, expr1, < , expr2)
1202 #define CHECK_GE_S(expr1, expr2) CHECK_OP_S(check_GE_impl, expr1, >=, expr2)
1203 #define CHECK_GT_S(expr1, expr2) CHECK_OP_S(check_GT_impl, expr1, > , expr2)
1204 
1205 #if LOGURU_DEBUG_LOGGING
1206 	// Debug logging enabled:
1207 	#define DVLOG_IF_S(verbosity, cond)     VLOG_IF_S(verbosity, cond)
1208 	#define DLOG_IF_S(verbosity_name, cond) LOG_IF_S(verbosity_name, cond)
1209 	#define DVLOG_S(verbosity)              VLOG_S(verbosity)
1210 	#define DLOG_S(verbosity_name)          LOG_S(verbosity_name)
1211 #else
1212 	// Debug logging disabled:
1213 	#define DVLOG_IF_S(verbosity, cond)                                                     \
1214 		(true || (verbosity) > loguru::current_verbosity_cutoff() || (cond) == false)       \
1215 			? (void)0                                                                       \
1216 			: loguru::Voidify() & loguru::StreamLogger(verbosity, __FILE__, __LINE__)
1217 
1218 	#define DLOG_IF_S(verbosity_name, cond) DVLOG_IF_S(loguru::Verbosity_ ## verbosity_name, cond)
1219 	#define DVLOG_S(verbosity)              DVLOG_IF_S(verbosity, true)
1220 	#define DLOG_S(verbosity_name)          DVLOG_S(loguru::Verbosity_ ## verbosity_name)
1221 #endif
1222 
1223 #if LOGURU_DEBUG_CHECKS
1224 	// Debug checks enabled:
1225 	#define DCHECK_S(cond)                  CHECK_S(cond)
1226 	#define DCHECK_NOTNULL_S(x)             CHECK_NOTNULL_S(x)
1227 	#define DCHECK_EQ_S(a, b)               CHECK_EQ_S(a, b)
1228 	#define DCHECK_NE_S(a, b)               CHECK_NE_S(a, b)
1229 	#define DCHECK_LT_S(a, b)               CHECK_LT_S(a, b)
1230 	#define DCHECK_LE_S(a, b)               CHECK_LE_S(a, b)
1231 	#define DCHECK_GT_S(a, b)               CHECK_GT_S(a, b)
1232 	#define DCHECK_GE_S(a, b)               CHECK_GE_S(a, b)
1233 #else
1234 // Debug checks disabled:
1235 	#define DCHECK_S(cond)                  CHECK_S(true || (cond))
1236 	#define DCHECK_NOTNULL_S(x)             CHECK_S(true || (x) != nullptr)
1237 	#define DCHECK_EQ_S(a, b)               CHECK_S(true || (a) == (b))
1238 	#define DCHECK_NE_S(a, b)               CHECK_S(true || (a) != (b))
1239 	#define DCHECK_LT_S(a, b)               CHECK_S(true || (a) <  (b))
1240 	#define DCHECK_LE_S(a, b)               CHECK_S(true || (a) <= (b))
1241 	#define DCHECK_GT_S(a, b)               CHECK_S(true || (a) >  (b))
1242 	#define DCHECK_GE_S(a, b)               CHECK_S(true || (a) >= (b))
1243 #endif
1244 
1245 #if LOGURU_REPLACE_GLOG
1246 	#undef LOG
1247 	#undef VLOG
1248 	#undef LOG_IF
1249 	#undef VLOG_IF
1250 	#undef CHECK
1251 	#undef CHECK_NOTNULL
1252 	#undef CHECK_EQ
1253 	#undef CHECK_NE
1254 	#undef CHECK_LT
1255 	#undef CHECK_LE
1256 	#undef CHECK_GT
1257 	#undef CHECK_GE
1258 	#undef DLOG
1259 	#undef DVLOG
1260 	#undef DLOG_IF
1261 	#undef DVLOG_IF
1262 	#undef DCHECK
1263 	#undef DCHECK_NOTNULL
1264 	#undef DCHECK_EQ
1265 	#undef DCHECK_NE
1266 	#undef DCHECK_LT
1267 	#undef DCHECK_LE
1268 	#undef DCHECK_GT
1269 	#undef DCHECK_GE
1270 	#undef VLOG_IS_ON
1271 
1272 	#define LOG            LOG_S
1273 	#define VLOG           VLOG_S
1274 	#define LOG_IF         LOG_IF_S
1275 	#define VLOG_IF        VLOG_IF_S
1276 	#define CHECK(cond)    CHECK_S(!!(cond))
1277 	#define CHECK_NOTNULL  CHECK_NOTNULL_S
1278 	#define CHECK_EQ       CHECK_EQ_S
1279 	#define CHECK_NE       CHECK_NE_S
1280 	#define CHECK_LT       CHECK_LT_S
1281 	#define CHECK_LE       CHECK_LE_S
1282 	#define CHECK_GT       CHECK_GT_S
1283 	#define CHECK_GE       CHECK_GE_S
1284 	#define DLOG           DLOG_S
1285 	#define DVLOG          DVLOG_S
1286 	#define DLOG_IF        DLOG_IF_S
1287 	#define DVLOG_IF       DVLOG_IF_S
1288 	#define DCHECK         DCHECK_S
1289 	#define DCHECK_NOTNULL DCHECK_NOTNULL_S
1290 	#define DCHECK_EQ      DCHECK_EQ_S
1291 	#define DCHECK_NE      DCHECK_NE_S
1292 	#define DCHECK_LT      DCHECK_LT_S
1293 	#define DCHECK_LE      DCHECK_LE_S
1294 	#define DCHECK_GT      DCHECK_GT_S
1295 	#define DCHECK_GE      DCHECK_GE_S
1296 	#define VLOG_IS_ON(verbosity) ((verbosity) <= loguru::current_verbosity_cutoff())
1297 
1298 #endif // LOGURU_REPLACE_GLOG
1299 
1300 #endif // LOGURU_WITH_STREAMS
1301 
1302 #endif // LOGURU_HAS_DECLARED_STREAMS_HEADER
1303 
1304 // ----------------------------------------------------------------------------
1305 // 88 8b    d8 88""Yb 88     888888 8b    d8 888888 88b 88 888888    db    888888 88  dP"Yb  88b 88
1306 // 88 88b  d88 88__dP 88     88__   88b  d88 88__   88Yb88   88     dPYb     88   88 dP   Yb 88Yb88
1307 // 88 88YbdP88 88"""  88  .o 88""   88YbdP88 88""   88 Y88   88    dP__Yb    88   88 Yb   dP 88 Y88
1308 // 88 88 YY 88 88     88ood8 888888 88 YY 88 888888 88  Y8   88   dP""""Yb   88   88  YbodP  88  Y8
1309 
1310 /* In one of your .cpp files you need to do the following:
1311 #define LOGURU_IMPLEMENTATION 1
1312 #include <loguru.hpp>
1313 
1314 This will define all the Loguru functions so that the linker may find them.
1315 */
1316 
1317 #if defined(LOGURU_IMPLEMENTATION) && !defined(LOGURU_HAS_BEEN_IMPLEMENTED)
1318 #define LOGURU_HAS_BEEN_IMPLEMENTED
1319 
1320 #define LOGURU_PREAMBLE_WIDTH (53 + LOGURU_THREADNAME_WIDTH + LOGURU_FILENAME_WIDTH)
1321 
1322 #include <algorithm>
1323 #include <atomic>
1324 #include <chrono>
1325 #include <cstdarg>
1326 #include <cstdio>
1327 #include <cstdlib>
1328 #include <cstring>
1329 #include <mutex>
1330 #include <regex>
1331 #include <string>
1332 #include <thread>
1333 #include <vector>
1334 
1335 #ifdef _WIN32
1336 	#include <direct.h>
1337 
1338 	#define localtime_r(a, b) localtime_s(b, a) // No localtime_r with MSVC, but arguments are swapped for localtime_s
1339 #else
1340 	#include <signal.h>
1341 	#include <sys/stat.h> // mkdir
1342 	#include <unistd.h>   // STDERR_FILENO
1343 #endif
1344 
1345 #ifdef __linux__
1346 	#include <linux/limits.h> // PATH_MAX
1347 #elif !defined(_WIN32)
1348 	#include <limits.h> // PATH_MAX
1349 #endif
1350 
1351 #ifndef PATH_MAX
1352 	#define PATH_MAX 1024
1353 #endif
1354 
1355 #ifdef __APPLE__
1356 	#include "TargetConditionals.h"
1357 #endif
1358 
1359 // TODO: use defined(_POSIX_VERSION) for some of these things?
1360 
1361 #if defined(_WIN32) || defined(__CYGWIN__)
1362 	#define LOGURU_PTHREADS    0
1363 	#define LOGURU_WINTHREADS  1
1364 	#ifndef LOGURU_STACKTRACES
1365 		#define LOGURU_STACKTRACES 0
1366 	#endif
1367 #elif defined(__rtems__)
1368 	#define LOGURU_PTHREADS    1
1369 	#define LOGURU_WINTHREADS  0
1370 	#ifndef LOGURU_STACKTRACES
1371 		#define LOGURU_STACKTRACES 0
1372 	#endif
1373 #else
1374 	#define LOGURU_PTHREADS    1
1375 	#define LOGURU_WINTHREADS  0
1376 	#ifndef LOGURU_STACKTRACES
1377 		#define LOGURU_STACKTRACES 1
1378 	#endif
1379 #endif
1380 
1381 #if LOGURU_STACKTRACES
1382 	#include <cxxabi.h>    // for __cxa_demangle
1383 	#include <dlfcn.h>     // for dladdr
1384 	#include <execinfo.h>  // for backtrace
1385 #endif // LOGURU_STACKTRACES
1386 
1387 #if LOGURU_PTHREADS
1388 	#include <pthread.h>
1389 	#if defined(__FreeBSD__)
1390 		#include <pthread_np.h>
1391 	#ifndef __DragonFly__
1392 		#include <sys/thr.h>
1393 	#endif
1394 	#elif defined(__OpenBSD__)
1395 		#include <pthread_np.h>
1396 	#endif
1397 
1398 	#ifdef __linux__
1399 		/* On Linux, the default thread name is the same as the name of the binary.
1400 		   Additionally, all new threads inherit the name of the thread it got forked from.
1401 		   For this reason, Loguru use the pthread Thread Local Storage
1402 		   for storing thread names on Linux. */
1403 		#define LOGURU_PTLS_NAMES 1
1404 	#endif
1405 #endif
1406 
1407 #if LOGURU_WINTHREADS
1408 	#ifndef _WIN32_WINNT
1409 		#define _WIN32_WINNT 0x0502
1410 	#endif
1411 	#define WIN32_LEAN_AND_MEAN
1412 	#define NOMINMAX
1413 	#include <windows.h>
1414 #endif
1415 
1416 #ifndef LOGURU_PTLS_NAMES
1417    #define LOGURU_PTLS_NAMES 0
1418 #endif
1419 
1420 namespace loguru
1421 {
1422 	using namespace std::chrono;
1423 
1424 #if LOGURU_WITH_FILEABS
1425 	struct FileAbs
1426 	{
1427 		char path[PATH_MAX];
1428 		char mode_str[4];
1429 		Verbosity verbosity;
1430 		struct stat st;
1431 		FILE* fp;
1432 		bool is_reopening = false; // to prevent recursive call in file_reopen.
1433 		decltype(steady_clock::now()) last_check_time = steady_clock::now();
1434 	};
1435 #else
1436 	typedef FILE* FileAbs;
1437 #endif
1438 
1439 	struct Callback
1440 	{
1441 		std::string     id;
1442 		log_handler_t   callback;
1443 		void*           user_data;
1444 		Verbosity       verbosity; // Does not change!
1445 		close_handler_t close;
1446 		flush_handler_t flush;
1447 		unsigned        indentation;
1448 	};
1449 
1450 	using CallbackVec = std::vector<Callback>;
1451 
1452 	using StringPair     = std::pair<std::string, std::string>;
1453 	using StringPairList = std::vector<StringPair>;
1454 
1455 	const auto SCOPE_TIME_PRECISION = 3; // 3=ms, 6≈us, 9=ns
1456 
1457 	const auto s_start_time = steady_clock::now();
1458 
1459 	Verbosity g_stderr_verbosity  = Verbosity_0;
1460 	bool      g_colorlogtostderr  = true;
1461 	unsigned  g_flush_interval_ms = 0;
1462 	bool      g_preamble          = true;
1463 
1464 	// Preamble details
1465 	bool      g_preamble_date     = true;
1466 	bool      g_preamble_time     = true;
1467 	bool      g_preamble_uptime   = true;
1468 	bool      g_preamble_thread   = true;
1469 	bool      g_preamble_file     = true;
1470 	bool      g_preamble_verbose  = true;
1471 	bool      g_preamble_pipe     = true;
1472 
1473 	static std::recursive_mutex  s_mutex;
1474 	static Verbosity             s_max_out_verbosity = Verbosity_OFF;
1475 	static std::string           s_argv0_filename;
1476 	static std::string           s_arguments;
1477 	static char                  s_current_dir[PATH_MAX];
1478 	static CallbackVec           s_callbacks;
1479 	static fatal_handler_t       s_fatal_handler   = nullptr;
1480 	static StringPairList        s_user_stack_cleanups;
1481 	static bool                  s_strip_file_path = true;
1482 	static std::atomic<unsigned> s_stderr_indentation { 0 };
1483 
1484 	// For periodic flushing:
1485 	static std::thread* s_flush_thread   = nullptr;
1486 	static bool         s_needs_flushing = false;
1487 
__anon1ad9de9b0102()1488 	static const bool s_terminal_has_color = [](){
1489 		#ifdef _WIN32
1490 			#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
1491 			#define ENABLE_VIRTUAL_TERMINAL_PROCESSING  0x0004
1492 			#endif
1493 
1494 			HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
1495 			if (hOut != INVALID_HANDLE_VALUE) {
1496 				DWORD dwMode = 0;
1497 				GetConsoleMode(hOut, &dwMode);
1498 				dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
1499 				return SetConsoleMode(hOut, dwMode) != 0;
1500 			}
1501 			return false;
1502 		#else
1503 			if (const char* term = getenv("TERM")) {
1504 				return 0 == strcmp(term, "cygwin")
1505 					|| 0 == strcmp(term, "linux")
1506 					|| 0 == strcmp(term, "rxvt-unicode-256color")
1507 					|| 0 == strcmp(term, "screen")
1508 					|| 0 == strcmp(term, "screen-256color")
1509 					|| 0 == strcmp(term, "tmux-256color")
1510 					|| 0 == strcmp(term, "xterm")
1511 					|| 0 == strcmp(term, "xterm-256color")
1512 					|| 0 == strcmp(term, "xterm-termite")
1513 					|| 0 == strcmp(term, "xterm-color");
1514 			} else {
1515 				return false;
1516 			}
1517 		#endif
1518 	}();
1519 
1520 	static void print_preamble_header(char* out_buff, size_t out_buff_size);
1521 
1522 	#if LOGURU_PTLS_NAMES
1523 		static pthread_once_t s_pthread_key_once = PTHREAD_ONCE_INIT;
1524 		static pthread_key_t  s_pthread_key_name;
1525 
make_pthread_key_name()1526 		void make_pthread_key_name()
1527 		{
1528 			(void)pthread_key_create(&s_pthread_key_name, free);
1529 		}
1530 	#endif
1531 
1532 	// ------------------------------------------------------------------------------
1533 	// Colors
1534 
terminal_has_color()1535 	bool terminal_has_color() { return s_terminal_has_color; }
1536 
1537 	// Colors
1538 
1539 #ifdef _WIN32
1540 #define VTSEQ(ID) ("\x1b[1;" #ID "m")
1541 #else
1542 #define VTSEQ(ID) ("\e[" #ID "m")
1543 #endif
1544 
terminal_black()1545 	const char* terminal_black()      { return s_terminal_has_color ? VTSEQ(30) : ""; }
terminal_red()1546 	const char* terminal_red()        { return s_terminal_has_color ? VTSEQ(31) : ""; }
terminal_green()1547 	const char* terminal_green()      { return s_terminal_has_color ? VTSEQ(32) : ""; }
terminal_yellow()1548 	const char* terminal_yellow()     { return s_terminal_has_color ? VTSEQ(33) : ""; }
terminal_blue()1549 	const char* terminal_blue()       { return s_terminal_has_color ? VTSEQ(34) : ""; }
terminal_purple()1550 	const char* terminal_purple()     { return s_terminal_has_color ? VTSEQ(35) : ""; }
terminal_cyan()1551 	const char* terminal_cyan()       { return s_terminal_has_color ? VTSEQ(36) : ""; }
terminal_light_gray()1552 	const char* terminal_light_gray() { return s_terminal_has_color ? VTSEQ(37) : ""; }
terminal_white()1553 	const char* terminal_white()      { return s_terminal_has_color ? VTSEQ(37) : ""; }
terminal_light_red()1554 	const char* terminal_light_red()  { return s_terminal_has_color ? VTSEQ(91) : ""; }
terminal_dim()1555 	const char* terminal_dim()        { return s_terminal_has_color ? VTSEQ(2)  : ""; }
1556 
1557 	// Formating
terminal_bold()1558 	const char* terminal_bold()       { return s_terminal_has_color ? VTSEQ(1) : ""; }
terminal_underline()1559 	const char* terminal_underline()  { return s_terminal_has_color ? VTSEQ(4) : ""; }
1560 
1561 	// You should end each line with this!
terminal_reset()1562 	const char* terminal_reset()      { return s_terminal_has_color ? VTSEQ(0) : ""; }
1563 
1564 	// ------------------------------------------------------------------------------
1565 #if LOGURU_WITH_FILEABS
1566 	void file_reopen(void* user_data);
to_file(void * user_data)1567 	inline FILE* to_file(void* user_data) { return reinterpret_cast<FileAbs*>(user_data)->fp; }
1568 #else
to_file(void * user_data)1569 	inline FILE* to_file(void* user_data) { return reinterpret_cast<FILE*>(user_data); }
1570 #endif
1571 
file_log(void * user_data,const Message & message)1572 	void file_log(void* user_data, const Message& message)
1573 	{
1574 #if LOGURU_WITH_FILEABS
1575 		FileAbs* file_abs = reinterpret_cast<FileAbs*>(user_data);
1576 		if (file_abs->is_reopening) {
1577 			return;
1578 		}
1579 		// It is better checking file change every minute/hour/day,
1580 		// instead of doing this every time we log.
1581 		// Here check_interval is set to zero to enable checking every time;
1582 		const auto check_interval = seconds(0);
1583 		if (duration_cast<seconds>(steady_clock::now() - file_abs->last_check_time) > check_interval) {
1584 			file_abs->last_check_time = steady_clock::now();
1585 			file_reopen(user_data);
1586 		}
1587 		FILE* file = to_file(user_data);
1588 		if (!file) {
1589 			return;
1590 		}
1591 #else
1592 		FILE* file = to_file(user_data);
1593 #endif
1594 		fprintf(file, "%s%s%s%s\n",
1595 			message.preamble, message.indentation, message.prefix, message.message);
1596 		if (g_flush_interval_ms == 0) {
1597 			fflush(file);
1598 		}
1599 	}
1600 
file_close(void * user_data)1601 	void file_close(void* user_data)
1602 	{
1603 		FILE* file = to_file(user_data);
1604 		if (file) {
1605 			fclose(file);
1606 		}
1607 #if LOGURU_WITH_FILEABS
1608 		delete reinterpret_cast<FileAbs*>(user_data);
1609 #endif
1610 	}
1611 
file_flush(void * user_data)1612 	void file_flush(void* user_data)
1613 	{
1614 		FILE* file = to_file(user_data);
1615 		fflush(file);
1616 	}
1617 
1618 #if LOGURU_WITH_FILEABS
file_reopen(void * user_data)1619 	void file_reopen(void* user_data)
1620 	{
1621 		FileAbs * file_abs = reinterpret_cast<FileAbs*>(user_data);
1622 		struct stat st;
1623 		int ret;
1624 		if (!file_abs->fp || (ret = stat(file_abs->path, &st)) == -1 || (st.st_ino != file_abs->st.st_ino)) {
1625 			file_abs->is_reopening = true;
1626 			if (file_abs->fp) {
1627 				fclose(file_abs->fp);
1628 			}
1629 			if (!file_abs->fp) {
1630 				LOG_F(INFO, "Reopening file '%s' due to previous error", file_abs->path);
1631 			}
1632 			else if (ret < 0) {
1633 				const auto why = errno_as_text();
1634 				LOG_F(INFO, "Reopening file '%s' due to '%s'", file_abs->path, why.c_str());
1635 			} else {
1636 				LOG_F(INFO, "Reopening file '%s' due to file changed", file_abs->path);
1637 			}
1638 			// try reopen current file.
1639 			if (!create_directories(file_abs->path)) {
1640 				LOG_F(ERROR, "Failed to create directories to '%s'", file_abs->path);
1641 			}
1642 			file_abs->fp = fopen(file_abs->path, file_abs->mode_str);
1643 			if (!file_abs->fp) {
1644 				LOG_F(ERROR, "Failed to open '%s'", file_abs->path);
1645 			} else {
1646 				stat(file_abs->path, &file_abs->st);
1647 			}
1648 			file_abs->is_reopening = false;
1649 		}
1650 	}
1651 #endif
1652 	// ------------------------------------------------------------------------------
1653 
1654 	// Helpers:
1655 
~Text()1656 	Text::~Text() { free(_str); }
1657 
1658 	LOGURU_PRINTF_LIKE(1, 0)
vtextprintf(const char * format,va_list vlist)1659 	static Text vtextprintf(const char* format, va_list vlist)
1660 	{
1661 #ifdef _WIN32
1662 		int bytes_needed = _vscprintf(format, vlist);
1663 		CHECK_F(bytes_needed >= 0, "Bad string format: '%s'", format);
1664 		char* buff = (char*)malloc(bytes_needed+1);
1665 		vsnprintf(buff, bytes_needed+1, format, vlist);
1666 		return Text(buff);
1667 #else
1668 		char* buff = nullptr;
1669 		int result = vasprintf(&buff, format, vlist);
1670 		CHECK_F(result >= 0, "Bad string format: '%s'", format);
1671 		return Text(buff);
1672 #endif
1673 	}
1674 
textprintf(const char * format,...)1675 	Text textprintf(const char* format, ...)
1676 	{
1677 		va_list vlist;
1678 		va_start(vlist, format);
1679 		auto result = vtextprintf(format, vlist);
1680 		va_end(vlist);
1681 		return result;
1682 	}
1683 
1684 	// Overloaded for variadic template matching.
textprintf()1685 	Text textprintf()
1686 	{
1687 		return Text(static_cast<char*>(calloc(1, 1)));
1688 	}
1689 
indentation(unsigned depth)1690 	static const char* indentation(unsigned depth)
1691 	{
1692 		static const char buff[] =
1693 		".   .   .   .   .   .   .   .   .   .   " ".   .   .   .   .   .   .   .   .   .   "
1694 		".   .   .   .   .   .   .   .   .   .   " ".   .   .   .   .   .   .   .   .   .   "
1695 		".   .   .   .   .   .   .   .   .   .   " ".   .   .   .   .   .   .   .   .   .   "
1696 		".   .   .   .   .   .   .   .   .   .   " ".   .   .   .   .   .   .   .   .   .   "
1697 		".   .   .   .   .   .   .   .   .   .   " ".   .   .   .   .   .   .   .   .   .   ";
1698 		static const size_t INDENTATION_WIDTH = 4;
1699 		static const size_t NUM_INDENTATIONS = (sizeof(buff) - 1) / INDENTATION_WIDTH;
1700 		depth = std::min<unsigned>(depth, NUM_INDENTATIONS);
1701 		return buff + INDENTATION_WIDTH * (NUM_INDENTATIONS - depth);
1702 	}
1703 
parse_args(int & argc,char * argv[],const char * verbosity_flag)1704 	static void parse_args(int& argc, char* argv[], const char* verbosity_flag)
1705 	{
1706 		int arg_dest = 1;
1707 		int out_argc = argc;
1708 
1709 		for (int arg_it = 1; arg_it < argc; ++arg_it) {
1710 			auto cmd = argv[arg_it];
1711 			auto arg_len = strlen(verbosity_flag);
1712 			if (strncmp(cmd, verbosity_flag, arg_len) == 0 && !std::isalpha(cmd[arg_len], std::locale(""))) {
1713 				out_argc -= 1;
1714 				auto value_str = cmd + arg_len;
1715 				if (value_str[0] == '\0') {
1716 					// Value in separate argument
1717 					arg_it += 1;
1718 					CHECK_LT_F(arg_it, argc, "Missing verbosiy level after %s", verbosity_flag);
1719 					value_str = argv[arg_it];
1720 					out_argc -= 1;
1721 				}
1722 				if (*value_str == '=') { value_str += 1; }
1723 
1724 				if (strcmp(value_str, "OFF") == 0) {
1725 					g_stderr_verbosity = Verbosity_OFF;
1726 				} else if (strcmp(value_str, "INFO") == 0) {
1727 					g_stderr_verbosity = Verbosity_INFO;
1728 				} else if (strcmp(value_str, "WARNING") == 0) {
1729 					g_stderr_verbosity = Verbosity_WARNING;
1730 				} else if (strcmp(value_str, "ERROR") == 0) {
1731 					g_stderr_verbosity = Verbosity_ERROR;
1732 				} else if (strcmp(value_str, "FATAL") == 0) {
1733 					g_stderr_verbosity = Verbosity_FATAL;
1734 				} else {
1735 					char* end = 0;
1736 					g_stderr_verbosity = static_cast<int>(strtol(value_str, &end, 10));
1737 					CHECK_F(end && *end == '\0',
1738 						"Invalid verbosity. Expected integer, INFO, WARNING, ERROR or OFF, got '%s'", value_str);
1739 				}
1740 			} else {
1741 				argv[arg_dest++] = argv[arg_it];
1742 			}
1743 		}
1744 
1745 		argc = out_argc;
1746 		argv[argc] = nullptr;
1747 	}
1748 
now_ns()1749 	static long long now_ns()
1750 	{
1751 		return duration_cast<nanoseconds>(high_resolution_clock::now().time_since_epoch()).count();
1752 	}
1753 
1754 	// Returns the part of the path after the last / or \ (if any).
filename(const char * path)1755 	const char* filename(const char* path)
1756 	{
1757 		for (auto ptr = path; *ptr; ++ptr) {
1758 			if (*ptr == '/' || *ptr == '\\') {
1759 				path = ptr + 1;
1760 			}
1761 		}
1762 		return path;
1763 	}
1764 
1765 	// ------------------------------------------------------------------------------
1766 
on_atexit()1767 	static void on_atexit()
1768 	{
1769 		LOG_F(INFO, "atexit");
1770 		flush();
1771 	}
1772 
1773 	static void install_signal_handlers();
1774 
write_hex_digit(std::string & out,unsigned num)1775 	static void write_hex_digit(std::string& out, unsigned num)
1776 	{
1777 		DCHECK_LT_F(num, 16u);
1778 		if (num < 10u) { out.push_back(char('0' + num)); }
1779 		else { out.push_back(char('A' + num - 10)); }
1780 	}
1781 
write_hex_byte(std::string & out,uint8_t n)1782 	static void write_hex_byte(std::string& out, uint8_t n)
1783 	{
1784 		write_hex_digit(out, n >> 4u);
1785 		write_hex_digit(out, n & 0x0f);
1786 	}
1787 
escape(std::string & out,const std::string & str)1788 	static void escape(std::string& out, const std::string& str)
1789 	{
1790 		for (char c : str) {
1791 			/**/ if (c == '\a') { out += "\\a";  }
1792 			else if (c == '\b') { out += "\\b";  }
1793 			else if (c == '\f') { out += "\\f";  }
1794 			else if (c == '\n') { out += "\\n";  }
1795 			else if (c == '\r') { out += "\\r";  }
1796 			else if (c == '\t') { out += "\\t";  }
1797 			else if (c == '\v') { out += "\\v";  }
1798 			else if (c == '\\') { out += "\\\\"; }
1799 			else if (c == '\'') { out += "\\\'"; }
1800 			else if (c == '\"') { out += "\\\""; }
1801 			else if (c == ' ')  { out += "\\ ";  }
1802 			else if (0 <= c && c < 0x20) { // ASCI control character:
1803 			// else if (c < 0x20 || c != (c & 127)) { // ASCII control character or UTF-8:
1804 				out += "\\x";
1805 				write_hex_byte(out, static_cast<uint8_t>(c));
1806 			} else { out += c; }
1807 		}
1808 	}
1809 
errno_as_text()1810 	Text errno_as_text()
1811 	{
1812 		char buff[256];
1813 	#if defined(__GLIBC__) && defined(_GNU_SOURCE)
1814 		// GNU Version
1815 		return Text(strdup(strerror_r(errno, buff, sizeof(buff))));
1816 	#elif defined(__APPLE__) || _POSIX_C_SOURCE >= 200112L
1817 		// XSI Version
1818 		strerror_r(errno, buff, sizeof(buff));
1819 		return Text(strdup(buff));
1820 	#elif defined(_WIN32)
1821 		strerror_s(buff, sizeof(buff), errno);
1822 		return Text(strdup(buff));
1823 	#else
1824 		// Not thread-safe.
1825 		return Text(strdup(strerror(errno)));
1826 	#endif
1827 	}
1828 
init(int & argc,char * argv[],const char * verbosity_flag)1829 	void init(int& argc, char* argv[], const char* verbosity_flag)
1830 	{
1831 		CHECK_GT_F(argc,       0,       "Expected proper argc/argv");
1832 		CHECK_EQ_F(argv[argc], nullptr, "Expected proper argc/argv");
1833 
1834 		s_argv0_filename = filename(argv[0]);
1835 
1836 		#ifdef _WIN32
1837 			#define getcwd _getcwd
1838 		#endif
1839 
1840 		if (!getcwd(s_current_dir, sizeof(s_current_dir)))
1841 		{
1842 			const auto error_text = errno_as_text();
1843 			LOG_F(WARNING, "Failed to get current working directory: %s", error_text.c_str());
1844 		}
1845 
1846 		s_arguments = "";
1847 		for (int i = 0; i < argc; ++i) {
1848 			escape(s_arguments, argv[i]);
1849 			if (i + 1 < argc) {
1850 				s_arguments += " ";
1851 			}
1852 		}
1853 
1854 		if (verbosity_flag) {
1855 			parse_args(argc, argv, verbosity_flag);
1856 		}
1857 
1858 		#if LOGURU_PTLS_NAMES || LOGURU_WINTHREADS
1859 			set_thread_name("main thread");
1860 		#elif LOGURU_PTHREADS
1861 			char old_thread_name[16] = {0};
1862 			auto this_thread = pthread_self();
1863 			#if defined(__APPLE__) || defined(__linux__)
1864 				pthread_getname_np(this_thread, old_thread_name, sizeof(old_thread_name));
1865 			#endif
1866 			if (old_thread_name[0] == 0) {
1867 				#ifdef __APPLE__
1868 					pthread_setname_np("main thread");
1869 				#elif defined(__FreeBSD__) || defined(__OpenBSD__)
1870 					pthread_set_name_np(this_thread, "main thread");
1871 				#elif defined(__linux__)
1872 					pthread_setname_np(this_thread, "main thread");
1873 				#endif
1874 			}
1875 		#endif // LOGURU_PTHREADS
1876 
1877 		if (g_stderr_verbosity >= Verbosity_INFO) {
1878 			if (g_preamble) {
1879 				char preamble_explain[LOGURU_PREAMBLE_WIDTH];
1880 				print_preamble_header(preamble_explain, sizeof(preamble_explain));
1881 				if (g_colorlogtostderr && s_terminal_has_color) {
1882 					fprintf(stderr, "%s%s%s\n", terminal_reset(), terminal_dim(), preamble_explain);
1883 				} else {
1884 					fprintf(stderr, "%s\n", preamble_explain);
1885 				}
1886 			}
1887 			fflush(stderr);
1888 		}
1889 		LOG_F(INFO, "arguments: %s", s_arguments.c_str());
1890 		if (strlen(s_current_dir) != 0)
1891 		{
1892 			LOG_F(INFO, "Current dir: %s", s_current_dir);
1893 		}
1894 		LOG_F(INFO, "stderr verbosity: %d", g_stderr_verbosity);
1895 		LOG_F(INFO, "-----------------------------------");
1896 
1897 		install_signal_handlers();
1898 
1899 		atexit(on_atexit);
1900 	}
1901 
shutdown()1902 	void shutdown()
1903 	{
1904 		LOG_F(INFO, "loguru::shutdown()");
1905 		remove_all_callbacks();
1906 		set_fatal_handler(nullptr);
1907 	}
1908 
write_date_time(char * buff,size_t buff_size)1909 	void write_date_time(char* buff, size_t buff_size)
1910 	{
1911 		auto now = system_clock::now();
1912 		long long ms_since_epoch = duration_cast<milliseconds>(now.time_since_epoch()).count();
1913 		time_t sec_since_epoch = time_t(ms_since_epoch / 1000);
1914 		tm time_info;
1915 		localtime_r(&sec_since_epoch, &time_info);
1916 		snprintf(buff, buff_size, "%04d%02d%02d_%02d%02d%02d.%03lld",
1917 			1900 + time_info.tm_year, 1 + time_info.tm_mon, time_info.tm_mday,
1918 			time_info.tm_hour, time_info.tm_min, time_info.tm_sec, ms_since_epoch % 1000);
1919 	}
1920 
argv0_filename()1921 	const char* argv0_filename()
1922 	{
1923 		return s_argv0_filename.c_str();
1924 	}
1925 
arguments()1926 	const char* arguments()
1927 	{
1928 		return s_arguments.c_str();
1929 	}
1930 
current_dir()1931 	const char* current_dir()
1932 	{
1933 		return s_current_dir;
1934 	}
1935 
home_dir()1936 	const char* home_dir()
1937 	{
1938 		#ifdef _WIN32
1939 			auto user_profile = getenv("USERPROFILE");
1940 			CHECK_F(user_profile != nullptr, "Missing USERPROFILE");
1941 			return user_profile;
1942 		#else // _WIN32
1943 			auto home = getenv("HOME");
1944 			CHECK_F(home != nullptr, "Missing HOME");
1945 			return home;
1946 		#endif // _WIN32
1947 	}
1948 
suggest_log_path(const char * prefix,char * buff,unsigned buff_size)1949 	void suggest_log_path(const char* prefix, char* buff, unsigned buff_size)
1950 	{
1951 		if (prefix[0] == '~') {
1952 			snprintf(buff, buff_size - 1, "%s%s", home_dir(), prefix + 1);
1953 		} else {
1954 			snprintf(buff, buff_size - 1, "%s", prefix);
1955 		}
1956 
1957 		// Check for terminating /
1958 		size_t n = strlen(buff);
1959 		if (n != 0) {
1960 			if (buff[n - 1] != '/') {
1961 				CHECK_F(n + 2 < buff_size, "Filename buffer too small");
1962 				buff[n] = '/';
1963 				buff[n + 1] = '\0';
1964 			}
1965 		}
1966 
1967 		strncat(buff, s_argv0_filename.c_str(), buff_size - strlen(buff) - 1);
1968 		strncat(buff, "/",                      buff_size - strlen(buff) - 1);
1969 		write_date_time(buff + strlen(buff),    buff_size - strlen(buff));
1970 		strncat(buff, ".log",                   buff_size - strlen(buff) - 1);
1971 	}
1972 
create_directories(const char * file_path_const)1973 	bool create_directories(const char* file_path_const)
1974 	{
1975 		CHECK_F(file_path_const && *file_path_const);
1976 		char* file_path = strdup(file_path_const);
1977 		for (char* p = strchr(file_path + 1, '/'); p; p = strchr(p + 1, '/')) {
1978 			*p = '\0';
1979 
1980 	#ifdef _WIN32
1981 			if (_mkdir(file_path) == -1) {
1982 	#else
1983 			if (mkdir(file_path, 0755) == -1) {
1984 	#endif
1985 				if (errno != EEXIST) {
1986 					LOG_F(ERROR, "Failed to create directory '%s'", file_path);
1987 					LOG_IF_F(ERROR, errno == EACCES,       "EACCES");
1988 					LOG_IF_F(ERROR, errno == ENAMETOOLONG, "ENAMETOOLONG");
1989 					LOG_IF_F(ERROR, errno == ENOENT,       "ENOENT");
1990 					LOG_IF_F(ERROR, errno == ENOTDIR,      "ENOTDIR");
1991 					LOG_IF_F(ERROR, errno == ELOOP,        "ELOOP");
1992 
1993 					*p = '/';
1994 					free(file_path);
1995 					return false;
1996 				}
1997 			}
1998 			*p = '/';
1999 		}
2000 		free(file_path);
2001 		return true;
2002 	}
2003 	bool add_file(const char* path_in, FileMode mode, Verbosity verbosity)
2004 	{
2005 		char path[PATH_MAX];
2006 		if (path_in[0] == '~') {
2007 			snprintf(path, sizeof(path) - 1, "%s%s", home_dir(), path_in + 1);
2008 		} else {
2009 			snprintf(path, sizeof(path) - 1, "%s", path_in);
2010 		}
2011 
2012 		if (!create_directories(path)) {
2013 			LOG_F(ERROR, "Failed to create directories to '%s'", path);
2014 		}
2015 
2016 		const char* mode_str = (mode == FileMode::Truncate ? "w" : "a");
2017 		auto file = fopen(path, mode_str);
2018 		if (!file) {
2019 			LOG_F(ERROR, "Failed to open '%s'", path);
2020 			return false;
2021 		}
2022 #if LOGURU_WITH_FILEABS
2023 		FileAbs* file_abs = new FileAbs(); // this is deleted in file_close;
2024 		snprintf(file_abs->path, sizeof(file_abs->path) - 1, "%s", path);
2025 		snprintf(file_abs->mode_str, sizeof(file_abs->mode_str) - 1, "%s", mode_str);
2026 		stat(file_abs->path, &file_abs->st);
2027 		file_abs->fp = file;
2028 		file_abs->verbosity = verbosity;
2029 		add_callback(path_in, file_log, file_abs, verbosity, file_close, file_flush);
2030 #else
2031 		add_callback(path_in, file_log, file, verbosity, file_close, file_flush);
2032 #endif
2033 
2034 		if (mode == FileMode::Append) {
2035 			fprintf(file, "\n\n\n\n\n");
2036 		}
2037 		if (!s_arguments.empty()) {
2038 			fprintf(file, "arguments: %s\n", s_arguments.c_str());
2039 		}
2040 		if (strlen(s_current_dir) != 0) {
2041 			fprintf(file, "Current dir: %s\n", s_current_dir);
2042 		}
2043 		fprintf(file, "File verbosity level: %d\n", verbosity);
2044 		if (g_preamble) {
2045 			char preamble_explain[LOGURU_PREAMBLE_WIDTH];
2046 			print_preamble_header(preamble_explain, sizeof(preamble_explain));
2047 			fprintf(file, "%s\n", preamble_explain);
2048 		}
2049 		fflush(file);
2050 
2051 		LOG_F(INFO, "Logging to '%s', mode: '%s', verbosity: %d", path, mode_str, verbosity);
2052 		return true;
2053 	}
2054 
2055 	// Will be called right before abort().
2056 	void set_fatal_handler(fatal_handler_t handler)
2057 	{
2058 		s_fatal_handler = handler;
2059 	}
2060 
2061 	fatal_handler_t get_fatal_handler()
2062 	{
2063 		return s_fatal_handler;
2064 	}
2065 
2066 	void add_stack_cleanup(const char* find_this, const char* replace_with_this)
2067 	{
2068 		if (strlen(find_this) <= strlen(replace_with_this)) {
2069 			LOG_F(WARNING, "add_stack_cleanup: the replacement should be shorter than the pattern!");
2070 			return;
2071 		}
2072 
2073 		s_user_stack_cleanups.push_back(StringPair(find_this, replace_with_this));
2074 	}
2075 
2076 	static void on_callback_change()
2077 	{
2078 		s_max_out_verbosity = Verbosity_OFF;
2079 		for (const auto& callback : s_callbacks) {
2080 			s_max_out_verbosity = std::max(s_max_out_verbosity, callback.verbosity);
2081 		}
2082 	}
2083 
2084 	void add_callback(
2085 		const char*     id,
2086 		log_handler_t   callback,
2087 		void*           user_data,
2088 		Verbosity       verbosity,
2089 		close_handler_t on_close,
2090 		flush_handler_t on_flush)
2091 	{
2092 		std::lock_guard<std::recursive_mutex> lock(s_mutex);
2093 		s_callbacks.push_back(Callback{id, callback, user_data, verbosity, on_close, on_flush, 0});
2094 		on_callback_change();
2095 	}
2096 
2097 	bool remove_callback(const char* id)
2098 	{
2099 		std::lock_guard<std::recursive_mutex> lock(s_mutex);
2100 		auto it = std::find_if(begin(s_callbacks), end(s_callbacks), [&](const Callback& c) { return c.id == id; });
2101 		if (it != s_callbacks.end()) {
2102 			if (it->close) { it->close(it->user_data); }
2103 			s_callbacks.erase(it);
2104 			on_callback_change();
2105 			return true;
2106 		} else {
2107 			LOG_F(ERROR, "Failed to locate callback with id '%s'", id);
2108 			return false;
2109 		}
2110 	}
2111 
2112 	void remove_all_callbacks()
2113 	{
2114 		std::lock_guard<std::recursive_mutex> lock(s_mutex);
2115 		for (auto& callback : s_callbacks) {
2116 			if (callback.close) {
2117 				callback.close(callback.user_data);
2118 			}
2119 		}
2120 		s_callbacks.clear();
2121 		on_callback_change();
2122 	}
2123 
2124 	// Returns the maximum of g_stderr_verbosity and all file/custom outputs.
2125 	Verbosity current_verbosity_cutoff()
2126 	{
2127 		return g_stderr_verbosity > s_max_out_verbosity ?
2128 			   g_stderr_verbosity : s_max_out_verbosity;
2129 	}
2130 
2131 #if LOGURU_WINTHREADS
2132 	char* get_thread_name_win32()
2133 	{
2134 		__declspec( thread ) static char thread_name[LOGURU_THREADNAME_WIDTH + 1] = {0};
2135 		return &thread_name[0];
2136 	}
2137 #endif // LOGURU_WINTHREADS
2138 
2139 	void set_thread_name(const char* name)
2140 	{
2141 		#if LOGURU_PTLS_NAMES
2142 			(void)pthread_once(&s_pthread_key_once, make_pthread_key_name);
2143 			(void)pthread_setspecific(s_pthread_key_name, strdup(name));
2144 
2145 		#elif LOGURU_PTHREADS
2146 			#ifdef __APPLE__
2147 				pthread_setname_np(name);
2148 			#elif defined(__FreeBSD__) || defined(__OpenBSD__)
2149 				pthread_set_name_np(pthread_self(), name);
2150 			#elif defined(__linux__)
2151 				pthread_setname_np(pthread_self(), name);
2152 			#endif
2153 		#elif LOGURU_WINTHREADS
2154 			strncpy_s(get_thread_name_win32(), LOGURU_THREADNAME_WIDTH + 1, name, _TRUNCATE);
2155 		#else // LOGURU_PTHREADS
2156 			(void)name;
2157 		#endif // LOGURU_PTHREADS
2158 	}
2159 
2160 #if LOGURU_PTLS_NAMES
2161 	const char* get_thread_name_ptls()
2162 	{
2163 		(void)pthread_once(&s_pthread_key_once, make_pthread_key_name);
2164 		return static_cast<const char*>(pthread_getspecific(s_pthread_key_name));
2165 	}
2166 #endif // LOGURU_PTLS_NAMES
2167 
2168 	void get_thread_name(char* buffer, unsigned long long length, bool right_align_hext_id)
2169 	{
2170 		CHECK_NE_F(length, 0u, "Zero length buffer in get_thread_name");
2171 		CHECK_NOTNULL_F(buffer, "nullptr in get_thread_name");
2172 #if LOGURU_PTHREADS
2173 		auto thread = pthread_self();
2174 		#if LOGURU_PTLS_NAMES
2175 			if (const char* name = get_thread_name_ptls()) {
2176 				snprintf(buffer, length, "%s", name);
2177 			} else {
2178 				buffer[0] = 0;
2179 			}
2180 		#elif defined(__APPLE__) || defined(__linux__)
2181 			pthread_getname_np(thread, buffer, length);
2182 		#else
2183 			buffer[0] = 0;
2184 		#endif
2185 
2186 		if (buffer[0] == 0) {
2187 			#ifdef __APPLE__
2188 				uint64_t thread_id;
2189 				pthread_threadid_np(thread, &thread_id);
2190 			#elif defined(__DragonFly__)
2191 				uint64_t thread_id = thread;
2192 			#elif defined(__FreeBSD__)
2193 				long thread_id;
2194 				(void)thr_self(&thread_id);
2195 			#elif defined(__OpenBSD__)
2196 				unsigned thread_id = -1;
2197 			#else
2198 				uint64_t thread_id = thread;
2199 			#endif
2200 			if (right_align_hext_id) {
2201 				snprintf(buffer, length, "%*X", length - 1, static_cast<unsigned>(thread_id));
2202 			} else {
2203 				snprintf(buffer, length, "%X", static_cast<unsigned>(thread_id));
2204 			}
2205 		}
2206 #elif LOGURU_WINTHREADS
2207 		if (const char* name = get_thread_name_win32()) {
2208 			snprintf(buffer, (size_t)length, "%s", name);
2209 		} else {
2210 			buffer[0] = 0;
2211 		}
2212 #else // !LOGURU_WINTHREADS && !LOGURU_WINTHREADS
2213 		buffer[0] = 0;
2214 #endif
2215 
2216 	}
2217 
2218 	// ------------------------------------------------------------------------
2219 	// Stack traces
2220 
2221 #if LOGURU_STACKTRACES
2222 	Text demangle(const char* name)
2223 	{
2224 		int status = -1;
2225 		char* demangled = abi::__cxa_demangle(name, 0, 0, &status);
2226 		Text result{status == 0 ? demangled : strdup(name)};
2227 		return result;
2228 	}
2229 
2230 	#if LOGURU_RTTI
2231 		template <class T>
2232 		std::string type_name()
2233 		{
2234 			auto demangled = demangle(typeid(T).name());
2235 			return demangled.c_str();
2236 		}
2237 	#endif // LOGURU_RTTI
2238 
2239 	static const StringPairList REPLACE_LIST = {
2240 		#if LOGURU_RTTI
2241 			{ type_name<std::string>(),    "std::string"    },
2242 			{ type_name<std::wstring>(),   "std::wstring"   },
2243 			{ type_name<std::u16string>(), "std::u16string" },
2244 			{ type_name<std::u32string>(), "std::u32string" },
2245 		#endif // LOGURU_RTTI
2246 		{ "std::__1::",                "std::"          },
2247 		{ "__thiscall ",               ""               },
2248 		{ "__cdecl ",                  ""               },
2249 	};
2250 
2251 	void do_replacements(const StringPairList& replacements, std::string& str)
2252 	{
2253 		for (auto&& p : replacements) {
2254 			if (p.first.size() <= p.second.size()) {
2255 				// On gcc, "type_name<std::string>()" is "std::string"
2256 				continue;
2257 			}
2258 
2259 			size_t it;
2260 			while ((it=str.find(p.first)) != std::string::npos) {
2261 				str.replace(it, p.first.size(), p.second);
2262 			}
2263 		}
2264 	}
2265 
2266 	std::string prettify_stacktrace(const std::string& input)
2267 	{
2268 		std::string output = input;
2269 
2270 		do_replacements(s_user_stack_cleanups, output);
2271 		do_replacements(REPLACE_LIST, output);
2272 
2273 		try {
2274 			std::regex std_allocator_re(R"(,\s*std::allocator<[^<>]+>)");
2275 			output = std::regex_replace(output, std_allocator_re, std::string(""));
2276 
2277 			std::regex template_spaces_re(R"(<\s*([^<> ]+)\s*>)");
2278 			output = std::regex_replace(output, template_spaces_re, std::string("<$1>"));
2279 		} catch (std::regex_error&) {
2280 			// Probably old GCC.
2281 		}
2282 
2283 		return output;
2284 	}
2285 
2286 	std::string stacktrace_as_stdstring(int skip)
2287 	{
2288 		// From https://gist.github.com/fmela/591333
2289 		void* callstack[128];
2290 		const auto max_frames = sizeof(callstack) / sizeof(callstack[0]);
2291 		int num_frames = backtrace(callstack, max_frames);
2292 		char** symbols = backtrace_symbols(callstack, num_frames);
2293 
2294 		std::string result;
2295 		// Print stack traces so the most relevant ones are written last
2296 		// Rationale: http://yellerapp.com/posts/2015-01-22-upside-down-stacktraces.html
2297 		for (int i = num_frames - 1; i >= skip; --i) {
2298 			char buf[1024];
2299 			Dl_info info;
2300 			if (dladdr(callstack[i], &info) && info.dli_sname) {
2301 				char* demangled = NULL;
2302 				int status = -1;
2303 				if (info.dli_sname[0] == '_') {
2304 					demangled = abi::__cxa_demangle(info.dli_sname, 0, 0, &status);
2305 				}
2306 				snprintf(buf, sizeof(buf), "%-3d %*p %s + %zd\n",
2307 						 i - skip, int(2 + sizeof(void*) * 2), callstack[i],
2308 						 status == 0 ? demangled :
2309 						 info.dli_sname == 0 ? symbols[i] : info.dli_sname,
2310 						 static_cast<char*>(callstack[i]) - static_cast<char*>(info.dli_saddr));
2311 				free(demangled);
2312 			} else {
2313 				snprintf(buf, sizeof(buf), "%-3d %*p %s\n",
2314 						 i - skip, int(2 + sizeof(void*) * 2), callstack[i], symbols[i]);
2315 			}
2316 			result += buf;
2317 		}
2318 		free(symbols);
2319 
2320 		if (num_frames == max_frames) {
2321 			result = "[truncated]\n" + result;
2322 		}
2323 
2324 		if (!result.empty() && result[result.size() - 1] == '\n') {
2325 			result.resize(result.size() - 1);
2326 		}
2327 
2328 		return prettify_stacktrace(result);
2329 	}
2330 
2331 #else // LOGURU_STACKTRACES
2332 	Text demangle(const char* name)
2333 	{
2334 		return Text(strdup(name));
2335 	}
2336 
2337 	std::string stacktrace_as_stdstring(int)
2338 	{
2339 		// No stacktraces available on this platform"
2340 		return "";
2341 	}
2342 
2343 #endif // LOGURU_STACKTRACES
2344 
2345 	Text stacktrace(int skip)
2346 	{
2347 		auto str = stacktrace_as_stdstring(skip + 1);
2348 		return Text(strdup(str.c_str()));
2349 	}
2350 
2351 	// ------------------------------------------------------------------------
2352 
2353 	static void print_preamble_header(char* out_buff, size_t out_buff_size)
2354 	{
2355 		long pos = 0;
2356 		snprintf(out_buff, out_buff_size, ""); // Make sure there is a '\0' and handle out_buff_size==0
2357 		if (g_preamble_date) {
2358 			pos += snprintf(out_buff + pos, out_buff_size - pos, "date       ");
2359 		}
2360 		if (g_preamble_time) {
2361 			pos += snprintf(out_buff + pos, out_buff_size - pos, "time         ");
2362 		}
2363 		if (g_preamble_uptime) {
2364 			pos += snprintf(out_buff + pos, out_buff_size - pos, "( uptime  ) ");
2365 		}
2366 		if (g_preamble_thread) {
2367 			pos += snprintf(out_buff + pos, out_buff_size - pos, "[%-*s]", LOGURU_THREADNAME_WIDTH, " thread name/id");
2368 		}
2369 		if (g_preamble_file) {
2370 			pos += snprintf(out_buff + pos, out_buff_size - pos, "%*s:line  ", LOGURU_FILENAME_WIDTH, "file");
2371 		}
2372 		if (g_preamble_verbose) {
2373 			pos += snprintf(out_buff + pos, out_buff_size - pos, "   v");
2374 		}
2375 		if (g_preamble_pipe) {
2376 			pos += snprintf(out_buff + pos, out_buff_size - pos, "| ");
2377 		}
2378 	}
2379 
2380 	static void print_preamble(char* out_buff, size_t out_buff_size, Verbosity verbosity, const char* file, unsigned line)
2381 	{
2382 		if (!g_preamble) {
2383 			out_buff[0] = '\0';
2384 			return;
2385 		}
2386 		long long ms_since_epoch = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
2387 		time_t sec_since_epoch = time_t(ms_since_epoch / 1000);
2388 		tm time_info;
2389 		localtime_r(&sec_since_epoch, &time_info);
2390 
2391 		auto uptime_ms = duration_cast<milliseconds>(steady_clock::now() - s_start_time).count();
2392 		auto uptime_sec = uptime_ms / 1000.0;
2393 
2394 		char thread_name[LOGURU_THREADNAME_WIDTH + 1] = {0};
2395 		get_thread_name(thread_name, LOGURU_THREADNAME_WIDTH + 1, true);
2396 
2397 		if (s_strip_file_path) {
2398 			file = filename(file);
2399 		}
2400 
2401 		char level_buff[6];
2402 		if (verbosity <= Verbosity_FATAL) {
2403 			snprintf(level_buff, sizeof(level_buff) - 1, "FATL");
2404 		} else if (verbosity == Verbosity_ERROR) {
2405 			snprintf(level_buff, sizeof(level_buff) - 1, "ERR");
2406 		} else if (verbosity == Verbosity_WARNING) {
2407 			snprintf(level_buff, sizeof(level_buff) - 1, "WARN");
2408 		} else {
2409 			snprintf(level_buff, sizeof(level_buff) - 1, "% 4d", verbosity);
2410 		}
2411 
2412 		long pos = 0;
2413 
2414 		snprintf(out_buff, out_buff_size, ""); // Make sure there is a '\0' and handle out_buff_size==0
2415 		if (g_preamble_date) {
2416 			pos += snprintf(out_buff + pos, out_buff_size - pos, "%04d-%02d-%02d ",
2417 				             1900 + time_info.tm_year, 1 + time_info.tm_mon, time_info.tm_mday);
2418 		}
2419 		if (g_preamble_time) {
2420 			pos += snprintf(out_buff + pos, out_buff_size - pos, "%02d:%02d:%02d.%03lld ",
2421 			               time_info.tm_hour, time_info.tm_min, time_info.tm_sec, ms_since_epoch % 1000);
2422 		}
2423 		if (g_preamble_uptime) {
2424 			pos += snprintf(out_buff + pos, out_buff_size - pos, "(%8.3fs) ",
2425 			               uptime_sec);
2426 		}
2427 		if (g_preamble_thread) {
2428 			pos += snprintf(out_buff + pos, out_buff_size - pos, "[%-*s]",
2429 			               LOGURU_THREADNAME_WIDTH, thread_name);
2430 		}
2431 		if (g_preamble_file) {
2432 			pos += snprintf(out_buff + pos, out_buff_size - pos, "%*s:%-5u ",
2433 			               LOGURU_FILENAME_WIDTH, file, line);
2434 		}
2435 		if (g_preamble_verbose) {
2436 			pos += snprintf(out_buff + pos, out_buff_size - pos, "%4s",
2437 			               level_buff);
2438 		}
2439 		if (g_preamble_pipe) {
2440 			pos += snprintf(out_buff + pos, out_buff_size - pos, "| ");
2441 		}
2442 	}
2443 
2444 	// stack_trace_skip is just if verbosity == FATAL.
2445 	static void log_message(int stack_trace_skip, Message& message, bool with_indentation, bool abort_if_fatal)
2446 	{
2447 		const auto verbosity = message.verbosity;
2448 		std::lock_guard<std::recursive_mutex> lock(s_mutex);
2449 
2450 		if (message.verbosity == Verbosity_FATAL) {
2451 			auto st = loguru::stacktrace(stack_trace_skip + 2);
2452 			if (!st.empty()) {
2453 				RAW_LOG_F(ERROR, "Stack trace:\n%s", st.c_str());
2454 			}
2455 
2456 			auto ec = loguru::get_error_context();
2457 			if (!ec.empty()) {
2458 				RAW_LOG_F(ERROR, "%s", ec.c_str());
2459 			}
2460 		}
2461 
2462 		if (with_indentation) {
2463 			message.indentation = indentation(s_stderr_indentation);
2464 		}
2465 
2466 		if (verbosity <= g_stderr_verbosity) {
2467 			if (g_colorlogtostderr && s_terminal_has_color) {
2468 				if (verbosity > Verbosity_WARNING) {
2469 					fprintf(stderr, "%s%s%s%s%s%s%s%s%s\n",
2470 						terminal_reset(),
2471 						terminal_dim(),
2472 						message.preamble,
2473 						message.indentation,
2474 						terminal_reset(),
2475 						verbosity == Verbosity_INFO ? terminal_bold() : terminal_light_gray(),
2476 						message.prefix,
2477 						message.message,
2478 						terminal_reset());
2479 				} else {
2480 					fprintf(stderr, "%s%s%s%s%s%s%s%s\n",
2481 						terminal_reset(),
2482 						terminal_bold(),
2483 						verbosity == Verbosity_WARNING ? terminal_red() : terminal_light_red(),
2484 						message.preamble,
2485 						message.indentation,
2486 						message.prefix,
2487 						message.message,
2488 						terminal_reset());
2489 				}
2490 			} else {
2491 				fprintf(stderr, "%s%s%s%s\n",
2492 					message.preamble, message.indentation, message.prefix, message.message);
2493 			}
2494 
2495 			if (g_flush_interval_ms == 0) {
2496 				fflush(stderr);
2497 			} else {
2498 				s_needs_flushing = true;
2499 			}
2500 		}
2501 
2502 		for (auto& p : s_callbacks) {
2503 			if (verbosity <= p.verbosity) {
2504 				if (with_indentation) {
2505 					message.indentation = indentation(p.indentation);
2506 				}
2507 				p.callback(p.user_data, message);
2508 				if (g_flush_interval_ms == 0) {
2509 					if (p.flush) { p.flush(p.user_data); }
2510 				} else {
2511 					s_needs_flushing = true;
2512 				}
2513 			}
2514 		}
2515 
2516 		if (g_flush_interval_ms > 0 && !s_flush_thread) {
2517 			s_flush_thread = new std::thread([](){
2518 				for (;;) {
2519 					if (s_needs_flushing) {
2520 						flush();
2521 					}
2522 					std::this_thread::sleep_for(std::chrono::milliseconds(g_flush_interval_ms));
2523 				}
2524 			});
2525 		}
2526 
2527 		if (message.verbosity == Verbosity_FATAL) {
2528 			flush();
2529 
2530 			if (s_fatal_handler) {
2531 				s_fatal_handler(message);
2532 				flush();
2533 			}
2534 
2535 			if (abort_if_fatal) {
2536 #if LOGURU_CATCH_SIGABRT && !defined(_WIN32)
2537 				// Make sure we don't catch our own abort:
2538 				signal(SIGABRT, SIG_DFL);
2539 #endif
2540 				abort();
2541 			}
2542 		}
2543 	}
2544 
2545 	// stack_trace_skip is just if verbosity == FATAL.
2546 	void log_to_everywhere(int stack_trace_skip, Verbosity verbosity,
2547 	                       const char* file, unsigned line,
2548 	                       const char* prefix, const char* buff)
2549 	{
2550 		char preamble_buff[LOGURU_PREAMBLE_WIDTH];
2551 		print_preamble(preamble_buff, sizeof(preamble_buff), verbosity, file, line);
2552 		auto message = Message{verbosity, file, line, preamble_buff, "", prefix, buff};
2553 		log_message(stack_trace_skip + 1, message, true, true);
2554 	}
2555 
2556 #if LOGURU_USE_FMTLIB
2557 	void log(Verbosity verbosity, const char* file, unsigned line, const char* format, fmt::ArgList args)
2558 	{
2559 		auto formatted = fmt::format(format, args);
2560 		log_to_everywhere(1, verbosity, file, line, "", formatted.c_str());
2561 	}
2562 
2563 	void raw_log(Verbosity verbosity, const char* file, unsigned line, const char* format, fmt::ArgList args)
2564 	{
2565 		auto formatted = fmt::format(format, args);
2566 		auto message = Message{verbosity, file, line, "", "", "", formatted.c_str()};
2567 		log_message(1, message, false, true);
2568 	}
2569 
2570 #else
2571 	void log(Verbosity verbosity, const char* file, unsigned line, const char* format, ...)
2572 	{
2573 		va_list vlist;
2574 		va_start(vlist, format);
2575 		auto buff = vtextprintf(format, vlist);
2576 		log_to_everywhere(1, verbosity, file, line, "", buff.c_str());
2577 		va_end(vlist);
2578 	}
2579 
2580 	void raw_log(Verbosity verbosity, const char* file, unsigned line, const char* format, ...)
2581 	{
2582 		va_list vlist;
2583 		va_start(vlist, format);
2584 		auto buff = vtextprintf(format, vlist);
2585 		auto message = Message{verbosity, file, line, "", "", "", buff.c_str()};
2586 		log_message(1, message, false, true);
2587 		va_end(vlist);
2588 	}
2589 #endif
2590 
2591 	void flush()
2592 	{
2593 		std::lock_guard<std::recursive_mutex> lock(s_mutex);
2594 		fflush(stderr);
2595 		for (const auto& callback : s_callbacks)
2596 		{
2597 			if (callback.flush) {
2598 				callback.flush(callback.user_data);
2599 			}
2600 		}
2601 		s_needs_flushing = false;
2602 	}
2603 
2604 	LogScopeRAII::LogScopeRAII(Verbosity verbosity, const char* file, unsigned line, const char* format, ...)
2605 		: _verbosity(verbosity), _file(file), _line(line)
2606 	{
2607 		if (verbosity <= current_verbosity_cutoff()) {
2608 			std::lock_guard<std::recursive_mutex> lock(s_mutex);
2609 			_indent_stderr = (verbosity <= g_stderr_verbosity);
2610 			_start_time_ns = now_ns();
2611 			va_list vlist;
2612 			va_start(vlist, format);
2613 			vsnprintf(_name, sizeof(_name), format, vlist);
2614 			log_to_everywhere(1, _verbosity, file, line, "{ ", _name);
2615 			va_end(vlist);
2616 
2617 			if (_indent_stderr) {
2618 				++s_stderr_indentation;
2619 			}
2620 
2621 			for (auto& p : s_callbacks) {
2622 				if (verbosity <= p.verbosity) {
2623 					++p.indentation;
2624 				}
2625 			}
2626 		} else {
2627 			_file = nullptr;
2628 		}
2629 	}
2630 
2631 	LogScopeRAII::~LogScopeRAII()
2632 	{
2633 		if (_file) {
2634 			std::lock_guard<std::recursive_mutex> lock(s_mutex);
2635 			if (_indent_stderr && s_stderr_indentation > 0) {
2636 				--s_stderr_indentation;
2637 			}
2638 			for (auto& p : s_callbacks) {
2639 				// Note: Callback indentation cannot change!
2640 				if (_verbosity <= p.verbosity) {
2641 					// in unlikely case this callback is new
2642 					if (p.indentation > 0) {
2643 						--p.indentation;
2644 					}
2645 				}
2646 			}
2647 			auto duration_sec = (now_ns() - _start_time_ns) / 1e9;
2648 			auto buff = textprintf("%.*f s: %s", SCOPE_TIME_PRECISION, duration_sec, _name);
2649 			log_to_everywhere(1, _verbosity, _file, _line, "} ", buff.c_str());
2650 		}
2651 	}
2652 
2653 	void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line, const char* format, ...)
2654 	{
2655 		va_list vlist;
2656 		va_start(vlist, format);
2657 		auto buff = vtextprintf(format, vlist);
2658 		log_to_everywhere(stack_trace_skip + 1, Verbosity_FATAL, file, line, expr, buff.c_str());
2659 		va_end(vlist);
2660 		abort(); // log_to_everywhere already does this, but this makes the analyzer happy.
2661 	}
2662 
2663 	void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line)
2664 	{
2665 		log_and_abort(stack_trace_skip + 1, expr, file, line, " ");
2666 	}
2667 
2668 	// ----------------------------------------------------------------------------
2669 	// Streams:
2670 
2671 	std::string vstrprintf(const char* format, va_list vlist)
2672 	{
2673 		auto text = vtextprintf(format, vlist);
2674 		std::string result = text.c_str();
2675 		return result;
2676 	}
2677 
2678 	std::string strprintf(const char* format, ...)
2679 	{
2680 		va_list vlist;
2681 		va_start(vlist, format);
2682 		auto result = vstrprintf(format, vlist);
2683 		va_end(vlist);
2684 		return result;
2685 	}
2686 
2687 	#if LOGURU_WITH_STREAMS
2688 
2689 	StreamLogger::~StreamLogger() noexcept(false)
2690 	{
2691 		auto message = _ss.str();
2692 		log(_verbosity, _file, _line, "%s", message.c_str());
2693 	}
2694 
2695 	AbortLogger::~AbortLogger() noexcept(false)
2696 	{
2697 		auto message = _ss.str();
2698 		loguru::log_and_abort(1, _expr, _file, _line, "%s", message.c_str());
2699 	}
2700 
2701 	#endif // LOGURU_WITH_STREAMS
2702 
2703 	// ----------------------------------------------------------------------------
2704 	// 888888 88""Yb 88""Yb  dP"Yb  88""Yb      dP""b8  dP"Yb  88b 88 888888 888888 Yb  dP 888888
2705 	// 88__   88__dP 88__dP dP   Yb 88__dP     dP   `" dP   Yb 88Yb88   88   88__    YbdP    88
2706 	// 88""   88"Yb  88"Yb  Yb   dP 88"Yb      Yb      Yb   dP 88 Y88   88   88""    dPYb    88
2707 	// 888888 88  Yb 88  Yb  YbodP  88  Yb      YboodP  YbodP  88  Y8   88   888888 dP  Yb   88
2708 	// ----------------------------------------------------------------------------
2709 
2710 	struct StringStream
2711 	{
2712 		std::string str;
2713 	};
2714 
2715 	// Use this in your EcPrinter implementations.
2716 	void stream_print(StringStream& out_string_stream, const char* text)
2717 	{
2718 		out_string_stream.str += text;
2719 	}
2720 
2721 	// ----------------------------------------------------------------------------
2722 
2723 	using ECPtr = EcEntryBase*;
2724 
2725 #if defined(_WIN32) || (defined(__APPLE__) && !TARGET_OS_IPHONE)
2726 	#ifdef __APPLE__
2727 		#define LOGURU_THREAD_LOCAL __thread
2728 	#else
2729 		#define LOGURU_THREAD_LOCAL thread_local
2730 	#endif
2731 	static LOGURU_THREAD_LOCAL ECPtr thread_ec_ptr = nullptr;
2732 
2733 	ECPtr& get_thread_ec_head_ref()
2734 	{
2735 		return thread_ec_ptr;
2736 	}
2737 #else // !thread_local
2738 	static pthread_once_t s_ec_pthread_once = PTHREAD_ONCE_INIT;
2739 	static pthread_key_t  s_ec_pthread_key;
2740 
2741 	void free_ec_head_ref(void* io_error_context)
2742 	{
2743 		delete reinterpret_cast<ECPtr*>(io_error_context);
2744 	}
2745 
2746 	void ec_make_pthread_key()
2747 	{
2748 		(void)pthread_key_create(&s_ec_pthread_key, free_ec_head_ref);
2749 	}
2750 
2751 	ECPtr& get_thread_ec_head_ref()
2752 	{
2753 		(void)pthread_once(&s_ec_pthread_once, ec_make_pthread_key);
2754 		auto ec = reinterpret_cast<ECPtr*>(pthread_getspecific(s_ec_pthread_key));
2755 		if (ec == nullptr) {
2756 			ec = new ECPtr(nullptr);
2757 			(void)pthread_setspecific(s_ec_pthread_key, ec);
2758 		}
2759 		return *ec;
2760 	}
2761 #endif // !thread_local
2762 
2763 	// ----------------------------------------------------------------------------
2764 
2765 	EcHandle get_thread_ec_handle()
2766 	{
2767 		return get_thread_ec_head_ref();
2768 	}
2769 
2770 	Text get_error_context()
2771 	{
2772 		return get_error_context_for(get_thread_ec_head_ref());
2773 	}
2774 
2775 	Text get_error_context_for(const EcEntryBase* ec_head)
2776 	{
2777 		std::vector<const EcEntryBase*> stack;
2778 		while (ec_head) {
2779 			stack.push_back(ec_head);
2780 			ec_head = ec_head->_previous;
2781 		}
2782 		std::reverse(stack.begin(), stack.end());
2783 
2784 		StringStream result;
2785 		if (!stack.empty()) {
2786 			result.str += "------------------------------------------------\n";
2787 			for (auto entry : stack) {
2788 				const auto description = std::string(entry->_descr) + ":";
2789 				auto prefix = textprintf("[ErrorContext] %*s:%-5u %-20s ",
2790 					LOGURU_FILENAME_WIDTH, filename(entry->_file), entry->_line, description.c_str());
2791 				result.str += prefix.c_str();
2792 				entry->print_value(result);
2793 				result.str += "\n";
2794 			}
2795 			result.str += "------------------------------------------------";
2796 		}
2797 		return Text(strdup(result.str.c_str()));
2798 	}
2799 
2800 	EcEntryBase::EcEntryBase(const char* file, unsigned line, const char* descr)
2801 		: _file(file), _line(line), _descr(descr)
2802 	{
2803 		EcEntryBase*& ec_head = get_thread_ec_head_ref();
2804 		_previous = ec_head;
2805 		ec_head = this;
2806 	}
2807 
2808 	EcEntryBase::~EcEntryBase()
2809 	{
2810 		get_thread_ec_head_ref() = _previous;
2811 	}
2812 
2813 	// ------------------------------------------------------------------------
2814 
2815 	Text ec_to_text(const char* value)
2816 	{
2817 		// Add quotes around the string to make it obvious where it begin and ends.
2818 		// This is great for detecting erroneous leading or trailing spaces in e.g. an identifier.
2819 		auto str = "\"" + std::string(value) + "\"";
2820 		return Text{strdup(str.c_str())};
2821 	}
2822 
2823 	Text ec_to_text(char c)
2824 	{
2825 		// Add quotes around the character to make it obvious where it begin and ends.
2826 		std::string str = "'";
2827 
2828 		auto write_hex_digit = [&](unsigned num)
2829 		{
2830 			if (num < 10u) { str += char('0' + num); }
2831 			else           { str += char('a' + num - 10); }
2832 		};
2833 
2834 		auto write_hex_16 = [&](uint16_t n)
2835 		{
2836 			write_hex_digit((n >> 12u) & 0x0f);
2837 			write_hex_digit((n >>  8u) & 0x0f);
2838 			write_hex_digit((n >>  4u) & 0x0f);
2839 			write_hex_digit((n >>  0u) & 0x0f);
2840 		};
2841 
2842 		if      (c == '\\') { str += "\\\\"; }
2843 		else if (c == '\"') { str += "\\\""; }
2844 		else if (c == '\'') { str += "\\\'"; }
2845 		else if (c == '\0') { str += "\\0";  }
2846 		else if (c == '\b') { str += "\\b";  }
2847 		else if (c == '\f') { str += "\\f";  }
2848 		else if (c == '\n') { str += "\\n";  }
2849 		else if (c == '\r') { str += "\\r";  }
2850 		else if (c == '\t') { str += "\\t";  }
2851 		else if (0 <= c && c < 0x20) {
2852 			str += "\\u";
2853 			write_hex_16(static_cast<uint16_t>(c));
2854 		} else { str += c; }
2855 
2856 		str += "'";
2857 
2858 		return Text{strdup(str.c_str())};
2859 	}
2860 
2861 	#define DEFINE_EC(Type)                        \
2862 		Text ec_to_text(Type value)                \
2863 		{                                          \
2864 			auto str = std::to_string(value);      \
2865 			return Text{strdup(str.c_str())};      \
2866 		}
2867 
2868 	DEFINE_EC(int)
2869 	DEFINE_EC(unsigned int)
2870 	DEFINE_EC(long)
2871 	DEFINE_EC(unsigned long)
2872 	DEFINE_EC(long long)
2873 	DEFINE_EC(unsigned long long)
2874 	DEFINE_EC(float)
2875 	DEFINE_EC(double)
2876 	DEFINE_EC(long double)
2877 
2878 	#undef DEFINE_EC
2879 
2880 	Text ec_to_text(EcHandle ec_handle)
2881 	{
2882 		Text parent_ec = get_error_context_for(ec_handle);
2883 		char* with_newline = (char*)malloc(strlen(parent_ec.c_str()) + 2);
2884 		with_newline[0] = '\n';
2885 		strcpy(with_newline + 1, parent_ec.c_str());
2886 		return Text(with_newline);
2887 	}
2888 
2889 	// ----------------------------------------------------------------------------
2890 
2891 } // namespace loguru
2892 
2893 // ----------------------------------------------------------------------------
2894 // .dP"Y8 88  dP""b8 88b 88    db    88     .dP"Y8
2895 // `Ybo." 88 dP   `" 88Yb88   dPYb   88     `Ybo."
2896 // o.`Y8b 88 Yb  "88 88 Y88  dP__Yb  88  .o o.`Y8b
2897 // 8bodP' 88  YboodP 88  Y8 dP""""Yb 88ood8 8bodP'
2898 // ----------------------------------------------------------------------------
2899 
2900 #ifdef _WIN32
2901 namespace loguru {
install_signal_handlers()2902 	void install_signal_handlers()
2903 	{
2904 		#if defined(_MSC_VER)
2905 		#pragma message ( "No signal handlers on Win32" )
2906 		#else
2907 		#warning "No signal handlers on Win32"
2908 		#endif
2909 	}
2910 } // namespace loguru
2911 
2912 #else // _WIN32
2913 
2914 namespace loguru
2915 {
2916 	struct Signal
2917 	{
2918 		int         number;
2919 		const char* name;
2920 	};
2921 	const Signal ALL_SIGNALS[] = {
2922 #if LOGURU_CATCH_SIGABRT
2923 		{ SIGABRT, "SIGABRT" },
2924 #endif
2925 		{ SIGBUS,  "SIGBUS"  },
2926 		{ SIGFPE,  "SIGFPE"  },
2927 		{ SIGILL,  "SIGILL"  },
2928 		{ SIGINT,  "SIGINT"  },
2929 		{ SIGSEGV, "SIGSEGV" },
2930 		{ SIGTERM, "SIGTERM" },
2931 	};
2932 
write_to_stderr(const char * data,size_t size)2933 	void write_to_stderr(const char* data, size_t size)
2934 	{
2935 		auto result = write(STDERR_FILENO, data, size);
2936 		(void)result; // Ignore errors.
2937 	}
2938 
write_to_stderr(const char * data)2939 	void write_to_stderr(const char* data)
2940 	{
2941 		write_to_stderr(data, strlen(data));
2942 	}
2943 
call_default_signal_handler(int signal_number)2944 	void call_default_signal_handler(int signal_number)
2945 	{
2946 		struct sigaction sig_action;
2947 		memset(&sig_action, 0, sizeof(sig_action));
2948 		sigemptyset(&sig_action.sa_mask);
2949 		sig_action.sa_handler = SIG_DFL;
2950 		sigaction(signal_number, &sig_action, NULL);
2951 		kill(getpid(), signal_number);
2952 	}
2953 
signal_handler(int signal_number,siginfo_t *,void *)2954 	void signal_handler(int signal_number, siginfo_t*, void*)
2955 	{
2956 		const char* signal_name = "UNKNOWN SIGNAL";
2957 
2958 		for (const auto& s : ALL_SIGNALS) {
2959 			if (s.number == signal_number) {
2960 				signal_name = s.name;
2961 				break;
2962 			}
2963 		}
2964 
2965 		// --------------------------------------------------------------------
2966 		/* There are few things that are safe to do in a signal handler,
2967 		   but writing to stderr is one of them.
2968 		   So we first print out what happened to stderr so we're sure that gets out,
2969 		   then we do the unsafe things, like logging the stack trace.
2970 		*/
2971 
2972 		if (g_colorlogtostderr && s_terminal_has_color) {
2973 			write_to_stderr(terminal_reset());
2974 			write_to_stderr(terminal_bold());
2975 			write_to_stderr(terminal_light_red());
2976 		}
2977 		write_to_stderr("\n");
2978 		write_to_stderr("Loguru caught a signal: ");
2979 		write_to_stderr(signal_name);
2980 		write_to_stderr("\n");
2981 		if (g_colorlogtostderr && s_terminal_has_color) {
2982 			write_to_stderr(terminal_reset());
2983 		}
2984 
2985 		// --------------------------------------------------------------------
2986 
2987 #if LOGURU_UNSAFE_SIGNAL_HANDLER
2988 		// --------------------------------------------------------------------
2989 		/* Now we do unsafe things. This can for example lead to deadlocks if
2990 		   the signal was triggered from the system's memory management functions
2991 		   and the code below tries to do allocations.
2992 		*/
2993 
2994 		flush();
2995 		char preamble_buff[LOGURU_PREAMBLE_WIDTH];
2996 		print_preamble(preamble_buff, sizeof(preamble_buff), Verbosity_FATAL, "", 0);
2997 		auto message = Message{Verbosity_FATAL, "", 0, preamble_buff, "", "Signal: ", signal_name};
2998 		try {
2999 			log_message(1, message, false, false);
3000 		} catch (...) {
3001 			// This can happed due to s_fatal_handler.
3002 			write_to_stderr("Exception caught and ignored by Loguru signal handler.\n");
3003 		}
3004 		flush();
3005 
3006 		// --------------------------------------------------------------------
3007 #endif // LOGURU_UNSAFE_SIGNAL_HANDLER
3008 
3009 		call_default_signal_handler(signal_number);
3010 	}
3011 
install_signal_handlers()3012 	void install_signal_handlers()
3013 	{
3014 		struct sigaction sig_action;
3015 		memset(&sig_action, 0, sizeof(sig_action));
3016 		sigemptyset(&sig_action.sa_mask);
3017 		sig_action.sa_flags |= SA_SIGINFO;
3018 		sig_action.sa_sigaction = &signal_handler;
3019 		for (const auto& s : ALL_SIGNALS) {
3020 			CHECK_F(sigaction(s.number, &sig_action, NULL) != -1,
3021 				"Failed to install handler for %s", s.name);
3022 		}
3023 	}
3024 } // namespace loguru
3025 
3026 #endif // _WIN32
3027 
3028 #endif // LOGURU_IMPLEMENTATION
3029