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