1 //
2 //  Bismillah ar-Rahmaan ar-Raheem
3 //
4 //  Easylogging++ v9.96.4
5 //  Single-header only, cross-platform logging library for C++ applications
6 //
7 //  Copyright (c) 2012-2018 Muflihun Labs
8 //  Copyright (c) 2012-2018 @abumusamq
9 //
10 //  This library is released under the MIT Licence.
11 //  https://github.com/muflihun/easyloggingpp/blob/master/LICENSE
12 //
13 //  https://github.com/muflihun/easyloggingpp
14 //  https://muflihun.github.io/easyloggingpp
15 //  http://muflihun.com
16 //
17 
18 #ifndef EASYLOGGINGPP_H
19 #define EASYLOGGINGPP_H
20 // Compilers and C++0x/C++11 Evaluation
21 #if __cplusplus >= 201103L
22 #  define ELPP_CXX11 1
23 #endif  // __cplusplus >= 201103L
24 #if (defined(__GNUC__))
25 #  define ELPP_COMPILER_GCC 1
26 #else
27 #  define ELPP_COMPILER_GCC 0
28 #endif
29 #if ELPP_COMPILER_GCC
30 #    define ELPP_GCC_VERSION (__GNUC__ * 10000 \
31 + __GNUC_MINOR__ * 100 \
32 + __GNUC_PATCHLEVEL__)
33 #  if defined(__GXX_EXPERIMENTAL_CXX0X__)
34 #    define ELPP_CXX0X 1
35 #  endif
36 #endif
37 // Visual C++
38 #if defined(_MSC_VER)
39 #  define ELPP_COMPILER_MSVC 1
40 #else
41 #  define ELPP_COMPILER_MSVC 0
42 #endif
43 #define ELPP_CRT_DBG_WARNINGS ELPP_COMPILER_MSVC
44 #if ELPP_COMPILER_MSVC
45 #  if (_MSC_VER == 1600)
46 #    define ELPP_CXX0X 1
47 #  elif(_MSC_VER >= 1700)
48 #    define ELPP_CXX11 1
49 #  endif
50 #endif
51 // Clang++
52 #if (defined(__clang__) && (__clang__ == 1))
53 #  define ELPP_COMPILER_CLANG 1
54 #else
55 #  define ELPP_COMPILER_CLANG 0
56 #endif
57 #if ELPP_COMPILER_CLANG
58 #  if __has_include(<thread>)
59 #    include <cstddef> // Make __GLIBCXX__ defined when using libstdc++
60 #    if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426
61 #      define ELPP_CLANG_SUPPORTS_THREAD
62 #    endif // !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426
63 #  endif // __has_include(<thread>)
64 #endif
65 #if (defined(__MINGW32__) || defined(__MINGW64__))
66 #  define ELPP_MINGW 1
67 #else
68 #  define ELPP_MINGW 0
69 #endif
70 #if (defined(__CYGWIN__) && (__CYGWIN__ == 1))
71 #  define ELPP_CYGWIN 1
72 #else
73 #  define ELPP_CYGWIN 0
74 #endif
75 #if (defined(__INTEL_COMPILER))
76 #  define ELPP_COMPILER_INTEL 1
77 #else
78 #  define ELPP_COMPILER_INTEL 0
79 #endif
80 // Operating System Evaluation
81 // Windows
82 #if (defined(_WIN32) || defined(_WIN64))
83 #  define ELPP_OS_WINDOWS 1
84 #else
85 #  define ELPP_OS_WINDOWS 0
86 #endif
87 // Linux
88 #if (defined(__linux) || defined(__linux__))
89 #  define ELPP_OS_LINUX 1
90 #else
91 #  define ELPP_OS_LINUX 0
92 #endif
93 #if (defined(__APPLE__))
94 #  define ELPP_OS_MAC 1
95 #else
96 #  define ELPP_OS_MAC 0
97 #endif
98 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
99 #  define ELPP_OS_FREEBSD 1
100 #else
101 #  define ELPP_OS_FREEBSD 0
102 #endif
103 #if (defined(__sun))
104 #  define ELPP_OS_SOLARIS 1
105 #else
106 #  define ELPP_OS_SOLARIS 0
107 #endif
108 #if (defined(_AIX))
109 #  define ELPP_OS_AIX 1
110 #else
111 #  define ELPP_OS_AIX 0
112 #endif
113 #if (defined(__NetBSD__))
114 #  define ELPP_OS_NETBSD 1
115 #else
116 #  define ELPP_OS_NETBSD 0
117 #endif
118 // Unix
119 #if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_NETBSD || ELPP_OS_SOLARIS || ELPP_OS_AIX) && (!ELPP_OS_WINDOWS))
120 #  define ELPP_OS_UNIX 1
121 #else
122 #  define ELPP_OS_UNIX 0
123 #endif
124 #if (defined(__ANDROID__))
125 #  define ELPP_OS_ANDROID 1
126 #else
127 #  define ELPP_OS_ANDROID 0
128 #endif
129 // Evaluating Cygwin as *nix OS
130 #if !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN
131 #  undef ELPP_OS_UNIX
132 #  undef ELPP_OS_LINUX
133 #  define ELPP_OS_UNIX 1
134 #  define ELPP_OS_LINUX 1
135 #endif //  !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN
136 #if !defined(ELPP_INTERNAL_DEBUGGING_OUT_INFO)
137 #  define ELPP_INTERNAL_DEBUGGING_OUT_INFO std::cout
138 #endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
139 #if !defined(ELPP_INTERNAL_DEBUGGING_OUT_ERROR)
140 #  define ELPP_INTERNAL_DEBUGGING_OUT_ERROR std::cerr
141 #endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
142 #if !defined(ELPP_INTERNAL_DEBUGGING_ENDL)
143 #  define ELPP_INTERNAL_DEBUGGING_ENDL std::endl
144 #endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
145 #if !defined(ELPP_INTERNAL_DEBUGGING_MSG)
146 #  define ELPP_INTERNAL_DEBUGGING_MSG(msg) msg
147 #endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
148 // Internal Assertions and errors
149 #if !defined(ELPP_DISABLE_ASSERT)
150 #  if (defined(ELPP_DEBUG_ASSERT_FAILURE))
151 #    define ELPP_ASSERT(expr, msg) if (!(expr)) { \
152 std::stringstream internalInfoStream; internalInfoStream << msg; \
153 ELPP_INTERNAL_DEBUGGING_OUT_ERROR \
154 << "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" \
155 << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" << ELPP_INTERNAL_DEBUGGING_ENDL; base::utils::abort(1, \
156 "ELPP Assertion failure, please define ELPP_DEBUG_ASSERT_FAILURE"); }
157 #  else
158 #    define ELPP_ASSERT(expr, msg) if (!(expr)) { \
159 std::stringstream internalInfoStream; internalInfoStream << msg; \
160 ELPP_INTERNAL_DEBUGGING_OUT_ERROR\
161 << "ASSERTION FAILURE FROM EASYLOGGING++ (LINE: " \
162 << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" \
163 << ELPP_INTERNAL_DEBUGGING_ENDL; }
164 #  endif  // (defined(ELPP_DEBUG_ASSERT_FAILURE))
165 #else
166 #  define ELPP_ASSERT(x, y)
167 #endif  //(!defined(ELPP_DISABLE_ASSERT)
168 #if ELPP_COMPILER_MSVC
169 #  define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \
170 { char buff[256]; strerror_s(buff, 256, errno); \
171 ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << buff << " [" << errno << "]";} (void)0
172 #else
173 #  define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \
174 ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << strerror(errno) << " [" << errno << "]"; (void)0
175 #endif  // ELPP_COMPILER_MSVC
176 #if defined(ELPP_DEBUG_ERRORS)
177 #  if !defined(ELPP_INTERNAL_ERROR)
178 #    define ELPP_INTERNAL_ERROR(msg, pe) { \
179 std::stringstream internalInfoStream; internalInfoStream << "<ERROR> " << msg; \
180 ELPP_INTERNAL_DEBUGGING_OUT_ERROR \
181 << "ERROR FROM EASYLOGGING++ (LINE: " << __LINE__ << ") " \
182 << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << ELPP_INTERNAL_DEBUGGING_ENDL; \
183 if (pe) { ELPP_INTERNAL_DEBUGGING_OUT_ERROR << "    "; ELPP_INTERNAL_DEBUGGING_WRITE_PERROR; }} (void)0
184 #  endif
185 #else
186 #  undef ELPP_INTERNAL_INFO
187 #  define ELPP_INTERNAL_ERROR(msg, pe)
188 #endif  // defined(ELPP_DEBUG_ERRORS)
189 #if (defined(ELPP_DEBUG_INFO))
190 #  if !(defined(ELPP_INTERNAL_INFO_LEVEL))
191 #    define ELPP_INTERNAL_INFO_LEVEL 9
192 #  endif  // !(defined(ELPP_INTERNAL_INFO_LEVEL))
193 #  if !defined(ELPP_INTERNAL_INFO)
194 #    define ELPP_INTERNAL_INFO(lvl, msg) { if (lvl <= ELPP_INTERNAL_INFO_LEVEL) { \
195 std::stringstream internalInfoStream; internalInfoStream << "<INFO> " << msg; \
196 ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) \
197 << ELPP_INTERNAL_DEBUGGING_ENDL; }}
198 #  endif
199 #else
200 #  undef ELPP_INTERNAL_INFO
201 #  define ELPP_INTERNAL_INFO(lvl, msg)
202 #endif  // (defined(ELPP_DEBUG_INFO))
203 #if (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG))
204 #  if (ELPP_COMPILER_GCC && !ELPP_MINGW && !ELPP_OS_ANDROID)
205 #    define ELPP_STACKTRACE 1
206 #  else
207 #      if ELPP_COMPILER_MSVC
208 #         pragma message("Stack trace not available for this compiler")
209 #      else
210 #         warning "Stack trace not available for this compiler";
211 #      endif  // ELPP_COMPILER_MSVC
212 #    define ELPP_STACKTRACE 0
213 #  endif  // ELPP_COMPILER_GCC
214 #else
215 #    define ELPP_STACKTRACE 0
216 #endif  // (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG))
217 // Miscellaneous macros
218 #define ELPP_UNUSED(x) (void)x
219 #if ELPP_OS_UNIX
220 // Log file permissions for unix-based systems
221 #  define ELPP_LOG_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH
222 #endif  // ELPP_OS_UNIX
223 #if defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC
224 #  if defined(ELPP_EXPORT_SYMBOLS)
225 #    define ELPP_EXPORT __declspec(dllexport)
226 #  else
227 #    define ELPP_EXPORT __declspec(dllimport)
228 #  endif  // defined(ELPP_EXPORT_SYMBOLS)
229 #else
230 #  define ELPP_EXPORT
231 #endif  // defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC
232 // Some special functions that are VC++ specific
233 #undef STRTOK
234 #undef STRERROR
235 #undef STRCAT
236 #undef STRCPY
237 #if ELPP_CRT_DBG_WARNINGS
238 #  define STRTOK(a, b, c) strtok_s(a, b, c)
239 #  define STRERROR(a, b, c) strerror_s(a, b, c)
240 #  define STRCAT(a, b, len) strcat_s(a, len, b)
241 #  define STRCPY(a, b, len) strcpy_s(a, len, b)
242 #else
243 #  define STRTOK(a, b, c) strtok(a, b)
244 #  define STRERROR(a, b, c) strerror(c)
245 #  define STRCAT(a, b, len) strcat(a, b)
246 #  define STRCPY(a, b, len) strcpy(a, b)
247 #endif
248 // Compiler specific support evaluations
249 #if (ELPP_MINGW && !defined(ELPP_FORCE_USE_STD_THREAD))
250 #  define ELPP_USE_STD_THREADING 0
251 #else
252 #  if ((ELPP_COMPILER_CLANG && defined(ELPP_CLANG_SUPPORTS_THREAD)) || \
253        (!ELPP_COMPILER_CLANG && defined(ELPP_CXX11)) || \
254        defined(ELPP_FORCE_USE_STD_THREAD))
255 #    define ELPP_USE_STD_THREADING 1
256 #  else
257 #    define ELPP_USE_STD_THREADING 0
258 #  endif
259 #endif
260 #undef ELPP_FINAL
261 #if ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702)
262 #  define ELPP_FINAL
263 #else
264 #  define ELPP_FINAL final
265 #endif  // ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702)
266 #if defined(ELPP_EXPERIMENTAL_ASYNC)
267 #  define ELPP_ASYNC_LOGGING 1
268 #else
269 #  define ELPP_ASYNC_LOGGING 0
270 #endif // defined(ELPP_EXPERIMENTAL_ASYNC)
271 #if defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING
272 #  define ELPP_THREADING_ENABLED 1
273 #else
274 #  define ELPP_THREADING_ENABLED 0
275 #endif  // defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING
276 // Function macro ELPP_FUNC
277 #undef ELPP_FUNC
278 #if ELPP_COMPILER_MSVC  // Visual C++
279 #  define ELPP_FUNC __FUNCSIG__
280 #elif ELPP_COMPILER_GCC  // GCC
281 #  define ELPP_FUNC __PRETTY_FUNCTION__
282 #elif ELPP_COMPILER_INTEL  // Intel C++
283 #  define ELPP_FUNC __PRETTY_FUNCTION__
284 #elif ELPP_COMPILER_CLANG  // Clang++
285 #  define ELPP_FUNC __PRETTY_FUNCTION__
286 #else
287 #  if defined(__func__)
288 #    define ELPP_FUNC __func__
289 #  else
290 #    define ELPP_FUNC ""
291 #  endif  // defined(__func__)
292 #endif  // defined(_MSC_VER)
293 #undef ELPP_VARIADIC_TEMPLATES_SUPPORTED
294 // Keep following line commented until features are fixed
295 #define ELPP_VARIADIC_TEMPLATES_SUPPORTED \
296 (ELPP_COMPILER_GCC || ELPP_COMPILER_CLANG || ELPP_COMPILER_INTEL || (ELPP_COMPILER_MSVC && _MSC_VER >= 1800))
297 // Logging Enable/Disable macros
298 #if defined(ELPP_DISABLE_LOGS)
299 #define ELPP_LOGGING_ENABLED 0
300 #else
301 #define ELPP_LOGGING_ENABLED 1
302 #endif
303 #if (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED))
304 #  define ELPP_DEBUG_LOG 1
305 #else
306 #  define ELPP_DEBUG_LOG 0
307 #endif  // (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED))
308 #if (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))
309 #  define ELPP_INFO_LOG 1
310 #else
311 #  define ELPP_INFO_LOG 0
312 #endif  // (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))
313 #if (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))
314 #  define ELPP_WARNING_LOG 1
315 #else
316 #  define ELPP_WARNING_LOG 0
317 #endif  // (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))
318 #if (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))
319 #  define ELPP_ERROR_LOG 1
320 #else
321 #  define ELPP_ERROR_LOG 0
322 #endif  // (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))
323 #if (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))
324 #  define ELPP_FATAL_LOG 1
325 #else
326 #  define ELPP_FATAL_LOG 0
327 #endif  // (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))
328 #if (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))
329 #  define ELPP_TRACE_LOG 1
330 #else
331 #  define ELPP_TRACE_LOG 0
332 #endif  // (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))
333 #if (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED))
334 #  define ELPP_VERBOSE_LOG 1
335 #else
336 #  define ELPP_VERBOSE_LOG 0
337 #endif  // (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED))
338 #if (!(ELPP_CXX0X || ELPP_CXX11))
339 #   error "C++0x (or higher) support not detected! (Is `-std=c++11' missing?)"
340 #endif  // (!(ELPP_CXX0X || ELPP_CXX11))
341 // Headers
342 #if defined(ELPP_SYSLOG)
343 #   include <syslog.h>
344 #endif  // defined(ELPP_SYSLOG)
345 #include <ctime>
346 #include <cstring>
347 #include <cstdlib>
348 #include <cctype>
349 #include <cwchar>
350 #include <csignal>
351 #include <cerrno>
352 #include <cstdarg>
353 #if defined(ELPP_UNICODE)
354 #   include <locale>
355 #  if ELPP_OS_WINDOWS
356 #      include <codecvt>
357 #  endif // ELPP_OS_WINDOWS
358 #endif  // defined(ELPP_UNICODE)
359 #if ELPP_STACKTRACE
360 #   include <cxxabi.h>
361 #   include <execinfo.h>
362 #endif  // ELPP_STACKTRACE
363 #if ELPP_OS_ANDROID
364 #   include <sys/system_properties.h>
365 #endif  // ELPP_OS_ANDROID
366 #if ELPP_OS_UNIX
367 #   include <sys/stat.h>
368 #   include <sys/time.h>
369 #elif ELPP_OS_WINDOWS
370 #   include <direct.h>
371 #   include <windows.h>
372 #  if defined(WIN32_LEAN_AND_MEAN)
373 #      if defined(ELPP_WINSOCK2)
374 #         include <winsock2.h>
375 #      else
376 #         include <winsock.h>
377 #      endif // defined(ELPP_WINSOCK2)
378 #  endif // defined(WIN32_LEAN_AND_MEAN)
379 #endif  // ELPP_OS_UNIX
380 #include <string>
381 #include <vector>
382 #include <map>
383 #include <unordered_map>
384 #include <utility>
385 #include <functional>
386 #include <algorithm>
387 #include <fstream>
388 #include <iostream>
389 #include <sstream>
390 #include <memory>
391 #include <type_traits>
392 #if ELPP_THREADING_ENABLED
393 #  if ELPP_USE_STD_THREADING
394 #      include <mutex>
395 #      include <thread>
396 #  else
397 #      if ELPP_OS_UNIX
398 #         include <pthread.h>
399 #      endif  // ELPP_OS_UNIX
400 #  endif  // ELPP_USE_STD_THREADING
401 #endif  // ELPP_THREADING_ENABLED
402 #if ELPP_ASYNC_LOGGING
403 #  if defined(ELPP_NO_SLEEP_FOR)
404 #      include <unistd.h>
405 #  endif  // defined(ELPP_NO_SLEEP_FOR)
406 #   include <thread>
407 #   include <queue>
408 #   include <condition_variable>
409 #endif  // ELPP_ASYNC_LOGGING
410 #if defined(ELPP_STL_LOGGING)
411 // For logging STL based templates
412 #   include <list>
413 #   include <queue>
414 #   include <deque>
415 #   include <set>
416 #   include <bitset>
417 #   include <stack>
418 #  if defined(ELPP_LOG_STD_ARRAY)
419 #      include <array>
420 #  endif  // defined(ELPP_LOG_STD_ARRAY)
421 #  if defined(ELPP_LOG_UNORDERED_SET)
422 #      include <unordered_set>
423 #  endif  // defined(ELPP_UNORDERED_SET)
424 #endif  // defined(ELPP_STL_LOGGING)
425 #if defined(ELPP_QT_LOGGING)
426 // For logging Qt based classes & templates
427 #   include <QString>
428 #   include <QByteArray>
429 #   include <QVector>
430 #   include <QList>
431 #   include <QPair>
432 #   include <QMap>
433 #   include <QQueue>
434 #   include <QSet>
435 #   include <QLinkedList>
436 #   include <QHash>
437 #   include <QMultiHash>
438 #   include <QStack>
439 #endif  // defined(ELPP_QT_LOGGING)
440 #if defined(ELPP_BOOST_LOGGING)
441 // For logging boost based classes & templates
442 #   include <boost/container/vector.hpp>
443 #   include <boost/container/stable_vector.hpp>
444 #   include <boost/container/list.hpp>
445 #   include <boost/container/deque.hpp>
446 #   include <boost/container/map.hpp>
447 #   include <boost/container/flat_map.hpp>
448 #   include <boost/container/set.hpp>
449 #   include <boost/container/flat_set.hpp>
450 #endif  // defined(ELPP_BOOST_LOGGING)
451 #if defined(ELPP_WXWIDGETS_LOGGING)
452 // For logging wxWidgets based classes & templates
453 #   include <wx/vector.h>
454 #endif  // defined(ELPP_WXWIDGETS_LOGGING)
455 #if defined(ELPP_UTC_DATETIME)
456 #   define elpptime_r gmtime_r
457 #   define elpptime_s gmtime_s
458 #   define elpptime   gmtime
459 #else
460 #   define elpptime_r localtime_r
461 #   define elpptime_s localtime_s
462 #   define elpptime   localtime
463 #endif  // defined(ELPP_UTC_DATETIME)
464 // Forward declarations
465 namespace el {
466 class Logger;
467 class LogMessage;
468 class PerformanceTrackingData;
469 class Loggers;
470 class Helpers;
471 template <typename T> class Callback;
472 class LogDispatchCallback;
473 class PerformanceTrackingCallback;
474 class LoggerRegistrationCallback;
475 class LogDispatchData;
476 namespace base {
477 class Storage;
478 class RegisteredLoggers;
479 class PerformanceTracker;
480 class MessageBuilder;
481 class Writer;
482 class PErrorWriter;
483 class LogDispatcher;
484 class DefaultLogBuilder;
485 class DefaultLogDispatchCallback;
486 #if ELPP_ASYNC_LOGGING
487 class AsyncLogDispatchCallback;
488 class AsyncDispatchWorker;
489 #endif // ELPP_ASYNC_LOGGING
490 class DefaultPerformanceTrackingCallback;
491 }  // namespace base
492 }  // namespace el
493 /// @brief Easylogging++ entry namespace
494 namespace el {
495 /// @brief Namespace containing base/internal functionality used by Easylogging++
496 namespace base {
497 /// @brief Data types used by Easylogging++
498 namespace type {
499 #undef ELPP_LITERAL
500 #undef ELPP_STRLEN
501 #undef ELPP_COUT
502 #if defined(ELPP_UNICODE)
503 #  define ELPP_LITERAL(txt) L##txt
504 #  define ELPP_STRLEN wcslen
505 #  if defined ELPP_CUSTOM_COUT
506 #    define ELPP_COUT ELPP_CUSTOM_COUT
507 #  else
508 #    define ELPP_COUT std::wcout
509 #  endif  // defined ELPP_CUSTOM_COUT
510 typedef wchar_t char_t;
511 typedef std::wstring string_t;
512 typedef std::wstringstream stringstream_t;
513 typedef std::wfstream fstream_t;
514 typedef std::wostream ostream_t;
515 #else
516 #  define ELPP_LITERAL(txt) txt
517 #  define ELPP_STRLEN strlen
518 #  if defined ELPP_CUSTOM_COUT
519 #    define ELPP_COUT ELPP_CUSTOM_COUT
520 #  else
521 #    define ELPP_COUT std::cout
522 #  endif  // defined ELPP_CUSTOM_COUT
523 typedef char char_t;
524 typedef std::string string_t;
525 typedef std::stringstream stringstream_t;
526 typedef std::fstream fstream_t;
527 typedef std::ostream ostream_t;
528 #endif  // defined(ELPP_UNICODE)
529 #if defined(ELPP_CUSTOM_COUT_LINE)
530 #  define ELPP_COUT_LINE(logLine) ELPP_CUSTOM_COUT_LINE(logLine)
531 #else
532 #  define ELPP_COUT_LINE(logLine) logLine << std::flush
533 #endif // defined(ELPP_CUSTOM_COUT_LINE)
534 typedef unsigned int EnumType;
535 typedef unsigned short VerboseLevel;
536 typedef unsigned long int LineNumber;
537 typedef std::shared_ptr<base::Storage> StoragePointer;
538 typedef std::shared_ptr<LogDispatchCallback> LogDispatchCallbackPtr;
539 typedef std::shared_ptr<PerformanceTrackingCallback> PerformanceTrackingCallbackPtr;
540 typedef std::shared_ptr<LoggerRegistrationCallback> LoggerRegistrationCallbackPtr;
541 typedef std::unique_ptr<el::base::PerformanceTracker> PerformanceTrackerPtr;
542 }  // namespace type
543 /// @brief Internal helper class that prevent copy constructor for class
544 ///
545 /// @detail When using this class simply inherit it privately
546 class NoCopy {
547  protected:
NoCopy(void)548   NoCopy(void) {}
549  private:
550   NoCopy(const NoCopy&);
551   NoCopy& operator=(const NoCopy&);
552 };
553 /// @brief Internal helper class that makes all default constructors private.
554 ///
555 /// @detail This prevents initializing class making it static unless an explicit constructor is declared.
556 /// When using this class simply inherit it privately
557 class StaticClass {
558  private:
559   StaticClass(void);
560   StaticClass(const StaticClass&);
561   StaticClass& operator=(const StaticClass&);
562 };
563 }  // namespace base
564 /// @brief Represents enumeration for severity level used to determine level of logging
565 ///
566 /// @detail With Easylogging++, developers may disable or enable any level regardless of
567 /// what the severity is. Or they can choose to log using hierarchical logging flag
568 enum class Level : base::type::EnumType {
569   /// @brief Generic level that represents all the levels. Useful when setting global configuration for all levels
570   Global = 1,
571   /// @brief Information that can be useful to back-trace certain events - mostly useful than debug logs.
572   Trace = 2,
573   /// @brief Informational events most useful for developers to debug application
574   Debug = 4,
575   /// @brief Severe error information that will presumably abort application
576   Fatal = 8,
577   /// @brief Information representing errors in application but application will keep running
578   Error = 16,
579   /// @brief Useful when application has potentially harmful situtaions
580   Warning = 32,
581   /// @brief Information that can be highly useful and vary with verbose logging level.
582   Verbose = 64,
583   /// @brief Mainly useful to represent current progress of application
584   Info = 128,
585   /// @brief Represents unknown level
586   Unknown = 1010
587 };
588 } // namespace el
589 namespace std {
590 template<> struct hash<el::Level> {
591  public:
592   std::size_t operator()(const el::Level& l) const {
593     return hash<el::base::type::EnumType> {}(static_cast<el::base::type::EnumType>(l));
594   }
595 };
596 }
597 namespace el {
598 /// @brief Static class that contains helper functions for el::Level
599 class LevelHelper : base::StaticClass {
600  public:
601   /// @brief Represents minimum valid level. Useful when iterating through enum.
602   static const base::type::EnumType kMinValid = static_cast<base::type::EnumType>(Level::Trace);
603   /// @brief Represents maximum valid level. This is used internally and you should not need it.
604   static const base::type::EnumType kMaxValid = static_cast<base::type::EnumType>(Level::Info);
605   /// @brief Casts level to int, useful for iterating through enum.
606   static base::type::EnumType castToInt(Level level) {
607     return static_cast<base::type::EnumType>(level);
608   }
609   /// @brief Casts int(ushort) to level, useful for iterating through enum.
610   static Level castFromInt(base::type::EnumType l) {
611     return static_cast<Level>(l);
612   }
613   /// @brief Converts level to associated const char*
614   /// @return Upper case string based level.
615   static const char* convertToString(Level level);
616   /// @brief Converts from levelStr to Level
617   /// @param levelStr Upper case string based level.
618   ///        Lower case is also valid but providing upper case is recommended.
619   static Level convertFromString(const char* levelStr);
620   /// @brief Applies specified function to each level starting from startIndex
621   /// @param startIndex initial value to start the iteration from. This is passed as pointer and
622   ///        is left-shifted so this can be used inside function (fn) to represent current level.
623   /// @param fn function to apply with each level. This bool represent whether or not to stop iterating through levels.
624   static void forEachLevel(base::type::EnumType* startIndex, const std::function<bool(void)>& fn);
625 };
626 /// @brief Represents enumeration of ConfigurationType used to configure or access certain aspect
627 /// of logging
628 enum class ConfigurationType : base::type::EnumType {
629   /// @brief Determines whether or not corresponding level and logger of logging is enabled
630   /// You may disable all logs by using el::Level::Global
631   Enabled = 1,
632   /// @brief Whether or not to write corresponding log to log file
633   ToFile = 2,
634   /// @brief Whether or not to write corresponding level and logger log to standard output.
635   /// By standard output meaning termnal, command prompt etc
636   ToStandardOutput = 4,
637   /// @brief Determines format of logging corresponding level and logger.
638   Format = 8,
639   /// @brief Determines log file (full path) to write logs to for correponding level and logger
640   Filename = 16,
641   /// @brief Specifies precision of the subsecond part. It should be within range (1-6).
642   SubsecondPrecision = 32,
643   /// @brief Alias of SubsecondPrecision (for backward compatibility)
644   MillisecondsWidth = SubsecondPrecision,
645   /// @brief Determines whether or not performance tracking is enabled.
646   ///
647   /// @detail This does not depend on logger or level. Performance tracking always uses 'performance' logger
648   PerformanceTracking = 64,
649   /// @brief Specifies log file max size.
650   ///
651   /// @detail If file size of corresponding log file (for corresponding level) is >= specified size, log file will
652   /// be truncated and re-initiated.
653   MaxLogFileSize = 128,
654   /// @brief Specifies number of log entries to hold until we flush pending log data
655   LogFlushThreshold = 256,
656   /// @brief Represents unknown configuration
657   Unknown = 1010
658 };
659 /// @brief Static class that contains helper functions for el::ConfigurationType
660 class ConfigurationTypeHelper : base::StaticClass {
661  public:
662   /// @brief Represents minimum valid configuration type. Useful when iterating through enum.
663   static const base::type::EnumType kMinValid = static_cast<base::type::EnumType>(ConfigurationType::Enabled);
664   /// @brief Represents maximum valid configuration type. This is used internally and you should not need it.
665   static const base::type::EnumType kMaxValid = static_cast<base::type::EnumType>(ConfigurationType::MaxLogFileSize);
666   /// @brief Casts configuration type to int, useful for iterating through enum.
667   static base::type::EnumType castToInt(ConfigurationType configurationType) {
668     return static_cast<base::type::EnumType>(configurationType);
669   }
670   /// @brief Casts int(ushort) to configurationt type, useful for iterating through enum.
671   static ConfigurationType castFromInt(base::type::EnumType c) {
672     return static_cast<ConfigurationType>(c);
673   }
674   /// @brief Converts configuration type to associated const char*
675   /// @returns Upper case string based configuration type.
676   static const char* convertToString(ConfigurationType configurationType);
677   /// @brief Converts from configStr to ConfigurationType
678   /// @param configStr Upper case string based configuration type.
679   ///        Lower case is also valid but providing upper case is recommended.
680   static ConfigurationType convertFromString(const char* configStr);
681   /// @brief Applies specified function to each configuration type starting from startIndex
682   /// @param startIndex initial value to start the iteration from. This is passed by pointer and is left-shifted
683   ///        so this can be used inside function (fn) to represent current configuration type.
684   /// @param fn function to apply with each configuration type.
685   ///        This bool represent whether or not to stop iterating through configurations.
686   static inline void forEachConfigType(base::type::EnumType* startIndex, const std::function<bool(void)>& fn);
687 };
688 /// @brief Flags used while writing logs. This flags are set by user
689 enum class LoggingFlag : base::type::EnumType {
690   /// @brief Makes sure we have new line for each container log entry
691   NewLineForContainer = 1,
692   /// @brief Makes sure if -vmodule is used and does not specifies a module, then verbose
693   /// logging is allowed via that module.
694   AllowVerboseIfModuleNotSpecified = 2,
695   /// @brief When handling crashes by default, detailed crash reason will be logged as well
696   LogDetailedCrashReason = 4,
697   /// @brief Allows to disable application abortion when logged using FATAL level
698   DisableApplicationAbortOnFatalLog = 8,
699   /// @brief Flushes log with every log-entry (performance sensative) - Disabled by default
700   ImmediateFlush = 16,
701   /// @brief Enables strict file rolling
702   StrictLogFileSizeCheck = 32,
703   /// @brief Make terminal output colorful for supported terminals
704   ColoredTerminalOutput = 64,
705   /// @brief Supports use of multiple logging in same macro, e.g, CLOG(INFO, "default", "network")
706   MultiLoggerSupport = 128,
707   /// @brief Disables comparing performance tracker's checkpoints
708   DisablePerformanceTrackingCheckpointComparison = 256,
709   /// @brief Disable VModules
710   DisableVModules = 512,
711   /// @brief Disable VModules extensions
712   DisableVModulesExtensions = 1024,
713   /// @brief Enables hierarchical logging
714   HierarchicalLogging = 2048,
715   /// @brief Creates logger automatically when not available
716   CreateLoggerAutomatically = 4096,
717   /// @brief Adds spaces b/w logs that separated by left-shift operator
718   AutoSpacing = 8192,
719   /// @brief Preserves time format and does not convert it to sec, hour etc (performance tracking only)
720   FixedTimeFormat = 16384
721 };
722 namespace base {
723 /// @brief Namespace containing constants used internally.
724 namespace consts {
725 static const char  kFormatSpecifierCharValue               =      'v';
726 static const char  kFormatSpecifierChar                    =      '%';
727 static const unsigned int kMaxLogPerCounter                =      100000;
728 static const unsigned int kMaxLogPerContainer              =      100;
729 static const unsigned int kDefaultSubsecondPrecision       =      3;
730 
731 #ifdef ELPP_DEFAULT_LOGGER
732 static const char* kDefaultLoggerId                        =      ELPP_DEFAULT_LOGGER;
733 #else
734 static const char* kDefaultLoggerId                        =      "default";
735 #endif
736 
737 #ifdef ELPP_DEFAULT_PERFORMANCE_LOGGER
738 static const char* kPerformanceLoggerId                    =      ELPP_DEFAULT_PERFORMANCE_LOGGER;
739 #endif
740 
741 #if defined(ELPP_SYSLOG)
742 static const char* kSysLogLoggerId                         =      "syslog";
743 #endif  // defined(ELPP_SYSLOG)
744 
745 #if ELPP_OS_WINDOWS
746 static const char* kFilePathSeperator                      =      "\\";
747 #else
748 static const char* kFilePathSeperator                      =      "/";
749 #endif  // ELPP_OS_WINDOWS
750 
751 static const std::size_t kSourceFilenameMaxLength          =      100;
752 static const std::size_t kSourceLineMaxLength              =      10;
753 static const Level kPerformanceTrackerDefaultLevel         =      Level::Info;
754 const struct {
755   double value;
756   const base::type::char_t* unit;
757 } kTimeFormats[] = {
758   { 1000.0f, ELPP_LITERAL("us") },
759   { 1000.0f, ELPP_LITERAL("ms") },
760   { 60.0f, ELPP_LITERAL("seconds") },
761   { 60.0f, ELPP_LITERAL("minutes") },
762   { 24.0f, ELPP_LITERAL("hours") },
763   { 7.0f, ELPP_LITERAL("days") }
764 };
765 static const int kTimeFormatsCount                           =      sizeof(kTimeFormats) / sizeof(kTimeFormats[0]);
766 const struct {
767   int numb;
768   const char* name;
769   const char* brief;
770   const char* detail;
771 } kCrashSignals[] = {
772   // NOTE: Do not re-order, if you do please check CrashHandler(bool) constructor and CrashHandler::setHandler(..)
773   {
774     SIGABRT, "SIGABRT", "Abnormal termination",
775     "Program was abnormally terminated."
776   },
777   {
778     SIGFPE, "SIGFPE", "Erroneous arithmetic operation",
779     "Arithemetic operation issue such as division by zero or operation resulting in overflow."
780   },
781   {
782     SIGILL, "SIGILL", "Illegal instruction",
783     "Generally due to a corruption in the code or to an attempt to execute data."
784   },
785   {
786     SIGSEGV, "SIGSEGV", "Invalid access to memory",
787     "Program is trying to read an invalid (unallocated, deleted or corrupted) or inaccessible memory."
788   },
789   {
790     SIGINT, "SIGINT", "Interactive attention signal",
791     "Interruption generated (generally) by user or operating system."
792   },
793 };
794 static const int kCrashSignalsCount                          =      sizeof(kCrashSignals) / sizeof(kCrashSignals[0]);
795 }  // namespace consts
796 }  // namespace base
797 typedef std::function<void(const char*, std::size_t)> PreRollOutCallback;
798 namespace base {
799 static inline void defaultPreRollOutCallback(const char*, std::size_t) {}
800 /// @brief Enum to represent timestamp unit
801 enum class TimestampUnit : base::type::EnumType {
802   Microsecond = 0, Millisecond = 1, Second = 2, Minute = 3, Hour = 4, Day = 5
803 };
804 /// @brief Format flags used to determine specifiers that are active for performance improvements.
805 enum class FormatFlags : base::type::EnumType {
806   DateTime = 1 << 1,
807   LoggerId = 1 << 2,
808   File = 1 << 3,
809   Line = 1 << 4,
810   Location = 1 << 5,
811   Function = 1 << 6,
812   User = 1 << 7,
813   Host = 1 << 8,
814   LogMessage = 1 << 9,
815   VerboseLevel = 1 << 10,
816   AppName = 1 << 11,
817   ThreadId = 1 << 12,
818   Level = 1 << 13,
819   FileBase = 1 << 14,
820   LevelShort = 1 << 15
821 };
822 /// @brief A subsecond precision class containing actual width and offset of the subsecond part
823 class SubsecondPrecision {
824  public:
825   SubsecondPrecision(void) {
826     init(base::consts::kDefaultSubsecondPrecision);
827   }
828   explicit SubsecondPrecision(int width) {
829     init(width);
830   }
831   bool operator==(const SubsecondPrecision& ssPrec) {
832     return m_width == ssPrec.m_width && m_offset == ssPrec.m_offset;
833   }
834   int m_width;
835   unsigned int m_offset;
836  private:
837   void init(int width);
838 };
839 /// @brief Type alias of SubsecondPrecision
840 typedef SubsecondPrecision MillisecondsWidth;
841 /// @brief Namespace containing utility functions/static classes used internally
842 namespace utils {
843 /// @brief Deletes memory safely and points to null
844 template <typename T>
845 static
846 typename std::enable_if<std::is_pointer<T*>::value, void>::type
847 safeDelete(T*& pointer) {
848   if (pointer == nullptr)
849     return;
850   delete pointer;
851   pointer = nullptr;
852 }
853 /// @brief Bitwise operations for C++11 strong enum class. This casts e into Flag_T and returns value after bitwise operation
854 /// Use these function as <pre>flag = bitwise::Or<MyEnum>(MyEnum::val1, flag);</pre>
855 namespace bitwise {
856 template <typename Enum>
857 static inline base::type::EnumType And(Enum e, base::type::EnumType flag) {
858   return static_cast<base::type::EnumType>(flag) & static_cast<base::type::EnumType>(e);
859 }
860 template <typename Enum>
861 static inline base::type::EnumType Not(Enum e, base::type::EnumType flag) {
862   return static_cast<base::type::EnumType>(flag) & ~(static_cast<base::type::EnumType>(e));
863 }
864 template <typename Enum>
865 static inline base::type::EnumType Or(Enum e, base::type::EnumType flag) {
866   return static_cast<base::type::EnumType>(flag) | static_cast<base::type::EnumType>(e);
867 }
868 }  // namespace bitwise
869 template <typename Enum>
870 static inline void addFlag(Enum e, base::type::EnumType* flag) {
871   *flag = base::utils::bitwise::Or<Enum>(e, *flag);
872 }
873 template <typename Enum>
874 static inline void removeFlag(Enum e, base::type::EnumType* flag) {
875   *flag = base::utils::bitwise::Not<Enum>(e, *flag);
876 }
877 template <typename Enum>
878 static inline bool hasFlag(Enum e, base::type::EnumType flag) {
879   return base::utils::bitwise::And<Enum>(e, flag) > 0x0;
880 }
881 }  // namespace utils
882 namespace threading {
883 #if ELPP_THREADING_ENABLED
884 #  if !ELPP_USE_STD_THREADING
885 namespace internal {
886 /// @brief A mutex wrapper for compiler that dont yet support std::recursive_mutex
887 class Mutex : base::NoCopy {
888  public:
889   Mutex(void) {
890 #  if ELPP_OS_UNIX
891     pthread_mutexattr_t attr;
892     pthread_mutexattr_init(&attr);
893     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
894     pthread_mutex_init(&m_underlyingMutex, &attr);
895     pthread_mutexattr_destroy(&attr);
896 #  elif ELPP_OS_WINDOWS
897     InitializeCriticalSection(&m_underlyingMutex);
898 #  endif  // ELPP_OS_UNIX
899   }
900 
901   virtual ~Mutex(void) {
902 #  if ELPP_OS_UNIX
903     pthread_mutex_destroy(&m_underlyingMutex);
904 #  elif ELPP_OS_WINDOWS
905     DeleteCriticalSection(&m_underlyingMutex);
906 #  endif  // ELPP_OS_UNIX
907   }
908 
909   inline void lock(void) {
910 #  if ELPP_OS_UNIX
911     pthread_mutex_lock(&m_underlyingMutex);
912 #  elif ELPP_OS_WINDOWS
913     EnterCriticalSection(&m_underlyingMutex);
914 #  endif  // ELPP_OS_UNIX
915   }
916 
917   inline bool try_lock(void) {
918 #  if ELPP_OS_UNIX
919     return (pthread_mutex_trylock(&m_underlyingMutex) == 0);
920 #  elif ELPP_OS_WINDOWS
921     return TryEnterCriticalSection(&m_underlyingMutex);
922 #  endif  // ELPP_OS_UNIX
923   }
924 
925   inline void unlock(void) {
926 #  if ELPP_OS_UNIX
927     pthread_mutex_unlock(&m_underlyingMutex);
928 #  elif ELPP_OS_WINDOWS
929     LeaveCriticalSection(&m_underlyingMutex);
930 #  endif  // ELPP_OS_UNIX
931   }
932 
933  private:
934 #  if ELPP_OS_UNIX
935   pthread_mutex_t m_underlyingMutex;
936 #  elif ELPP_OS_WINDOWS
937   CRITICAL_SECTION m_underlyingMutex;
938 #  endif  // ELPP_OS_UNIX
939 };
940 /// @brief Scoped lock for compiler that dont yet support std::lock_guard
941 template <typename M>
942 class ScopedLock : base::NoCopy {
943  public:
944   explicit ScopedLock(M& mutex) {
945     m_mutex = &mutex;
946     m_mutex->lock();
947   }
948 
949   virtual ~ScopedLock(void) {
950     m_mutex->unlock();
951   }
952  private:
953   M* m_mutex;
954   ScopedLock(void);
955 };
956 } // namespace internal
957 typedef base::threading::internal::Mutex Mutex;
958 typedef base::threading::internal::ScopedLock<base::threading::Mutex> ScopedLock;
959 #  else
960 typedef std::recursive_mutex Mutex;
961 typedef std::lock_guard<base::threading::Mutex> ScopedLock;
962 #  endif  // !ELPP_USE_STD_THREADING
963 #else
964 namespace internal {
965 /// @brief Mutex wrapper used when multi-threading is disabled.
966 class NoMutex : base::NoCopy {
967  public:
968   NoMutex(void) {}
969   inline void lock(void) {}
970   inline bool try_lock(void) {
971     return true;
972   }
973   inline void unlock(void) {}
974 };
975 /// @brief Lock guard wrapper used when multi-threading is disabled.
976 template <typename Mutex>
977 class NoScopedLock : base::NoCopy {
978  public:
979   explicit NoScopedLock(Mutex&) {
980   }
981   virtual ~NoScopedLock(void) {
982   }
983  private:
984   NoScopedLock(void);
985 };
986 }  // namespace internal
987 typedef base::threading::internal::NoMutex Mutex;
988 typedef base::threading::internal::NoScopedLock<base::threading::Mutex> ScopedLock;
989 #endif  // ELPP_THREADING_ENABLED
990 /// @brief Base of thread safe class, this class is inheritable-only
991 class ThreadSafe {
992  public:
993   virtual inline void acquireLock(void) ELPP_FINAL { m_mutex.lock(); }
994   virtual inline void releaseLock(void) ELPP_FINAL { m_mutex.unlock(); }
995   virtual inline base::threading::Mutex& lock(void) ELPP_FINAL { return m_mutex; }
996  protected:
997   ThreadSafe(void) {}
998   virtual ~ThreadSafe(void) {}
999  private:
1000   base::threading::Mutex m_mutex;
1001 };
1002 
1003 #if ELPP_THREADING_ENABLED
1004 #  if !ELPP_USE_STD_THREADING
1005 /// @brief Gets ID of currently running threading in windows systems. On unix, nothing is returned.
1006 static std::string getCurrentThreadId(void) {
1007   std::stringstream ss;
1008 #      if (ELPP_OS_WINDOWS)
1009   ss << GetCurrentThreadId();
1010 #      endif  // (ELPP_OS_WINDOWS)
1011   return ss.str();
1012 }
1013 #  else
1014 /// @brief Gets ID of currently running threading using std::this_thread::get_id()
1015 static std::string getCurrentThreadId(void) {
1016   std::stringstream ss;
1017   ss << std::this_thread::get_id();
1018   return ss.str();
1019 }
1020 #  endif  // !ELPP_USE_STD_THREADING
1021 #else
1022 static inline std::string getCurrentThreadId(void) {
1023   return std::string();
1024 }
1025 #endif  // ELPP_THREADING_ENABLED
1026 }  // namespace threading
1027 namespace utils {
1028 class File : base::StaticClass {
1029  public:
1030   /// @brief Creates new out file stream for specified filename.
1031   /// @return Pointer to newly created fstream or nullptr
1032   static base::type::fstream_t* newFileStream(const std::string& filename);
1033 
1034   /// @brief Gets size of file provided in stream
1035   static std::size_t getSizeOfFile(base::type::fstream_t* fs);
1036 
1037   /// @brief Determines whether or not provided path exist in current file system
1038   static bool pathExists(const char* path, bool considerFile = false);
1039 
1040   /// @brief Creates specified path on file system
1041   /// @param path Path to create.
1042   static bool createPath(const std::string& path);
1043   /// @brief Extracts path of filename with leading slash
1044   static std::string extractPathFromFilename(const std::string& fullPath,
1045       const char* seperator = base::consts::kFilePathSeperator);
1046   /// @brief builds stripped filename and puts it in buff
1047   static void buildStrippedFilename(const char* filename, char buff[],
1048                                     std::size_t limit = base::consts::kSourceFilenameMaxLength);
1049   /// @brief builds base filename and puts it in buff
1050   static void buildBaseFilename(const std::string& fullPath, char buff[],
1051                                 std::size_t limit = base::consts::kSourceFilenameMaxLength,
1052                                 const char* seperator = base::consts::kFilePathSeperator);
1053 };
1054 /// @brief String utilities helper class used internally. You should not use it.
1055 class Str : base::StaticClass {
1056  public:
1057   /// @brief Checks if character is digit. Dont use libc implementation of it to prevent locale issues.
1058   static inline bool isDigit(char c) {
1059     return c >= '0' && c <= '9';
1060   }
1061 
1062   /// @brief Matches wildcards, '*' and '?' only supported.
1063   static bool wildCardMatch(const char* str, const char* pattern);
1064 
1065   static std::string& ltrim(std::string& str);
1066   static std::string& rtrim(std::string& str);
1067   static std::string& trim(std::string& str);
1068 
1069   /// @brief Determines whether or not str starts with specified string
1070   /// @param str String to check
1071   /// @param start String to check against
1072   /// @return Returns true if starts with specified string, false otherwise
1073   static bool startsWith(const std::string& str, const std::string& start);
1074 
1075   /// @brief Determines whether or not str ends with specified string
1076   /// @param str String to check
1077   /// @param end String to check against
1078   /// @return Returns true if ends with specified string, false otherwise
1079   static bool endsWith(const std::string& str, const std::string& end);
1080 
1081   /// @brief Replaces all instances of replaceWhat with 'replaceWith'. Original variable is changed for performance.
1082   /// @param [in,out] str String to replace from
1083   /// @param replaceWhat Character to replace
1084   /// @param replaceWith Character to replace with
1085   /// @return Modified version of str
1086   static std::string& replaceAll(std::string& str, char replaceWhat, char replaceWith);
1087 
1088   /// @brief Replaces all instances of 'replaceWhat' with 'replaceWith'. (String version) Replaces in place
1089   /// @param str String to replace from
1090   /// @param replaceWhat Character to replace
1091   /// @param replaceWith Character to replace with
1092   /// @return Modified (original) str
1093   static std::string& replaceAll(std::string& str, const std::string& replaceWhat,
1094                                  const std::string& replaceWith);
1095 
1096   static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat,
1097                                      const base::type::string_t& replaceWith);
1098 #if defined(ELPP_UNICODE)
1099   static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat,
1100                                      const std::string& replaceWith);
1101 #endif  // defined(ELPP_UNICODE)
1102   /// @brief Converts string to uppercase
1103   /// @param str String to convert
1104   /// @return Uppercase string
1105   static std::string& toUpper(std::string& str);
1106 
1107   /// @brief Compares cstring equality - uses strcmp
1108   static bool cStringEq(const char* s1, const char* s2);
1109 
1110   /// @brief Compares cstring equality (case-insensitive) - uses toupper(char)
1111   /// Dont use strcasecmp because of CRT (VC++)
1112   static bool cStringCaseEq(const char* s1, const char* s2);
1113 
1114   /// @brief Returns true if c exist in str
1115   static bool contains(const char* str, char c);
1116 
1117   static char* convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded = true);
1118   static char* addToBuff(const char* str, char* buf, const char* bufLim);
1119   static char* clearBuff(char buff[], std::size_t lim);
1120 
1121   /// @brief Converst wchar* to char*
1122   ///        NOTE: Need to free return value after use!
1123   static char* wcharPtrToCharPtr(const wchar_t* line);
1124 };
1125 /// @brief Operating System helper static class used internally. You should not use it.
1126 class OS : base::StaticClass {
1127  public:
1128 #if ELPP_OS_WINDOWS
1129   /// @brief Gets environment variables for Windows based OS.
1130   ///        We are not using <code>getenv(const char*)</code> because of CRT deprecation
1131   /// @param varname Variable name to get environment variable value for
1132   /// @return If variable exist the value of it otherwise nullptr
1133   static const char* getWindowsEnvironmentVariable(const char* varname);
1134 #endif  // ELPP_OS_WINDOWS
1135 #if ELPP_OS_ANDROID
1136   /// @brief Reads android property value
1137   static std::string getProperty(const char* prop);
1138 
1139   /// @brief Reads android device name
1140   static std::string getDeviceName(void);
1141 #endif  // ELPP_OS_ANDROID
1142 
1143   /// @brief Runs command on terminal and returns the output.
1144   ///
1145   /// @detail This is applicable only on unix based systems, for all other OS, an empty string is returned.
1146   /// @param command Bash command
1147   /// @return Result of bash output or empty string if no result found.
1148   static const std::string getBashOutput(const char* command);
1149 
1150   /// @brief Gets environment variable. This is cross-platform and CRT safe (for VC++)
1151   /// @param variableName Environment variable name
1152   /// @param defaultVal If no environment variable or value found the value to return by default
1153   /// @param alternativeBashCommand If environment variable not found what would be alternative bash command
1154   ///        in order to look for value user is looking for. E.g, for 'user' alternative command will 'whoami'
1155   static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal,
1156       const char* alternativeBashCommand = nullptr);
1157   /// @brief Gets current username.
1158   static std::string currentUser(void);
1159 
1160   /// @brief Gets current host name or computer name.
1161   ///
1162   /// @detail For android systems this is device name with its manufacturer and model seperated by hyphen
1163   static std::string currentHost(void);
1164   /// @brief Whether or not terminal supports colors
1165   static bool termSupportsColor(void);
1166 };
1167 /// @brief Contains utilities for cross-platform date/time. This class make use of el::base::utils::Str
1168 class DateTime : base::StaticClass {
1169  public:
1170   /// @brief Cross platform gettimeofday for Windows and unix platform. This can be used to determine current microsecond.
1171   ///
1172   /// @detail For unix system it uses gettimeofday(timeval*, timezone*) and for Windows, a seperate implementation is provided
1173   /// @param [in,out] tv Pointer that gets updated
1174   static void gettimeofday(struct timeval* tv);
1175 
1176   /// @brief Gets current date and time with a subsecond part.
1177   /// @param format User provided date/time format
1178   /// @param ssPrec A pointer to base::SubsecondPrecision from configuration (non-null)
1179   /// @returns string based date time in specified format.
1180   static std::string getDateTime(const char* format, const base::SubsecondPrecision* ssPrec);
1181 
1182   /// @brief Converts timeval (struct from ctime) to string using specified format and subsecond precision
1183   static std::string timevalToString(struct timeval tval, const char* format,
1184                                      const el::base::SubsecondPrecision* ssPrec);
1185 
1186   /// @brief Formats time to get unit accordingly, units like second if > 1000 or minutes if > 60000 etc
1187   static base::type::string_t formatTime(unsigned long long time, base::TimestampUnit timestampUnit);
1188 
1189   /// @brief Gets time difference in milli/micro second depending on timestampUnit
1190   static unsigned long long getTimeDifference(const struct timeval& endTime, const struct timeval& startTime,
1191       base::TimestampUnit timestampUnit);
1192 
1193 
1194   static struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo);
1195  private:
1196   static char* parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo,
1197                            std::size_t msec, const base::SubsecondPrecision* ssPrec);
1198 };
1199 /// @brief Command line arguments for application if specified using el::Helpers::setArgs(..) or START_EASYLOGGINGPP(..)
1200 class CommandLineArgs {
1201  public:
1202   CommandLineArgs(void) {
1203     setArgs(0, static_cast<char**>(nullptr));
1204   }
1205   CommandLineArgs(int argc, const char** argv) {
1206     setArgs(argc, argv);
1207   }
1208   CommandLineArgs(int argc, char** argv) {
1209     setArgs(argc, argv);
1210   }
1211   virtual ~CommandLineArgs(void) {}
1212   /// @brief Sets arguments and parses them
1213   inline void setArgs(int argc, const char** argv) {
1214     setArgs(argc, const_cast<char**>(argv));
1215   }
1216   /// @brief Sets arguments and parses them
1217   void setArgs(int argc, char** argv);
1218   /// @brief Returns true if arguments contain paramKey with a value (seperated by '=')
1219   bool hasParamWithValue(const char* paramKey) const;
1220   /// @brief Returns value of arguments
1221   /// @see hasParamWithValue(const char*)
1222   const char* getParamValue(const char* paramKey) const;
1223   /// @brief Return true if arguments has a param (not having a value) i,e without '='
1224   bool hasParam(const char* paramKey) const;
1225   /// @brief Returns true if no params available. This exclude argv[0]
1226   bool empty(void) const;
1227   /// @brief Returns total number of arguments. This exclude argv[0]
1228   std::size_t size(void) const;
1229   friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c);
1230 
1231  private:
1232   int m_argc;
1233   char** m_argv;
1234   std::unordered_map<std::string, std::string> m_paramsWithValue;
1235   std::vector<std::string> m_params;
1236 };
1237 /// @brief Abstract registry (aka repository) that provides basic interface for pointer repository specified by T_Ptr type.
1238 ///
1239 /// @detail Most of the functions are virtual final methods but anything implementing this abstract class should implement
1240 /// unregisterAll() and deepCopy(const AbstractRegistry<T_Ptr, Container>&) and write registerNew() method according to container
1241 /// and few more methods; get() to find element, unregister() to unregister single entry.
1242 /// Please note that this is thread-unsafe and should also implement thread-safety mechanisms in implementation.
1243 template <typename T_Ptr, typename Container>
1244 class AbstractRegistry : public base::threading::ThreadSafe {
1245  public:
1246   typedef typename Container::iterator iterator;
1247   typedef typename Container::const_iterator const_iterator;
1248 
1249   /// @brief Default constructor
1250   AbstractRegistry(void) {}
1251 
1252   /// @brief Move constructor that is useful for base classes
1253   AbstractRegistry(AbstractRegistry&& sr) {
1254     if (this == &sr) {
1255       return;
1256     }
1257     unregisterAll();
1258     m_list = std::move(sr.m_list);
1259   }
1260 
1261   bool operator==(const AbstractRegistry<T_Ptr, Container>& other) {
1262     if (size() != other.size()) {
1263       return false;
1264     }
1265     for (std::size_t i = 0; i < m_list.size(); ++i) {
1266       if (m_list.at(i) != other.m_list.at(i)) {
1267         return false;
1268       }
1269     }
1270     return true;
1271   }
1272 
1273   bool operator!=(const AbstractRegistry<T_Ptr, Container>& other) {
1274     if (size() != other.size()) {
1275       return true;
1276     }
1277     for (std::size_t i = 0; i < m_list.size(); ++i) {
1278       if (m_list.at(i) != other.m_list.at(i)) {
1279         return true;
1280       }
1281     }
1282     return false;
1283   }
1284 
1285   /// @brief Assignment move operator
1286   AbstractRegistry& operator=(AbstractRegistry&& sr) {
1287     if (this == &sr) {
1288       return *this;
1289     }
1290     unregisterAll();
1291     m_list = std::move(sr.m_list);
1292     return *this;
1293   }
1294 
1295   virtual ~AbstractRegistry(void) {
1296   }
1297 
1298   /// @return Iterator pointer from start of repository
1299   virtual inline iterator begin(void) ELPP_FINAL {
1300     return m_list.begin();
1301   }
1302 
1303   /// @return Iterator pointer from end of repository
1304   virtual inline iterator end(void) ELPP_FINAL {
1305     return m_list.end();
1306   }
1307 
1308 
1309   /// @return Constant iterator pointer from start of repository
1310   virtual inline const_iterator cbegin(void) const ELPP_FINAL {
1311     return m_list.cbegin();
1312   }
1313 
1314   /// @return End of repository
1315   virtual inline const_iterator cend(void) const ELPP_FINAL {
1316     return m_list.cend();
1317   }
1318 
1319   /// @return Whether or not repository is empty
1320   virtual inline bool empty(void) const ELPP_FINAL {
1321     return m_list.empty();
1322   }
1323 
1324   /// @return Size of repository
1325   virtual inline std::size_t size(void) const ELPP_FINAL {
1326     return m_list.size();
1327   }
1328 
1329   /// @brief Returns underlying container by reference
1330   virtual inline Container& list(void) ELPP_FINAL {
1331     return m_list;
1332   }
1333 
1334   /// @brief Returns underlying container by constant reference.
1335   virtual inline const Container& list(void) const ELPP_FINAL {
1336     return m_list;
1337   }
1338 
1339   /// @brief Unregisters all the pointers from current repository.
1340   virtual void unregisterAll(void) = 0;
1341 
1342  protected:
1343   virtual void deepCopy(const AbstractRegistry<T_Ptr, Container>&) = 0;
1344   void reinitDeepCopy(const AbstractRegistry<T_Ptr, Container>& sr) {
1345     unregisterAll();
1346     deepCopy(sr);
1347   }
1348 
1349  private:
1350   Container m_list;
1351 };
1352 
1353 /// @brief A pointer registry mechanism to manage memory and provide search functionalities. (non-predicate version)
1354 ///
1355 /// @detail NOTE: This is thread-unsafe implementation (although it contains lock function, it does not use these functions)
1356 ///         of AbstractRegistry<T_Ptr, Container>. Any implementation of this class should be
1357 ///         explicitly (by using lock functions)
1358 template <typename T_Ptr, typename T_Key = const char*>
1359 class Registry : public AbstractRegistry<T_Ptr, std::unordered_map<T_Key, T_Ptr*>> {
1360  public:
1361   typedef typename Registry<T_Ptr, T_Key>::iterator iterator;
1362   typedef typename Registry<T_Ptr, T_Key>::const_iterator const_iterator;
1363 
1364   Registry(void) {}
1365 
1366   /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor.
1367   Registry(const Registry& sr) : AbstractRegistry<T_Ptr, std::vector<T_Ptr*>>() {
1368     if (this == &sr) {
1369       return;
1370     }
1371     this->reinitDeepCopy(sr);
1372   }
1373 
1374   /// @brief Assignment operator that unregisters all the existing registeries and deeply copies each of repo element
1375   /// @see unregisterAll()
1376   /// @see deepCopy(const AbstractRegistry&)
1377   Registry& operator=(const Registry& sr) {
1378     if (this == &sr) {
1379       return *this;
1380     }
1381     this->reinitDeepCopy(sr);
1382     return *this;
1383   }
1384 
1385   virtual ~Registry(void) {
1386     unregisterAll();
1387   }
1388 
1389  protected:
1390   virtual void unregisterAll(void) ELPP_FINAL {
1391     if (!this->empty()) {
1392       for (auto&& curr : this->list()) {
1393         base::utils::safeDelete(curr.second);
1394       }
1395       this->list().clear();
1396     }
1397   }
1398 
1399 /// @brief Registers new registry to repository.
1400   virtual void registerNew(const T_Key& uniqKey, T_Ptr* ptr) ELPP_FINAL {
1401     unregister(uniqKey);
1402     this->list().insert(std::make_pair(uniqKey, ptr));
1403   }
1404 
1405 /// @brief Unregisters single entry mapped to specified unique key
1406   void unregister(const T_Key& uniqKey) {
1407     T_Ptr* existing = get(uniqKey);
1408     if (existing != nullptr) {
1409       this->list().erase(uniqKey);
1410       base::utils::safeDelete(existing);
1411     }
1412   }
1413 
1414 /// @brief Gets pointer from repository. If none found, nullptr is returned.
1415   T_Ptr* get(const T_Key& uniqKey) {
1416     iterator it = this->list().find(uniqKey);
1417     return it == this->list().end()
1418            ? nullptr
1419            : it->second;
1420   }
1421 
1422  private:
1423   virtual void deepCopy(const AbstractRegistry<T_Ptr, std::unordered_map<T_Key, T_Ptr*>>& sr) ELPP_FINAL {
1424     for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it) {
1425       registerNew(it->first, new T_Ptr(*it->second));
1426     }
1427   }
1428 };
1429 
1430 /// @brief A pointer registry mechanism to manage memory and provide search functionalities. (predicate version)
1431 ///
1432 /// @detail NOTE: This is thread-unsafe implementation of AbstractRegistry<T_Ptr, Container>. Any implementation of this class
1433 /// should be made thread-safe explicitly
1434 template <typename T_Ptr, typename Pred>
1435 class RegistryWithPred : public AbstractRegistry<T_Ptr, std::vector<T_Ptr*>> {
1436  public:
1437   typedef typename RegistryWithPred<T_Ptr, Pred>::iterator iterator;
1438   typedef typename RegistryWithPred<T_Ptr, Pred>::const_iterator const_iterator;
1439 
1440   RegistryWithPred(void) {
1441   }
1442 
1443   virtual ~RegistryWithPred(void) {
1444     unregisterAll();
1445   }
1446 
1447   /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor.
1448   RegistryWithPred(const RegistryWithPred& sr) : AbstractRegistry<T_Ptr, std::vector<T_Ptr*>>() {
1449     if (this == &sr) {
1450       return;
1451     }
1452     this->reinitDeepCopy(sr);
1453   }
1454 
1455   /// @brief Assignment operator that unregisters all the existing registeries and deeply copies each of repo element
1456   /// @see unregisterAll()
1457   /// @see deepCopy(const AbstractRegistry&)
1458   RegistryWithPred& operator=(const RegistryWithPred& sr) {
1459     if (this == &sr) {
1460       return *this;
1461     }
1462     this->reinitDeepCopy(sr);
1463     return *this;
1464   }
1465 
1466   friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const RegistryWithPred& sr) {
1467     for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
1468       os << ELPP_LITERAL("    ") << **it << ELPP_LITERAL("\n");
1469     }
1470     return os;
1471   }
1472 
1473  protected:
1474   virtual void unregisterAll(void) ELPP_FINAL {
1475     if (!this->empty()) {
1476       for (auto&& curr : this->list()) {
1477         base::utils::safeDelete(curr);
1478       }
1479       this->list().clear();
1480     }
1481   }
1482 
1483   virtual void unregister(T_Ptr*& ptr) ELPP_FINAL {
1484     if (ptr) {
1485       iterator iter = this->begin();
1486       for (; iter != this->end(); ++iter) {
1487         if (ptr == *iter) {
1488           break;
1489         }
1490       }
1491       if (iter != this->end() && *iter != nullptr) {
1492         this->list().erase(iter);
1493         base::utils::safeDelete(*iter);
1494       }
1495     }
1496   }
1497 
1498   virtual inline void registerNew(T_Ptr* ptr) ELPP_FINAL {
1499     this->list().push_back(ptr);
1500   }
1501 
1502 /// @brief Gets pointer from repository with speicifed arguments. Arguments are passed to predicate
1503 /// in order to validate pointer.
1504   template <typename T, typename T2>
1505   T_Ptr* get(const T& arg1, const T2 arg2) {
1506     iterator iter = std::find_if(this->list().begin(), this->list().end(), Pred(arg1, arg2));
1507     if (iter != this->list().end() && *iter != nullptr) {
1508       return *iter;
1509     }
1510     return nullptr;
1511   }
1512 
1513  private:
1514   virtual void deepCopy(const AbstractRegistry<T_Ptr, std::vector<T_Ptr*>>& sr) {
1515     for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
1516       registerNew(new T_Ptr(**it));
1517     }
1518   }
1519 };
1520 class Utils {
1521  public:
1522   template <typename T, typename TPtr>
1523   static bool installCallback(const std::string& id, std::unordered_map<std::string, TPtr>* mapT) {
1524     if (mapT->find(id) == mapT->end()) {
1525       mapT->insert(std::make_pair(id, TPtr(new T())));
1526       return true;
1527     }
1528     return false;
1529   }
1530 
1531   template <typename T, typename TPtr>
1532   static void uninstallCallback(const std::string& id, std::unordered_map<std::string, TPtr>* mapT) {
1533     if (mapT->find(id) != mapT->end()) {
1534       mapT->erase(id);
1535     }
1536   }
1537 
1538   template <typename T, typename TPtr>
1539   static T* callback(const std::string& id, std::unordered_map<std::string, TPtr>* mapT) {
1540     typename std::unordered_map<std::string, TPtr>::iterator iter = mapT->find(id);
1541     if (iter != mapT->end()) {
1542       return static_cast<T*>(iter->second.get());
1543     }
1544     return nullptr;
1545   }
1546 };
1547 }  // namespace utils
1548 } // namespace base
1549 /// @brief Base of Easylogging++ friendly class
1550 ///
1551 /// @detail After inheriting this class publicly, implement pure-virtual function `void log(std::ostream&) const`
1552 class Loggable {
1553  public:
1554   virtual ~Loggable(void) {}
1555   virtual void log(el::base::type::ostream_t&) const = 0;
1556  private:
1557   friend inline el::base::type::ostream_t& operator<<(el::base::type::ostream_t& os, const Loggable& loggable) {
1558     loggable.log(os);
1559     return os;
1560   }
1561 };
1562 namespace base {
1563 /// @brief Represents log format containing flags and date format. This is used internally to start initial log
1564 class LogFormat : public Loggable {
1565  public:
1566   LogFormat(void);
1567   LogFormat(Level level, const base::type::string_t& format);
1568   LogFormat(const LogFormat& logFormat);
1569   LogFormat(LogFormat&& logFormat);
1570   LogFormat& operator=(const LogFormat& logFormat);
1571   virtual ~LogFormat(void) {}
1572   bool operator==(const LogFormat& other);
1573 
1574   /// @brief Updates format to be used while logging.
1575   /// @param userFormat User provided format
1576   void parseFromFormat(const base::type::string_t& userFormat);
1577 
1578   inline Level level(void) const {
1579     return m_level;
1580   }
1581 
1582   inline const base::type::string_t& userFormat(void) const {
1583     return m_userFormat;
1584   }
1585 
1586   inline const base::type::string_t& format(void) const {
1587     return m_format;
1588   }
1589 
1590   inline const std::string& dateTimeFormat(void) const {
1591     return m_dateTimeFormat;
1592   }
1593 
1594   inline base::type::EnumType flags(void) const {
1595     return m_flags;
1596   }
1597 
1598   inline bool hasFlag(base::FormatFlags flag) const {
1599     return base::utils::hasFlag(flag, m_flags);
1600   }
1601 
1602   virtual void log(el::base::type::ostream_t& os) const {
1603     os << m_format;
1604   }
1605 
1606  protected:
1607   /// @brief Updates date time format if available in currFormat.
1608   /// @param index Index where %datetime, %date or %time was found
1609   /// @param [in,out] currFormat current format that is being used to format
1610   virtual void updateDateFormat(std::size_t index, base::type::string_t& currFormat) ELPP_FINAL;
1611 
1612   /// @brief Updates %level from format. This is so that we dont have to do it at log-writing-time. It uses m_format and m_level
1613   virtual void updateFormatSpec(void) ELPP_FINAL;
1614 
1615   inline void addFlag(base::FormatFlags flag) {
1616     base::utils::addFlag(flag, &m_flags);
1617   }
1618 
1619  private:
1620   Level m_level;
1621   base::type::string_t m_userFormat;
1622   base::type::string_t m_format;
1623   std::string m_dateTimeFormat;
1624   base::type::EnumType m_flags;
1625   std::string m_currentUser;
1626   std::string m_currentHost;
1627   friend class el::Logger;  // To resolve loggerId format specifier easily
1628 };
1629 }  // namespace base
1630 /// @brief Resolving function for format specifier
1631 typedef std::function<std::string(const LogMessage*)> FormatSpecifierValueResolver;
1632 /// @brief User-provided custom format specifier
1633 /// @see el::Helpers::installCustomFormatSpecifier
1634 /// @see FormatSpecifierValueResolver
1635 class CustomFormatSpecifier {
1636  public:
1637   CustomFormatSpecifier(const char* formatSpecifier, const FormatSpecifierValueResolver& resolver) :
1638     m_formatSpecifier(formatSpecifier), m_resolver(resolver) {}
1639   inline const char* formatSpecifier(void) const {
1640     return m_formatSpecifier;
1641   }
1642   inline const FormatSpecifierValueResolver& resolver(void) const {
1643     return m_resolver;
1644   }
1645   inline bool operator==(const char* formatSpecifier) {
1646     return strcmp(m_formatSpecifier, formatSpecifier) == 0;
1647   }
1648 
1649  private:
1650   const char* m_formatSpecifier;
1651   FormatSpecifierValueResolver m_resolver;
1652 };
1653 /// @brief Represents single configuration that has representing level, configuration type and a string based value.
1654 ///
1655 /// @detail String based value means any value either its boolean, integer or string itself, it will be embedded inside quotes
1656 /// and will be parsed later.
1657 ///
1658 /// Consider some examples below:
1659 ///   * el::Configuration confEnabledInfo(el::Level::Info, el::ConfigurationType::Enabled, "true");
1660 ///   * el::Configuration confMaxLogFileSizeInfo(el::Level::Info, el::ConfigurationType::MaxLogFileSize, "2048");
1661 ///   * el::Configuration confFilenameInfo(el::Level::Info, el::ConfigurationType::Filename, "/var/log/my.log");
1662 class Configuration : public Loggable {
1663  public:
1664   Configuration(const Configuration& c);
1665   Configuration& operator=(const Configuration& c);
1666 
1667   virtual ~Configuration(void) {
1668   }
1669 
1670   /// @brief Full constructor used to sets value of configuration
1671   Configuration(Level level, ConfigurationType configurationType, const std::string& value);
1672 
1673   /// @brief Gets level of current configuration
1674   inline Level level(void) const {
1675     return m_level;
1676   }
1677 
1678   /// @brief Gets configuration type of current configuration
1679   inline ConfigurationType configurationType(void) const {
1680     return m_configurationType;
1681   }
1682 
1683   /// @brief Gets string based configuration value
1684   inline const std::string& value(void) const {
1685     return m_value;
1686   }
1687 
1688   /// @brief Set string based configuration value
1689   /// @param value Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values
1690   ///        use them in quotes. They will be parsed when configuring
1691   inline void setValue(const std::string& value) {
1692     m_value = value;
1693   }
1694 
1695   virtual void log(el::base::type::ostream_t& os) const;
1696 
1697   /// @brief Used to find configuration from configuration (pointers) repository. Avoid using it.
1698   class Predicate {
1699    public:
1700     Predicate(Level level, ConfigurationType configurationType);
1701 
1702     bool operator()(const Configuration* conf) const;
1703 
1704    private:
1705     Level m_level;
1706     ConfigurationType m_configurationType;
1707   };
1708 
1709  private:
1710   Level m_level;
1711   ConfigurationType m_configurationType;
1712   std::string m_value;
1713 };
1714 
1715 /// @brief Thread-safe Configuration repository
1716 ///
1717 /// @detail This repository represents configurations for all the levels and configuration type mapped to a value.
1718 class Configurations : public base::utils::RegistryWithPred<Configuration, Configuration::Predicate> {
1719  public:
1720   /// @brief Default constructor with empty repository
1721   Configurations(void);
1722 
1723   /// @brief Constructor used to set configurations using configuration file.
1724   /// @param configurationFile Full path to configuration file
1725   /// @param useDefaultsForRemaining Lets you set the remaining configurations to default.
1726   /// @param base If provided, this configuration will be based off existing repository that this argument is pointing to.
1727   /// @see parseFromFile(const std::string&, Configurations* base)
1728   /// @see setRemainingToDefault()
1729   Configurations(const std::string& configurationFile, bool useDefaultsForRemaining = true,
1730                  Configurations* base = nullptr);
1731 
1732   virtual ~Configurations(void) {
1733   }
1734 
1735   /// @brief Parses configuration from file.
1736   /// @param configurationFile Full path to configuration file
1737   /// @param base Configurations to base new configuration repository off. This value is used when you want to use
1738   ///        existing Configurations to base all the values and then set rest of configuration via configuration file.
1739   /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
1740   ///         do not proceed without successful parse.
1741   bool parseFromFile(const std::string& configurationFile, Configurations* base = nullptr);
1742 
1743   /// @brief Parse configurations from configuration string.
1744   ///
1745   /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary
1746   /// new line characters are provided.
1747   /// @param base Configurations to base new configuration repository off. This value is used when you want to use
1748   ///        existing Configurations to base all the values and then set rest of configuration via configuration text.
1749   /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
1750   ///         do not proceed without successful parse.
1751   bool parseFromText(const std::string& configurationsString, Configurations* base = nullptr);
1752 
1753   /// @brief Sets configuration based-off an existing configurations.
1754   /// @param base Pointer to existing configurations.
1755   void setFromBase(Configurations* base);
1756 
1757   /// @brief Determines whether or not specified configuration type exists in the repository.
1758   ///
1759   /// @detail Returns as soon as first level is found.
1760   /// @param configurationType Type of configuration to check existence for.
1761   bool hasConfiguration(ConfigurationType configurationType);
1762 
1763   /// @brief Determines whether or not specified configuration type exists for specified level
1764   /// @param level Level to check
1765   /// @param configurationType Type of configuration to check existence for.
1766   bool hasConfiguration(Level level, ConfigurationType configurationType);
1767 
1768   /// @brief Sets value of configuration for specified level.
1769   ///
1770   /// @detail Any existing configuration for specified level will be replaced. Also note that configuration types
1771   /// ConfigurationType::SubsecondPrecision and ConfigurationType::PerformanceTracking will be ignored if not set for
1772   /// Level::Global because these configurations are not dependant on level.
1773   /// @param level Level to set configuration for (el::Level).
1774   /// @param configurationType Type of configuration (el::ConfigurationType)
1775   /// @param value A string based value. Regardless of what the data type of configuration is, it will always be string
1776   /// from users' point of view. This is then parsed later to be used internally.
1777   /// @see Configuration::setValue(const std::string& value)
1778   /// @see el::Level
1779   /// @see el::ConfigurationType
1780   void set(Level level, ConfigurationType configurationType, const std::string& value);
1781 
1782   /// @brief Sets single configuration based on other single configuration.
1783   /// @see set(Level level, ConfigurationType configurationType, const std::string& value)
1784   void set(Configuration* conf);
1785 
1786   inline Configuration* get(Level level, ConfigurationType configurationType) {
1787     base::threading::ScopedLock scopedLock(lock());
1788     return RegistryWithPred<Configuration, Configuration::Predicate>::get(level, configurationType);
1789   }
1790 
1791   /// @brief Sets configuration for all levels.
1792   /// @param configurationType Type of configuration
1793   /// @param value String based value
1794   /// @see Configurations::set(Level level, ConfigurationType configurationType, const std::string& value)
1795   inline void setGlobally(ConfigurationType configurationType, const std::string& value) {
1796     setGlobally(configurationType, value, false);
1797   }
1798 
1799   /// @brief Clears repository so that all the configurations are unset
1800   inline void clear(void) {
1801     base::threading::ScopedLock scopedLock(lock());
1802     unregisterAll();
1803   }
1804 
1805   /// @brief Gets configuration file used in parsing this configurations.
1806   ///
1807   /// @detail If this repository was set manually or by text this returns empty string.
1808   inline const std::string& configurationFile(void) const {
1809     return m_configurationFile;
1810   }
1811 
1812   /// @brief Sets configurations to "factory based" configurations.
1813   void setToDefault(void);
1814 
1815   /// @brief Lets you set the remaining configurations to default.
1816   ///
1817   /// @detail By remaining, it means that the level/type a configuration does not exist for.
1818   /// This function is useful when you want to minimize chances of failures, e.g, if you have a configuration file that sets
1819   /// configuration for all the configurations except for Enabled or not, we use this so that ENABLED is set to default i.e,
1820   /// true. If you dont do this explicitly (either by calling this function or by using second param in Constructor
1821   /// and try to access a value, an error is thrown
1822   void setRemainingToDefault(void);
1823 
1824   /// @brief Parser used internally to parse configurations from file or text.
1825   ///
1826   /// @detail This class makes use of base::utils::Str.
1827   /// You should not need this unless you are working on some tool for Easylogging++
1828   class Parser : base::StaticClass {
1829    public:
1830     /// @brief Parses configuration from file.
1831     /// @param configurationFile Full path to configuration file
1832     /// @param sender Sender configurations pointer. Usually 'this' is used from calling class
1833     /// @param base Configurations to base new configuration repository off. This value is used when you want to use
1834     ///        existing Configurations to base all the values and then set rest of configuration via configuration file.
1835     /// @return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you
1836     ///         do not proceed without successful parse.
1837     static bool parseFromFile(const std::string& configurationFile, Configurations* sender,
1838                               Configurations* base = nullptr);
1839 
1840     /// @brief Parse configurations from configuration string.
1841     ///
1842     /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary
1843     /// new line characters are provided. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you
1844     /// do not proceed without successful parse (This is recommended)
1845     /// @param configurationsString the configuration in plain text format
1846     /// @param sender Sender configurations pointer. Usually 'this' is used from calling class
1847     /// @param base Configurations to base new configuration repository off. This value is used when you want to use
1848     ///        existing Configurations to base all the values and then set rest of configuration via configuration text.
1849     /// @return True if successfully parsed, false otherwise.
1850     static bool parseFromText(const std::string& configurationsString, Configurations* sender,
1851                               Configurations* base = nullptr);
1852 
1853    private:
1854     friend class el::Loggers;
1855     static void ignoreComments(std::string* line);
1856     static bool isLevel(const std::string& line);
1857     static bool isComment(const std::string& line);
1858     static inline bool isConfig(const std::string& line);
1859     static bool parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, Level* currLevel,
1860                           Configurations* conf);
1861   };
1862 
1863  private:
1864   std::string m_configurationFile;
1865   bool m_isFromFile;
1866   friend class el::Loggers;
1867 
1868   /// @brief Unsafely sets configuration if does not already exist
1869   void unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value);
1870 
1871   /// @brief Thread unsafe set
1872   void unsafeSet(Level level, ConfigurationType configurationType, const std::string& value);
1873 
1874   /// @brief Sets configurations for all levels including Level::Global if includeGlobalLevel is true
1875   /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value)
1876   void setGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel);
1877 
1878   /// @brief Sets configurations (Unsafely) for all levels including Level::Global if includeGlobalLevel is true
1879   /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value)
1880   void unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel);
1881 };
1882 
1883 namespace base {
1884 typedef std::shared_ptr<base::type::fstream_t> FileStreamPtr;
1885 typedef std::unordered_map<std::string, FileStreamPtr> LogStreamsReferenceMap;
1886 /// @brief Configurations with data types.
1887 ///
1888 /// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations.
1889 /// This is to perform faster while writing logs using correct configurations.
1890 ///
1891 /// This is thread safe and final class containing non-virtual destructor (means nothing should inherit this class)
1892 class TypedConfigurations : public base::threading::ThreadSafe {
1893  public:
1894   /// @brief Constructor to initialize (construct) the object off el::Configurations
1895   /// @param configurations Configurations pointer/reference to base this typed configurations off.
1896   /// @param logStreamsReference Use ELPP->registeredLoggers()->logStreamsReference()
1897   TypedConfigurations(Configurations* configurations, base::LogStreamsReferenceMap* logStreamsReference);
1898 
1899   TypedConfigurations(const TypedConfigurations& other);
1900 
1901   virtual ~TypedConfigurations(void) {
1902   }
1903 
1904   const Configurations* configurations(void) const {
1905     return m_configurations;
1906   }
1907 
1908   bool enabled(Level level);
1909   bool toFile(Level level);
1910   const std::string& filename(Level level);
1911   bool toStandardOutput(Level level);
1912   const base::LogFormat& logFormat(Level level);
1913   const base::SubsecondPrecision& subsecondPrecision(Level level = Level::Global);
1914   const base::MillisecondsWidth& millisecondsWidth(Level level = Level::Global);
1915   bool performanceTracking(Level level = Level::Global);
1916   base::type::fstream_t* fileStream(Level level);
1917   std::size_t maxLogFileSize(Level level);
1918   std::size_t logFlushThreshold(Level level);
1919 
1920  private:
1921   Configurations* m_configurations;
1922   std::unordered_map<Level, bool> m_enabledMap;
1923   std::unordered_map<Level, bool> m_toFileMap;
1924   std::unordered_map<Level, std::string> m_filenameMap;
1925   std::unordered_map<Level, bool> m_toStandardOutputMap;
1926   std::unordered_map<Level, base::LogFormat> m_logFormatMap;
1927   std::unordered_map<Level, base::SubsecondPrecision> m_subsecondPrecisionMap;
1928   std::unordered_map<Level, bool> m_performanceTrackingMap;
1929   std::unordered_map<Level, base::FileStreamPtr> m_fileStreamMap;
1930   std::unordered_map<Level, std::size_t> m_maxLogFileSizeMap;
1931   std::unordered_map<Level, std::size_t> m_logFlushThresholdMap;
1932   base::LogStreamsReferenceMap* m_logStreamsReference;
1933 
1934   friend class el::Helpers;
1935   friend class el::base::MessageBuilder;
1936   friend class el::base::Writer;
1937   friend class el::base::DefaultLogDispatchCallback;
1938   friend class el::base::LogDispatcher;
1939 
1940   template <typename Conf_T>
1941   inline Conf_T getConfigByVal(Level level, const std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
1942     base::threading::ScopedLock scopedLock(lock());
1943     return unsafeGetConfigByVal(level, confMap, confName);  // This is not unsafe anymore - mutex locked in scope
1944   }
1945 
1946   template <typename Conf_T>
1947   inline Conf_T& getConfigByRef(Level level, std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
1948     base::threading::ScopedLock scopedLock(lock());
1949     return unsafeGetConfigByRef(level, confMap, confName);  // This is not unsafe anymore - mutex locked in scope
1950   }
1951 
1952   template <typename Conf_T>
1953   Conf_T unsafeGetConfigByVal(Level level, const std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
1954     ELPP_UNUSED(confName);
1955     typename std::unordered_map<Level, Conf_T>::const_iterator it = confMap->find(level);
1956     if (it == confMap->end()) {
1957       try {
1958         return confMap->at(Level::Global);
1959       } catch (...) {
1960         ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level ["
1961                             << LevelHelper::convertToString(level) << "]"
1962                             << std::endl << "Please ensure you have properly configured logger.", false);
1963         return Conf_T();
1964       }
1965     }
1966     return it->second;
1967   }
1968 
1969   template <typename Conf_T>
1970   Conf_T& unsafeGetConfigByRef(Level level, std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
1971     ELPP_UNUSED(confName);
1972     typename std::unordered_map<Level, Conf_T>::iterator it = confMap->find(level);
1973     if (it == confMap->end()) {
1974       try {
1975         return confMap->at(Level::Global);
1976       } catch (...) {
1977         ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level ["
1978                             << LevelHelper::convertToString(level) << "]"
1979                             << std::endl << "Please ensure you have properly configured logger.", false);
1980       }
1981     }
1982     return it->second;
1983   }
1984 
1985   template <typename Conf_T>
1986   void setValue(Level level, const Conf_T& value, std::unordered_map<Level, Conf_T>* confMap,
1987                 bool includeGlobalLevel = true) {
1988     // If map is empty and we are allowed to add into generic level (Level::Global), do it!
1989     if (confMap->empty() && includeGlobalLevel) {
1990       confMap->insert(std::make_pair(Level::Global, value));
1991       return;
1992     }
1993     // If same value exist in generic level already, dont add it to explicit level
1994     typename std::unordered_map<Level, Conf_T>::iterator it = confMap->find(Level::Global);
1995     if (it != confMap->end() && it->second == value) {
1996       return;
1997     }
1998     // Now make sure we dont double up values if we really need to add it to explicit level
1999     it = confMap->find(level);
2000     if (it == confMap->end()) {
2001       // Value not found for level, add new
2002       confMap->insert(std::make_pair(level, value));
2003     } else {
2004       // Value found, just update value
2005       confMap->at(level) = value;
2006     }
2007   }
2008 
2009   void build(Configurations* configurations);
2010   unsigned long getULong(std::string confVal);
2011   std::string resolveFilename(const std::string& filename);
2012   void insertFile(Level level, const std::string& fullFilename);
2013   bool unsafeValidateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback);
2014 
2015   inline bool validateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback) {
2016     base::threading::ScopedLock scopedLock(lock());
2017     return unsafeValidateFileRolling(level, preRollOutCallback);
2018   }
2019 };
2020 /// @brief Class that keeps record of current line hit for occasional logging
2021 class HitCounter {
2022  public:
2023   HitCounter(void) :
2024     m_filename(""),
2025     m_lineNumber(0),
2026     m_hitCounts(0) {
2027   }
2028 
2029   HitCounter(const char* filename, base::type::LineNumber lineNumber) :
2030     m_filename(filename),
2031     m_lineNumber(lineNumber),
2032     m_hitCounts(0) {
2033   }
2034 
2035   HitCounter(const HitCounter& hitCounter) :
2036     m_filename(hitCounter.m_filename),
2037     m_lineNumber(hitCounter.m_lineNumber),
2038     m_hitCounts(hitCounter.m_hitCounts) {
2039   }
2040 
2041   HitCounter& operator=(const HitCounter& hitCounter) {
2042     if (&hitCounter != this) {
2043       m_filename = hitCounter.m_filename;
2044       m_lineNumber = hitCounter.m_lineNumber;
2045       m_hitCounts = hitCounter.m_hitCounts;
2046     }
2047     return *this;
2048   }
2049 
2050   virtual ~HitCounter(void) {
2051   }
2052 
2053   /// @brief Resets location of current hit counter
2054   inline void resetLocation(const char* filename, base::type::LineNumber lineNumber) {
2055     m_filename = filename;
2056     m_lineNumber = lineNumber;
2057   }
2058 
2059   /// @brief Validates hit counts and resets it if necessary
2060   inline void validateHitCounts(std::size_t n) {
2061     if (m_hitCounts >= base::consts::kMaxLogPerCounter) {
2062       m_hitCounts = (n >= 1 ? base::consts::kMaxLogPerCounter % n : 0);
2063     }
2064     ++m_hitCounts;
2065   }
2066 
2067   inline const char* filename(void) const {
2068     return m_filename;
2069   }
2070 
2071   inline base::type::LineNumber lineNumber(void) const {
2072     return m_lineNumber;
2073   }
2074 
2075   inline std::size_t hitCounts(void) const {
2076     return m_hitCounts;
2077   }
2078 
2079   inline void increment(void) {
2080     ++m_hitCounts;
2081   }
2082 
2083   class Predicate {
2084    public:
2085     Predicate(const char* filename, base::type::LineNumber lineNumber)
2086       : m_filename(filename),
2087         m_lineNumber(lineNumber) {
2088     }
2089     inline bool operator()(const HitCounter* counter) {
2090       return ((counter != nullptr) &&
2091               (strcmp(counter->m_filename, m_filename) == 0) &&
2092               (counter->m_lineNumber == m_lineNumber));
2093     }
2094 
2095    private:
2096     const char* m_filename;
2097     base::type::LineNumber m_lineNumber;
2098   };
2099 
2100  private:
2101   const char* m_filename;
2102   base::type::LineNumber m_lineNumber;
2103   std::size_t m_hitCounts;
2104 };
2105 /// @brief Repository for hit counters used across the application
2106 class RegisteredHitCounters : public base::utils::RegistryWithPred<base::HitCounter, base::HitCounter::Predicate> {
2107  public:
2108   /// @brief Validates counter for every N, i.e, registers new if does not exist otherwise updates original one
2109   /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned
2110   bool validateEveryN(const char* filename, base::type::LineNumber lineNumber, std::size_t n);
2111 
2112   /// @brief Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one
2113   /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned
2114   bool validateAfterN(const char* filename, base::type::LineNumber lineNumber, std::size_t n);
2115 
2116   /// @brief Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original one
2117   /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned
2118   bool validateNTimes(const char* filename, base::type::LineNumber lineNumber, std::size_t n);
2119 
2120   /// @brief Gets hit counter registered at specified position
2121   inline const base::HitCounter* getCounter(const char* filename, base::type::LineNumber lineNumber) {
2122     base::threading::ScopedLock scopedLock(lock());
2123     return get(filename, lineNumber);
2124   }
2125 };
2126 /// @brief Action to be taken for dispatching
2127 enum class DispatchAction : base::type::EnumType {
2128   None = 1, NormalLog = 2, SysLog = 4
2129 };
2130 }  // namespace base
2131 template <typename T>
2132 class Callback : protected base::threading::ThreadSafe {
2133  public:
2134   Callback(void) : m_enabled(true) {}
2135   inline bool enabled(void) const {
2136     return m_enabled;
2137   }
2138   inline void setEnabled(bool enabled) {
2139     base::threading::ScopedLock scopedLock(lock());
2140     m_enabled = enabled;
2141   }
2142  protected:
2143   virtual void handle(const T* handlePtr) = 0;
2144  private:
2145   bool m_enabled;
2146 };
2147 class LogDispatchData {
2148  public:
2149   LogDispatchData() : m_logMessage(nullptr), m_dispatchAction(base::DispatchAction::None) {}
2150   inline const LogMessage* logMessage(void) const {
2151     return m_logMessage;
2152   }
2153   inline base::DispatchAction dispatchAction(void) const {
2154     return m_dispatchAction;
2155   }
2156   inline void setLogMessage(LogMessage* logMessage) {
2157     m_logMessage = logMessage;
2158   }
2159   inline void setDispatchAction(base::DispatchAction dispatchAction) {
2160     m_dispatchAction = dispatchAction;
2161   }
2162  private:
2163   LogMessage* m_logMessage;
2164   base::DispatchAction m_dispatchAction;
2165   friend class base::LogDispatcher;
2166 
2167 };
2168 class LogDispatchCallback : public Callback<LogDispatchData> {
2169  protected:
2170   virtual void handle(const LogDispatchData* data);
2171   base::threading::Mutex& fileHandle(const LogDispatchData* data);
2172  private:
2173   friend class base::LogDispatcher;
2174   std::unordered_map<std::string, std::unique_ptr<base::threading::Mutex>> m_fileLocks;
2175   base::threading::Mutex m_fileLocksMapLock;
2176 };
2177 class PerformanceTrackingCallback : public Callback<PerformanceTrackingData> {
2178  private:
2179   friend class base::PerformanceTracker;
2180 };
2181 class LoggerRegistrationCallback : public Callback<Logger> {
2182  private:
2183   friend class base::RegisteredLoggers;
2184 };
2185 class LogBuilder : base::NoCopy {
2186  public:
2187   LogBuilder() : m_termSupportsColor(base::utils::OS::termSupportsColor()) {}
2188   virtual ~LogBuilder(void) {
2189     ELPP_INTERNAL_INFO(3, "Destroying log builder...")
2190   }
2191   virtual base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const = 0;
2192   void convertToColoredOutput(base::type::string_t* logLine, Level level);
2193  private:
2194   bool m_termSupportsColor;
2195   friend class el::base::DefaultLogDispatchCallback;
2196 };
2197 typedef std::shared_ptr<LogBuilder> LogBuilderPtr;
2198 /// @brief Represents a logger holding ID and configurations we need to write logs
2199 ///
2200 /// @detail This class does not write logs itself instead its used by writer to read configuations from.
2201 class Logger : public base::threading::ThreadSafe, public Loggable {
2202  public:
2203   Logger(const std::string& id, base::LogStreamsReferenceMap* logStreamsReference);
2204   Logger(const std::string& id, const Configurations& configurations, base::LogStreamsReferenceMap* logStreamsReference);
2205   Logger(const Logger& logger);
2206   Logger& operator=(const Logger& logger);
2207 
2208   virtual ~Logger(void) {
2209     base::utils::safeDelete(m_typedConfigurations);
2210   }
2211 
2212   virtual inline void log(el::base::type::ostream_t& os) const {
2213     os << m_id.c_str();
2214   }
2215 
2216   /// @brief Configures the logger using specified configurations.
2217   void configure(const Configurations& configurations);
2218 
2219   /// @brief Reconfigures logger using existing configurations
2220   void reconfigure(void);
2221 
2222   inline const std::string& id(void) const {
2223     return m_id;
2224   }
2225 
2226   inline const std::string& parentApplicationName(void) const {
2227     return m_parentApplicationName;
2228   }
2229 
2230   inline void setParentApplicationName(const std::string& parentApplicationName) {
2231     m_parentApplicationName = parentApplicationName;
2232   }
2233 
2234   inline Configurations* configurations(void) {
2235     return &m_configurations;
2236   }
2237 
2238   inline base::TypedConfigurations* typedConfigurations(void) {
2239     return m_typedConfigurations;
2240   }
2241 
2242   static bool isValidId(const std::string& id);
2243 
2244   /// @brief Flushes logger to sync all log files for all levels
2245   void flush(void);
2246 
2247   void flush(Level level, base::type::fstream_t* fs);
2248 
2249   inline bool isFlushNeeded(Level level) {
2250     return ++m_unflushedCount.find(level)->second >= m_typedConfigurations->logFlushThreshold(level);
2251   }
2252 
2253   inline LogBuilder* logBuilder(void) const {
2254     return m_logBuilder.get();
2255   }
2256 
2257   inline void setLogBuilder(const LogBuilderPtr& logBuilder) {
2258     m_logBuilder = logBuilder;
2259   }
2260 
2261   inline bool enabled(Level level) const {
2262     return m_typedConfigurations->enabled(level);
2263   }
2264 
2265 #if ELPP_VARIADIC_TEMPLATES_SUPPORTED
2266 #  define LOGGER_LEVEL_WRITERS_SIGNATURES(FUNCTION_NAME)\
2267 template <typename T, typename... Args>\
2268 inline void FUNCTION_NAME(const char*, const T&, const Args&...);\
2269 template <typename T>\
2270 inline void FUNCTION_NAME(const T&);
2271 
2272   template <typename T, typename... Args>
2273   inline void verbose(int, const char*, const T&, const Args&...);
2274 
2275   template <typename T>
2276   inline void verbose(int, const T&);
2277 
2278   LOGGER_LEVEL_WRITERS_SIGNATURES(info)
2279   LOGGER_LEVEL_WRITERS_SIGNATURES(debug)
2280   LOGGER_LEVEL_WRITERS_SIGNATURES(warn)
2281   LOGGER_LEVEL_WRITERS_SIGNATURES(error)
2282   LOGGER_LEVEL_WRITERS_SIGNATURES(fatal)
2283   LOGGER_LEVEL_WRITERS_SIGNATURES(trace)
2284 #  undef LOGGER_LEVEL_WRITERS_SIGNATURES
2285 #endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
2286  private:
2287   std::string m_id;
2288   base::TypedConfigurations* m_typedConfigurations;
2289   base::type::stringstream_t m_stream;
2290   std::string m_parentApplicationName;
2291   bool m_isConfigured;
2292   Configurations m_configurations;
2293   std::unordered_map<Level, unsigned int> m_unflushedCount;
2294   base::LogStreamsReferenceMap* m_logStreamsReference;
2295   LogBuilderPtr m_logBuilder;
2296 
2297   friend class el::LogMessage;
2298   friend class el::Loggers;
2299   friend class el::Helpers;
2300   friend class el::base::RegisteredLoggers;
2301   friend class el::base::DefaultLogDispatchCallback;
2302   friend class el::base::MessageBuilder;
2303   friend class el::base::Writer;
2304   friend class el::base::PErrorWriter;
2305   friend class el::base::Storage;
2306   friend class el::base::PerformanceTracker;
2307   friend class el::base::LogDispatcher;
2308 
2309   Logger(void);
2310 
2311 #if ELPP_VARIADIC_TEMPLATES_SUPPORTED
2312   template <typename T, typename... Args>
2313   void log_(Level, int, const char*, const T&, const Args&...);
2314 
2315   template <typename T>
2316   inline void log_(Level, int, const T&);
2317 
2318   template <typename T, typename... Args>
2319   void log(Level, const char*, const T&, const Args&...);
2320 
2321   template <typename T>
2322   inline void log(Level, const T&);
2323 #endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
2324 
2325   void initUnflushedCount(void);
2326 
2327   inline base::type::stringstream_t& stream(void) {
2328     return m_stream;
2329   }
2330 
2331   void resolveLoggerFormatSpec(void) const;
2332 };
2333 namespace base {
2334 /// @brief Loggers repository
2335 class RegisteredLoggers : public base::utils::Registry<Logger, std::string> {
2336  public:
2337   explicit RegisteredLoggers(const LogBuilderPtr& defaultLogBuilder);
2338 
2339   virtual ~RegisteredLoggers(void) {
2340     unsafeFlushAll();
2341   }
2342 
2343   inline void setDefaultConfigurations(const Configurations& configurations) {
2344     base::threading::ScopedLock scopedLock(lock());
2345     m_defaultConfigurations.setFromBase(const_cast<Configurations*>(&configurations));
2346   }
2347 
2348   inline Configurations* defaultConfigurations(void) {
2349     return &m_defaultConfigurations;
2350   }
2351 
2352   Logger* get(const std::string& id, bool forceCreation = true);
2353 
2354   template <typename T>
2355   inline bool installLoggerRegistrationCallback(const std::string& id) {
2356     return base::utils::Utils::installCallback<T, base::type::LoggerRegistrationCallbackPtr>(id,
2357            &m_loggerRegistrationCallbacks);
2358   }
2359 
2360   template <typename T>
2361   inline void uninstallLoggerRegistrationCallback(const std::string& id) {
2362     base::utils::Utils::uninstallCallback<T, base::type::LoggerRegistrationCallbackPtr>(id, &m_loggerRegistrationCallbacks);
2363   }
2364 
2365   template <typename T>
2366   inline T* loggerRegistrationCallback(const std::string& id) {
2367     return base::utils::Utils::callback<T, base::type::LoggerRegistrationCallbackPtr>(id, &m_loggerRegistrationCallbacks);
2368   }
2369 
2370   bool remove(const std::string& id);
2371 
2372   inline bool has(const std::string& id) {
2373     return get(id, false) != nullptr;
2374   }
2375 
2376   inline void unregister(Logger*& logger) {
2377     base::threading::ScopedLock scopedLock(lock());
2378     base::utils::Registry<Logger, std::string>::unregister(logger->id());
2379   }
2380 
2381   inline base::LogStreamsReferenceMap* logStreamsReference(void) {
2382     return &m_logStreamsReference;
2383   }
2384 
2385   inline void flushAll(void) {
2386     base::threading::ScopedLock scopedLock(lock());
2387     unsafeFlushAll();
2388   }
2389 
2390   inline void setDefaultLogBuilder(LogBuilderPtr& logBuilderPtr) {
2391     base::threading::ScopedLock scopedLock(lock());
2392     m_defaultLogBuilder = logBuilderPtr;
2393   }
2394 
2395  private:
2396   LogBuilderPtr m_defaultLogBuilder;
2397   Configurations m_defaultConfigurations;
2398   base::LogStreamsReferenceMap m_logStreamsReference;
2399   std::unordered_map<std::string, base::type::LoggerRegistrationCallbackPtr> m_loggerRegistrationCallbacks;
2400   friend class el::base::Storage;
2401 
2402   void unsafeFlushAll(void);
2403 };
2404 /// @brief Represents registries for verbose logging
2405 class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
2406  public:
2407   explicit VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags);
2408 
2409   /// @brief Sets verbose level. Accepted range is 0-9
2410   void setLevel(base::type::VerboseLevel level);
2411 
2412   inline base::type::VerboseLevel level(void) const {
2413     return m_level;
2414   }
2415 
2416   inline void clearModules(void) {
2417     base::threading::ScopedLock scopedLock(lock());
2418     m_modules.clear();
2419   }
2420 
2421   void setModules(const char* modules);
2422 
2423   bool allowed(base::type::VerboseLevel vlevel, const char* file);
2424 
2425   inline const std::unordered_map<std::string, base::type::VerboseLevel>& modules(void) const {
2426     return m_modules;
2427   }
2428 
2429   void setFromArgs(const base::utils::CommandLineArgs* commandLineArgs);
2430 
2431   /// @brief Whether or not vModules enabled
2432   inline bool vModulesEnabled(void) {
2433     return !base::utils::hasFlag(LoggingFlag::DisableVModules, *m_pFlags);
2434   }
2435 
2436  private:
2437   base::type::VerboseLevel m_level;
2438   base::type::EnumType* m_pFlags;
2439   std::unordered_map<std::string, base::type::VerboseLevel> m_modules;
2440 };
2441 }  // namespace base
2442 class LogMessage {
2443  public:
2444   LogMessage(Level level, const std::string& file, base::type::LineNumber line, const std::string& func,
2445              base::type::VerboseLevel verboseLevel, Logger* logger) :
2446     m_level(level), m_file(file), m_line(line), m_func(func),
2447     m_verboseLevel(verboseLevel), m_logger(logger), m_message(logger->stream().str()) {
2448   }
2449   inline Level level(void) const {
2450     return m_level;
2451   }
2452   inline const std::string& file(void) const {
2453     return m_file;
2454   }
2455   inline base::type::LineNumber line(void) const {
2456     return m_line;
2457   }
2458   inline const std::string& func(void) const {
2459     return m_func;
2460   }
2461   inline base::type::VerboseLevel verboseLevel(void) const {
2462     return m_verboseLevel;
2463   }
2464   inline Logger* logger(void) const {
2465     return m_logger;
2466   }
2467   inline const base::type::string_t& message(void) const {
2468     return m_message;
2469   }
2470  private:
2471   Level m_level;
2472   std::string m_file;
2473   base::type::LineNumber m_line;
2474   std::string m_func;
2475   base::type::VerboseLevel m_verboseLevel;
2476   Logger* m_logger;
2477   base::type::string_t m_message;
2478 };
2479 namespace base {
2480 #if ELPP_ASYNC_LOGGING
2481 class AsyncLogItem {
2482  public:
2483   explicit AsyncLogItem(const LogMessage& logMessage, const LogDispatchData& data, const base::type::string_t& logLine)
2484     : m_logMessage(logMessage), m_dispatchData(data), m_logLine(logLine) {}
2485   virtual ~AsyncLogItem() {}
2486   inline LogMessage* logMessage(void) {
2487     return &m_logMessage;
2488   }
2489   inline LogDispatchData* data(void) {
2490     return &m_dispatchData;
2491   }
2492   inline base::type::string_t logLine(void) {
2493     return m_logLine;
2494   }
2495  private:
2496   LogMessage m_logMessage;
2497   LogDispatchData m_dispatchData;
2498   base::type::string_t m_logLine;
2499 };
2500 class AsyncLogQueue : public base::threading::ThreadSafe {
2501  public:
2502   virtual ~AsyncLogQueue() {
2503     ELPP_INTERNAL_INFO(6, "~AsyncLogQueue");
2504   }
2505 
2506   inline AsyncLogItem next(void) {
2507     base::threading::ScopedLock scopedLock(lock());
2508     AsyncLogItem result = m_queue.front();
2509     m_queue.pop();
2510     return result;
2511   }
2512 
2513   inline void push(const AsyncLogItem& item) {
2514     base::threading::ScopedLock scopedLock(lock());
2515     m_queue.push(item);
2516   }
2517   inline void pop(void) {
2518     base::threading::ScopedLock scopedLock(lock());
2519     m_queue.pop();
2520   }
2521   inline AsyncLogItem front(void) {
2522     base::threading::ScopedLock scopedLock(lock());
2523     return m_queue.front();
2524   }
2525   inline bool empty(void) {
2526     base::threading::ScopedLock scopedLock(lock());
2527     return m_queue.empty();
2528   }
2529  private:
2530   std::queue<AsyncLogItem> m_queue;
2531 };
2532 class IWorker {
2533  public:
2534   virtual ~IWorker() {}
2535   virtual void start() = 0;
2536 };
2537 #endif // ELPP_ASYNC_LOGGING
2538 /// @brief Easylogging++ management storage
2539 class Storage : base::NoCopy, public base::threading::ThreadSafe {
2540  public:
2541 #if ELPP_ASYNC_LOGGING
2542   Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker);
2543 #else
2544   explicit Storage(const LogBuilderPtr& defaultLogBuilder);
2545 #endif  // ELPP_ASYNC_LOGGING
2546 
2547   virtual ~Storage(void);
2548 
2549   inline bool validateEveryNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t occasion) {
2550     return hitCounters()->validateEveryN(filename, lineNumber, occasion);
2551   }
2552 
2553   inline bool validateAfterNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) {
2554     return hitCounters()->validateAfterN(filename, lineNumber, n);
2555   }
2556 
2557   inline bool validateNTimesCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) {
2558     return hitCounters()->validateNTimes(filename, lineNumber, n);
2559   }
2560 
2561   inline base::RegisteredHitCounters* hitCounters(void) const {
2562     return m_registeredHitCounters;
2563   }
2564 
2565   inline base::RegisteredLoggers* registeredLoggers(void) const {
2566     return m_registeredLoggers;
2567   }
2568 
2569   inline base::VRegistry* vRegistry(void) const {
2570     return m_vRegistry;
2571   }
2572 
2573 #if ELPP_ASYNC_LOGGING
2574   inline base::AsyncLogQueue* asyncLogQueue(void) const {
2575     return m_asyncLogQueue;
2576   }
2577 #endif  // ELPP_ASYNC_LOGGING
2578 
2579   inline const base::utils::CommandLineArgs* commandLineArgs(void) const {
2580     return &m_commandLineArgs;
2581   }
2582 
2583   inline void addFlag(LoggingFlag flag) {
2584     base::utils::addFlag(flag, &m_flags);
2585   }
2586 
2587   inline void removeFlag(LoggingFlag flag) {
2588     base::utils::removeFlag(flag, &m_flags);
2589   }
2590 
2591   inline bool hasFlag(LoggingFlag flag) const {
2592     return base::utils::hasFlag(flag, m_flags);
2593   }
2594 
2595   inline base::type::EnumType flags(void) const {
2596     return m_flags;
2597   }
2598 
2599   inline void setFlags(base::type::EnumType flags) {
2600     m_flags = flags;
2601   }
2602 
2603   inline void setPreRollOutCallback(const PreRollOutCallback& callback) {
2604     m_preRollOutCallback = callback;
2605   }
2606 
2607   inline void unsetPreRollOutCallback(void) {
2608     m_preRollOutCallback = base::defaultPreRollOutCallback;
2609   }
2610 
2611   inline PreRollOutCallback& preRollOutCallback(void) {
2612     return m_preRollOutCallback;
2613   }
2614 
2615   bool hasCustomFormatSpecifier(const char* formatSpecifier);
2616   void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier);
2617   bool uninstallCustomFormatSpecifier(const char* formatSpecifier);
2618 
2619   const std::vector<CustomFormatSpecifier>* customFormatSpecifiers(void) const {
2620     return &m_customFormatSpecifiers;
2621   }
2622 
2623   base::threading::Mutex& customFormatSpecifiersLock() {
2624     return m_customFormatSpecifiersLock;
2625   }
2626 
2627   inline void setLoggingLevel(Level level) {
2628     m_loggingLevel = level;
2629   }
2630 
2631   template <typename T>
2632   inline bool installLogDispatchCallback(const std::string& id) {
2633     return base::utils::Utils::installCallback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
2634   }
2635 
2636   template <typename T>
2637   inline void uninstallLogDispatchCallback(const std::string& id) {
2638     base::utils::Utils::uninstallCallback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
2639   }
2640   template <typename T>
2641   inline T* logDispatchCallback(const std::string& id) {
2642     return base::utils::Utils::callback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
2643   }
2644 
2645 #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
2646   template <typename T>
2647   inline bool installPerformanceTrackingCallback(const std::string& id) {
2648     return base::utils::Utils::installCallback<T, base::type::PerformanceTrackingCallbackPtr>(id,
2649            &m_performanceTrackingCallbacks);
2650   }
2651 
2652   template <typename T>
2653   inline void uninstallPerformanceTrackingCallback(const std::string& id) {
2654     base::utils::Utils::uninstallCallback<T, base::type::PerformanceTrackingCallbackPtr>(id,
2655         &m_performanceTrackingCallbacks);
2656   }
2657 
2658   template <typename T>
2659   inline T* performanceTrackingCallback(const std::string& id) {
2660     return base::utils::Utils::callback<T, base::type::PerformanceTrackingCallbackPtr>(id, &m_performanceTrackingCallbacks);
2661   }
2662 #endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
2663 
2664   /// @brief Sets thread name for current thread. Requires std::thread
2665   inline void setThreadName(const std::string& name) {
2666     if (name.empty()) return;
2667     base::threading::ScopedLock scopedLock(m_threadNamesLock);
2668     m_threadNames[base::threading::getCurrentThreadId()] = name;
2669   }
2670 
2671   inline std::string getThreadName(const std::string& threadId) {
2672     base::threading::ScopedLock scopedLock(m_threadNamesLock);
2673     std::unordered_map<std::string, std::string>::const_iterator it = m_threadNames.find(threadId);
2674     if (it == m_threadNames.end()) {
2675       return threadId;
2676     }
2677     return it->second;
2678   }
2679  private:
2680   base::RegisteredHitCounters* m_registeredHitCounters;
2681   base::RegisteredLoggers* m_registeredLoggers;
2682   base::type::EnumType m_flags;
2683   base::VRegistry* m_vRegistry;
2684 #if ELPP_ASYNC_LOGGING
2685   base::AsyncLogQueue* m_asyncLogQueue;
2686   base::IWorker* m_asyncDispatchWorker;
2687 #endif  // ELPP_ASYNC_LOGGING
2688   base::utils::CommandLineArgs m_commandLineArgs;
2689   PreRollOutCallback m_preRollOutCallback;
2690   std::unordered_map<std::string, base::type::LogDispatchCallbackPtr> m_logDispatchCallbacks;
2691   std::unordered_map<std::string, base::type::PerformanceTrackingCallbackPtr> m_performanceTrackingCallbacks;
2692   std::unordered_map<std::string, std::string> m_threadNames;
2693   std::vector<CustomFormatSpecifier> m_customFormatSpecifiers;
2694   base::threading::Mutex m_customFormatSpecifiersLock;
2695   base::threading::Mutex m_threadNamesLock;
2696   Level m_loggingLevel;
2697 
2698   friend class el::Helpers;
2699   friend class el::base::DefaultLogDispatchCallback;
2700   friend class el::LogBuilder;
2701   friend class el::base::MessageBuilder;
2702   friend class el::base::Writer;
2703   friend class el::base::PerformanceTracker;
2704   friend class el::base::LogDispatcher;
2705 
2706   void setApplicationArguments(int argc, char** argv);
2707 
2708   inline void setApplicationArguments(int argc, const char** argv) {
2709     setApplicationArguments(argc, const_cast<char**>(argv));
2710   }
2711 };
2712 extern ELPP_EXPORT base::type::StoragePointer elStorage;
2713 #define ELPP el::base::elStorage
2714 class DefaultLogDispatchCallback : public LogDispatchCallback {
2715  protected:
2716   void handle(const LogDispatchData* data);
2717  private:
2718   const LogDispatchData* m_data;
2719   void dispatch(base::type::string_t&& logLine);
2720 };
2721 #if ELPP_ASYNC_LOGGING
2722 class AsyncLogDispatchCallback : public LogDispatchCallback {
2723  protected:
2724   void handle(const LogDispatchData* data);
2725 };
2726 class AsyncDispatchWorker : public base::IWorker, public base::threading::ThreadSafe {
2727  public:
2728   AsyncDispatchWorker();
2729   virtual ~AsyncDispatchWorker();
2730 
2731   bool clean(void);
2732   void emptyQueue(void);
2733   virtual void start(void);
2734   void handle(AsyncLogItem* logItem);
2735   void run(void);
2736 
2737   void setContinueRunning(bool value) {
2738     base::threading::ScopedLock scopedLock(m_continueRunningLock);
2739     m_continueRunning = value;
2740   }
2741 
2742   bool continueRunning(void) const {
2743     return m_continueRunning;
2744   }
2745  private:
2746   std::condition_variable cv;
2747   bool m_continueRunning;
2748   base::threading::Mutex m_continueRunningLock;
2749 };
2750 #endif  // ELPP_ASYNC_LOGGING
2751 }  // namespace base
2752 namespace base {
2753 class DefaultLogBuilder : public LogBuilder {
2754  public:
2755   base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const;
2756 };
2757 /// @brief Dispatches log messages
2758 class LogDispatcher : base::NoCopy {
2759  public:
2760   LogDispatcher(bool proceed, LogMessage* logMessage, base::DispatchAction dispatchAction) :
2761     m_proceed(proceed),
2762     m_logMessage(logMessage),
2763     m_dispatchAction(std::move(dispatchAction)) {
2764   }
2765 
2766   void dispatch(void);
2767 
2768  private:
2769   bool m_proceed;
2770   LogMessage* m_logMessage;
2771   base::DispatchAction m_dispatchAction;
2772 };
2773 #if defined(ELPP_STL_LOGGING)
2774 /// @brief Workarounds to write some STL logs
2775 ///
2776 /// @detail There is workaround needed to loop through some stl containers. In order to do that, we need iterable containers
2777 /// of same type and provide iterator interface and pass it on to writeIterator().
2778 /// Remember, this is passed by value in constructor so that we dont change original containers.
2779 /// This operation is as expensive as Big-O(std::min(class_.size(), base::consts::kMaxLogPerContainer))
2780 namespace workarounds {
2781 /// @brief Abstract IterableContainer template that provides interface for iterable classes of type T
2782 template <typename T, typename Container>
2783 class IterableContainer {
2784  public:
2785   typedef typename Container::iterator iterator;
2786   typedef typename Container::const_iterator const_iterator;
2787   IterableContainer(void) {}
2788   virtual ~IterableContainer(void) {}
2789   iterator begin(void) {
2790     return getContainer().begin();
2791   }
2792   iterator end(void) {
2793     return getContainer().end();
2794   }
2795  private:
2796   virtual Container& getContainer(void) = 0;
2797 };
2798 /// @brief Implements IterableContainer and provides iterable std::priority_queue class
2799 template<typename T, typename Container = std::vector<T>, typename Comparator = std::less<typename Container::value_type>>
2800 class IterablePriorityQueue : public IterableContainer<T, Container>,
2801   public std::priority_queue<T, Container, Comparator> {
2802  public:
2803   IterablePriorityQueue(std::priority_queue<T, Container, Comparator> queue_) {
2804     std::size_t count_ = 0;
2805     while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) {
2806       this->push(queue_.top());
2807       queue_.pop();
2808     }
2809   }
2810  private:
2811   inline Container& getContainer(void) {
2812     return this->c;
2813   }
2814 };
2815 /// @brief Implements IterableContainer and provides iterable std::queue class
2816 template<typename T, typename Container = std::deque<T>>
2817 class IterableQueue : public IterableContainer<T, Container>, public std::queue<T, Container> {
2818  public:
2819   IterableQueue(std::queue<T, Container> queue_) {
2820     std::size_t count_ = 0;
2821     while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) {
2822       this->push(queue_.front());
2823       queue_.pop();
2824     }
2825   }
2826  private:
2827   inline Container& getContainer(void) {
2828     return this->c;
2829   }
2830 };
2831 /// @brief Implements IterableContainer and provides iterable std::stack class
2832 template<typename T, typename Container = std::deque<T>>
2833 class IterableStack : public IterableContainer<T, Container>, public std::stack<T, Container> {
2834  public:
2835   IterableStack(std::stack<T, Container> stack_) {
2836     std::size_t count_ = 0;
2837     while (++count_ < base::consts::kMaxLogPerContainer && !stack_.empty()) {
2838       this->push(stack_.top());
2839       stack_.pop();
2840     }
2841   }
2842  private:
2843   inline Container& getContainer(void) {
2844     return this->c;
2845   }
2846 };
2847 }  // namespace workarounds
2848 #endif  // defined(ELPP_STL_LOGGING)
2849 // Log message builder
2850 class MessageBuilder {
2851  public:
2852   MessageBuilder(void) : m_logger(nullptr), m_containerLogSeperator(ELPP_LITERAL("")) {}
2853   void initialize(Logger* logger);
2854 
2855 #  define ELPP_SIMPLE_LOG(LOG_TYPE)\
2856 MessageBuilder& operator<<(LOG_TYPE msg) {\
2857 m_logger->stream() << msg;\
2858 if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {\
2859 m_logger->stream() << " ";\
2860 }\
2861 return *this;\
2862 }
2863 
2864   inline MessageBuilder& operator<<(const std::string& msg) {
2865     return operator<<(msg.c_str());
2866   }
2867   ELPP_SIMPLE_LOG(char)
2868   ELPP_SIMPLE_LOG(bool)
2869   ELPP_SIMPLE_LOG(signed short)
2870   ELPP_SIMPLE_LOG(unsigned short)
2871   ELPP_SIMPLE_LOG(signed int)
2872   ELPP_SIMPLE_LOG(unsigned int)
2873   ELPP_SIMPLE_LOG(signed long)
2874   ELPP_SIMPLE_LOG(unsigned long)
2875   ELPP_SIMPLE_LOG(float)
2876   ELPP_SIMPLE_LOG(double)
2877   ELPP_SIMPLE_LOG(char*)
2878   ELPP_SIMPLE_LOG(const char*)
2879   ELPP_SIMPLE_LOG(const void*)
2880   ELPP_SIMPLE_LOG(long double)
2881   inline MessageBuilder& operator<<(const std::wstring& msg) {
2882     return operator<<(msg.c_str());
2883   }
2884   MessageBuilder& operator<<(const wchar_t* msg);
2885   // ostream manipulators
2886   inline MessageBuilder& operator<<(std::ostream& (*OStreamMani)(std::ostream&)) {
2887     m_logger->stream() << OStreamMani;
2888     return *this;
2889   }
2890 #define ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(temp)                                                    \
2891 template <typename T>                                                                            \
2892 inline MessageBuilder& operator<<(const temp<T>& template_inst) {                                \
2893 return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size());      \
2894 }
2895 #define ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(temp)                                                    \
2896 template <typename T1, typename T2>                                                              \
2897 inline MessageBuilder& operator<<(const temp<T1, T2>& template_inst) {                           \
2898 return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size());      \
2899 }
2900 #define ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(temp)                                                  \
2901 template <typename T1, typename T2, typename T3>                                                 \
2902 inline MessageBuilder& operator<<(const temp<T1, T2, T3>& template_inst) {                       \
2903 return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size());      \
2904 }
2905 #define ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(temp)                                                   \
2906 template <typename T1, typename T2, typename T3, typename T4>                                    \
2907 inline MessageBuilder& operator<<(const temp<T1, T2, T3, T4>& template_inst) {                   \
2908 return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size());      \
2909 }
2910 #define ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(temp)                                                   \
2911 template <typename T1, typename T2, typename T3, typename T4, typename T5>                       \
2912 inline MessageBuilder& operator<<(const temp<T1, T2, T3, T4, T5>& template_inst) {               \
2913 return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size());      \
2914 }
2915 
2916 #if defined(ELPP_STL_LOGGING)
2917   ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::vector)
2918   ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::list)
2919   ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::deque)
2920   ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::set)
2921   ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::multiset)
2922   ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::map)
2923   ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::multimap)
2924   template <class T, class Container>
2925   inline MessageBuilder& operator<<(const std::queue<T, Container>& queue_) {
2926     base::workarounds::IterableQueue<T, Container> iterableQueue_ =
2927       static_cast<base::workarounds::IterableQueue<T, Container> >(queue_);
2928     return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size());
2929   }
2930   template <class T, class Container>
2931   inline MessageBuilder& operator<<(const std::stack<T, Container>& stack_) {
2932     base::workarounds::IterableStack<T, Container> iterableStack_ =
2933       static_cast<base::workarounds::IterableStack<T, Container> >(stack_);
2934     return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size());
2935   }
2936   template <class T, class Container, class Comparator>
2937   inline MessageBuilder& operator<<(const std::priority_queue<T, Container, Comparator>& priorityQueue_) {
2938     base::workarounds::IterablePriorityQueue<T, Container, Comparator> iterablePriorityQueue_ =
2939       static_cast<base::workarounds::IterablePriorityQueue<T, Container, Comparator> >(priorityQueue_);
2940     return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size());
2941   }
2942   template <class First, class Second>
2943   MessageBuilder& operator<<(const std::pair<First, Second>& pair_) {
2944     m_logger->stream() << ELPP_LITERAL("(");
2945     operator << (static_cast<First>(pair_.first));
2946     m_logger->stream() << ELPP_LITERAL(", ");
2947     operator << (static_cast<Second>(pair_.second));
2948     m_logger->stream() << ELPP_LITERAL(")");
2949     return *this;
2950   }
2951   template <std::size_t Size>
2952   MessageBuilder& operator<<(const std::bitset<Size>& bitset_) {
2953     m_logger->stream() << ELPP_LITERAL("[");
2954     operator << (bitset_.to_string());
2955     m_logger->stream() << ELPP_LITERAL("]");
2956     return *this;
2957   }
2958 #  if defined(ELPP_LOG_STD_ARRAY)
2959   template <class T, std::size_t Size>
2960   inline MessageBuilder& operator<<(const std::array<T, Size>& array) {
2961     return writeIterator(array.begin(), array.end(), array.size());
2962   }
2963 #  endif  // defined(ELPP_LOG_STD_ARRAY)
2964 #  if defined(ELPP_LOG_UNORDERED_MAP)
2965   ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_map)
2966   ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_multimap)
2967 #  endif  // defined(ELPP_LOG_UNORDERED_MAP)
2968 #  if defined(ELPP_LOG_UNORDERED_SET)
2969   ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_set)
2970   ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_multiset)
2971 #  endif  // defined(ELPP_LOG_UNORDERED_SET)
2972 #endif  // defined(ELPP_STL_LOGGING)
2973 #if defined(ELPP_QT_LOGGING)
2974   inline MessageBuilder& operator<<(const QString& msg) {
2975 #  if defined(ELPP_UNICODE)
2976     m_logger->stream() << msg.toStdWString();
2977 #  else
2978     m_logger->stream() << msg.toStdString();
2979 #  endif  // defined(ELPP_UNICODE)
2980     return *this;
2981   }
2982   inline MessageBuilder& operator<<(const QByteArray& msg) {
2983     return operator << (QString(msg));
2984   }
2985   inline MessageBuilder& operator<<(const QStringRef& msg) {
2986     return operator<<(msg.toString());
2987   }
2988   inline MessageBuilder& operator<<(qint64 msg) {
2989 #  if defined(ELPP_UNICODE)
2990     m_logger->stream() << QString::number(msg).toStdWString();
2991 #  else
2992     m_logger->stream() << QString::number(msg).toStdString();
2993 #  endif  // defined(ELPP_UNICODE)
2994     return *this;
2995   }
2996   inline MessageBuilder& operator<<(quint64 msg) {
2997 #  if defined(ELPP_UNICODE)
2998     m_logger->stream() << QString::number(msg).toStdWString();
2999 #  else
3000     m_logger->stream() << QString::number(msg).toStdString();
3001 #  endif  // defined(ELPP_UNICODE)
3002     return *this;
3003   }
3004   inline MessageBuilder& operator<<(QChar msg) {
3005     m_logger->stream() << msg.toLatin1();
3006     return *this;
3007   }
3008   inline MessageBuilder& operator<<(const QLatin1String& msg) {
3009     m_logger->stream() << msg.latin1();
3010     return *this;
3011   }
3012   ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QList)
3013   ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QVector)
3014   ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QQueue)
3015   ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QSet)
3016   ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QLinkedList)
3017   ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QStack)
3018   template <typename First, typename Second>
3019   MessageBuilder& operator<<(const QPair<First, Second>& pair_) {
3020     m_logger->stream() << ELPP_LITERAL("(");
3021     operator << (static_cast<First>(pair_.first));
3022     m_logger->stream() << ELPP_LITERAL(", ");
3023     operator << (static_cast<Second>(pair_.second));
3024     m_logger->stream() << ELPP_LITERAL(")");
3025     return *this;
3026   }
3027   template <typename K, typename V>
3028   MessageBuilder& operator<<(const QMap<K, V>& map_) {
3029     m_logger->stream() << ELPP_LITERAL("[");
3030     QList<K> keys = map_.keys();
3031     typename QList<K>::const_iterator begin = keys.begin();
3032     typename QList<K>::const_iterator end = keys.end();
3033     int max_ = static_cast<int>(base::consts::kMaxLogPerContainer);  // to prevent warning
3034     for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
3035       m_logger->stream() << ELPP_LITERAL("(");
3036       operator << (static_cast<K>(*begin));
3037       m_logger->stream() << ELPP_LITERAL(", ");
3038       operator << (static_cast<V>(map_.value(*begin)));
3039       m_logger->stream() << ELPP_LITERAL(")");
3040       m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL(""));
3041     }
3042     if (begin != end) {
3043       m_logger->stream() << ELPP_LITERAL("...");
3044     }
3045     m_logger->stream() << ELPP_LITERAL("]");
3046     return *this;
3047   }
3048   template <typename K, typename V>
3049   inline MessageBuilder& operator<<(const QMultiMap<K, V>& map_) {
3050     operator << (static_cast<QMap<K, V>>(map_));
3051     return *this;
3052   }
3053   template <typename K, typename V>
3054   MessageBuilder& operator<<(const QHash<K, V>& hash_) {
3055     m_logger->stream() << ELPP_LITERAL("[");
3056     QList<K> keys = hash_.keys();
3057     typename QList<K>::const_iterator begin = keys.begin();
3058     typename QList<K>::const_iterator end = keys.end();
3059     int max_ = static_cast<int>(base::consts::kMaxLogPerContainer);  // prevent type warning
3060     for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
3061       m_logger->stream() << ELPP_LITERAL("(");
3062       operator << (static_cast<K>(*begin));
3063       m_logger->stream() << ELPP_LITERAL(", ");
3064       operator << (static_cast<V>(hash_.value(*begin)));
3065       m_logger->stream() << ELPP_LITERAL(")");
3066       m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL(""));
3067     }
3068     if (begin != end) {
3069       m_logger->stream() << ELPP_LITERAL("...");
3070     }
3071     m_logger->stream() << ELPP_LITERAL("]");
3072     return *this;
3073   }
3074   template <typename K, typename V>
3075   inline MessageBuilder& operator<<(const QMultiHash<K, V>& multiHash_) {
3076     operator << (static_cast<QHash<K, V>>(multiHash_));
3077     return *this;
3078   }
3079 #endif  // defined(ELPP_QT_LOGGING)
3080 #if defined(ELPP_BOOST_LOGGING)
3081   ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::vector)
3082   ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::stable_vector)
3083   ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::list)
3084   ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::deque)
3085   ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::map)
3086   ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::flat_map)
3087   ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::set)
3088   ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::flat_set)
3089 #endif  // defined(ELPP_BOOST_LOGGING)
3090 
3091   /// @brief Macro used internally that can be used externally to make containers easylogging++ friendly
3092   ///
3093   /// @detail This macro expands to write an ostream& operator<< for container. This container is expected to
3094   ///         have begin() and end() methods that return respective iterators
3095   /// @param ContainerType Type of container e.g, MyList from WX_DECLARE_LIST(int, MyList); in wxwidgets
3096   /// @param SizeMethod Method used to get size of container.
3097   /// @param ElementInstance Instance of element to be fed out. Insance name is "elem". See WXELPP_ENABLED macro
3098   ///        for an example usage
3099 #define MAKE_CONTAINERELPP_FRIENDLY(ContainerType, SizeMethod, ElementInstance) \
3100 el::base::type::ostream_t& operator<<(el::base::type::ostream_t& ss, const ContainerType& container) {\
3101 const el::base::type::char_t* sep = ELPP->hasFlag(el::LoggingFlag::NewLineForContainer) ? \
3102 ELPP_LITERAL("\n    ") : ELPP_LITERAL(", ");\
3103 ContainerType::const_iterator elem = container.begin();\
3104 ContainerType::const_iterator endElem = container.end();\
3105 std::size_t size_ = container.SizeMethod; \
3106 ss << ELPP_LITERAL("[");\
3107 for (std::size_t i = 0; elem != endElem && i < el::base::consts::kMaxLogPerContainer; ++i, ++elem) { \
3108 ss << ElementInstance;\
3109 ss << ((i < size_ - 1) ? sep : ELPP_LITERAL(""));\
3110 }\
3111 if (elem != endElem) {\
3112 ss << ELPP_LITERAL("...");\
3113 }\
3114 ss << ELPP_LITERAL("]");\
3115 return ss;\
3116 }
3117 #if defined(ELPP_WXWIDGETS_LOGGING)
3118   ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(wxVector)
3119 #  define ELPP_WX_PTR_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), *(*elem))
3120 #  define ELPP_WX_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), (*elem))
3121 #  define ELPP_WX_HASH_MAP_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), \
3122 ELPP_LITERAL("(") << elem->first << ELPP_LITERAL(", ") << elem->second << ELPP_LITERAL(")")
3123 #else
3124 #  define ELPP_WX_PTR_ENABLED(ContainerType)
3125 #  define ELPP_WX_ENABLED(ContainerType)
3126 #  define ELPP_WX_HASH_MAP_ENABLED(ContainerType)
3127 #endif  // defined(ELPP_WXWIDGETS_LOGGING)
3128   // Other classes
3129   template <class Class>
3130   ELPP_SIMPLE_LOG(const Class&)
3131 #undef ELPP_SIMPLE_LOG
3132 #undef ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG
3133 #undef ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG
3134 #undef ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG
3135 #undef ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG
3136 #undef ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG
3137  private:
3138   Logger* m_logger;
3139   const base::type::char_t* m_containerLogSeperator;
3140 
3141   template<class Iterator>
3142   MessageBuilder& writeIterator(Iterator begin_, Iterator end_, std::size_t size_) {
3143     m_logger->stream() << ELPP_LITERAL("[");
3144     for (std::size_t i = 0; begin_ != end_ && i < base::consts::kMaxLogPerContainer; ++i, ++begin_) {
3145       operator << (*begin_);
3146       m_logger->stream() << ((i < size_ - 1) ? m_containerLogSeperator : ELPP_LITERAL(""));
3147     }
3148     if (begin_ != end_) {
3149       m_logger->stream() << ELPP_LITERAL("...");
3150     }
3151     m_logger->stream() << ELPP_LITERAL("]");
3152     if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {
3153       m_logger->stream() << " ";
3154     }
3155     return *this;
3156   }
3157 };
3158 /// @brief Writes nothing - Used when certain log is disabled
3159 class NullWriter : base::NoCopy {
3160  public:
3161   NullWriter(void) {}
3162 
3163   // Null manipulator
3164   inline NullWriter& operator<<(std::ostream& (*)(std::ostream&)) {
3165     return *this;
3166   }
3167 
3168   template <typename T>
3169   inline NullWriter& operator<<(const T&) {
3170     return *this;
3171   }
3172 
3173   inline operator bool() {
3174     return true;
3175   }
3176 };
3177 /// @brief Main entry point of each logging
3178 class Writer : base::NoCopy {
3179  public:
3180   Writer(Level level, const char* file, base::type::LineNumber line,
3181          const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
3182          base::type::VerboseLevel verboseLevel = 0) :
3183     m_msg(nullptr), m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel),
3184     m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) {
3185   }
3186 
3187   Writer(LogMessage* msg, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog) :
3188     m_msg(msg), m_line(0), m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) {
3189   }
3190 
3191   virtual ~Writer(void) {
3192     processDispatch();
3193   }
3194 
3195   template <typename T>
3196   inline Writer& operator<<(const T& log) {
3197 #if ELPP_LOGGING_ENABLED
3198     if (m_proceed) {
3199       m_messageBuilder << log;
3200     }
3201 #endif  // ELPP_LOGGING_ENABLED
3202     return *this;
3203   }
3204 
3205   inline Writer& operator<<(std::ostream& (*log)(std::ostream&)) {
3206 #if ELPP_LOGGING_ENABLED
3207     if (m_proceed) {
3208       m_messageBuilder << log;
3209     }
3210 #endif  // ELPP_LOGGING_ENABLED
3211     return *this;
3212   }
3213 
3214   inline operator bool() {
3215     return true;
3216   }
3217 
3218   Writer& construct(Logger* logger, bool needLock = true);
3219   Writer& construct(int count, const char* loggerIds, ...);
3220  protected:
3221   LogMessage* m_msg;
3222   Level m_level;
3223   const char* m_file;
3224   const base::type::LineNumber m_line;
3225   const char* m_func;
3226   base::type::VerboseLevel m_verboseLevel;
3227   Logger* m_logger;
3228   bool m_proceed;
3229   base::MessageBuilder m_messageBuilder;
3230   base::DispatchAction m_dispatchAction;
3231   std::vector<std::string> m_loggerIds;
3232   friend class el::Helpers;
3233 
3234   void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true);
3235   void processDispatch();
3236   void triggerDispatch(void);
3237 };
3238 class PErrorWriter : public base::Writer {
3239  public:
3240   PErrorWriter(Level level, const char* file, base::type::LineNumber line,
3241                const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
3242                base::type::VerboseLevel verboseLevel = 0) :
3243     base::Writer(level, file, line, func, dispatchAction, verboseLevel) {
3244   }
3245 
3246   virtual ~PErrorWriter(void);
3247 };
3248 }  // namespace base
3249 // Logging from Logger class. Why this is here? Because we have Storage and Writer class available
3250 #if ELPP_VARIADIC_TEMPLATES_SUPPORTED
3251 template <typename T, typename... Args>
3252 void Logger::log_(Level level, int vlevel, const char* s, const T& value, const Args&... args) {
3253   base::MessageBuilder b;
3254   b.initialize(this);
3255   while (*s) {
3256     if (*s == base::consts::kFormatSpecifierChar) {
3257       if (*(s + 1) == base::consts::kFormatSpecifierChar) {
3258         ++s;
3259       } else {
3260         if (*(s + 1) == base::consts::kFormatSpecifierCharValue) {
3261           ++s;
3262           b << value;
3263           log_(level, vlevel, ++s, args...);
3264           return;
3265         }
3266       }
3267     }
3268     b << *s++;
3269   }
3270   ELPP_INTERNAL_ERROR("Too many arguments provided. Unable to handle. Please provide more format specifiers", false);
3271 }
3272 template <typename T>
3273 void Logger::log_(Level level, int vlevel, const T& log) {
3274   if (level == Level::Verbose) {
3275     if (ELPP->vRegistry()->allowed(vlevel, __FILE__)) {
3276       base::Writer(Level::Verbose, "FILE", 0, "FUNCTION",
3277                    base::DispatchAction::NormalLog, vlevel).construct(this, false) << log;
3278     } else {
3279       stream().str(ELPP_LITERAL(""));
3280       releaseLock();
3281     }
3282   } else {
3283     base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log;
3284   }
3285 }
3286 template <typename T, typename... Args>
3287 inline void Logger::log(Level level, const char* s, const T& value, const Args&... args) {
3288   acquireLock(); // released in Writer!
3289   log_(level, 0, s, value, args...);
3290 }
3291 template <typename T>
3292 inline void Logger::log(Level level, const T& log) {
3293   acquireLock(); // released in Writer!
3294   log_(level, 0, log);
3295 }
3296 #  if ELPP_VERBOSE_LOG
3297 template <typename T, typename... Args>
3298 inline void Logger::verbose(int vlevel, const char* s, const T& value, const Args&... args) {
3299   acquireLock(); // released in Writer!
3300   log_(el::Level::Verbose, vlevel, s, value, args...);
3301 }
3302 template <typename T>
3303 inline void Logger::verbose(int vlevel, const T& log) {
3304   acquireLock(); // released in Writer!
3305   log_(el::Level::Verbose, vlevel, log);
3306 }
3307 #  else
3308 template <typename T, typename... Args>
3309 inline void Logger::verbose(int, const char*, const T&, const Args&...) {
3310   return;
3311 }
3312 template <typename T>
3313 inline void Logger::verbose(int, const T&) {
3314   return;
3315 }
3316 #  endif  // ELPP_VERBOSE_LOG
3317 #  define LOGGER_LEVEL_WRITERS(FUNCTION_NAME, LOG_LEVEL)\
3318 template <typename T, typename... Args>\
3319 inline void Logger::FUNCTION_NAME(const char* s, const T& value, const Args&... args) {\
3320 log(LOG_LEVEL, s, value, args...);\
3321 }\
3322 template <typename T>\
3323 inline void Logger::FUNCTION_NAME(const T& value) {\
3324 log(LOG_LEVEL, value);\
3325 }
3326 #  define LOGGER_LEVEL_WRITERS_DISABLED(FUNCTION_NAME, LOG_LEVEL)\
3327 template <typename T, typename... Args>\
3328 inline void Logger::FUNCTION_NAME(const char*, const T&, const Args&...) {\
3329 return;\
3330 }\
3331 template <typename T>\
3332 inline void Logger::FUNCTION_NAME(const T&) {\
3333 return;\
3334 }
3335 
3336 #  if ELPP_INFO_LOG
3337 LOGGER_LEVEL_WRITERS(info, Level::Info)
3338 #  else
3339 LOGGER_LEVEL_WRITERS_DISABLED(info, Level::Info)
3340 #  endif // ELPP_INFO_LOG
3341 #  if ELPP_DEBUG_LOG
3342 LOGGER_LEVEL_WRITERS(debug, Level::Debug)
3343 #  else
3344 LOGGER_LEVEL_WRITERS_DISABLED(debug, Level::Debug)
3345 #  endif // ELPP_DEBUG_LOG
3346 #  if ELPP_WARNING_LOG
3347 LOGGER_LEVEL_WRITERS(warn, Level::Warning)
3348 #  else
3349 LOGGER_LEVEL_WRITERS_DISABLED(warn, Level::Warning)
3350 #  endif // ELPP_WARNING_LOG
3351 #  if ELPP_ERROR_LOG
3352 LOGGER_LEVEL_WRITERS(error, Level::Error)
3353 #  else
3354 LOGGER_LEVEL_WRITERS_DISABLED(error, Level::Error)
3355 #  endif // ELPP_ERROR_LOG
3356 #  if ELPP_FATAL_LOG
3357 LOGGER_LEVEL_WRITERS(fatal, Level::Fatal)
3358 #  else
3359 LOGGER_LEVEL_WRITERS_DISABLED(fatal, Level::Fatal)
3360 #  endif // ELPP_FATAL_LOG
3361 #  if ELPP_TRACE_LOG
3362 LOGGER_LEVEL_WRITERS(trace, Level::Trace)
3363 #  else
3364 LOGGER_LEVEL_WRITERS_DISABLED(trace, Level::Trace)
3365 #  endif // ELPP_TRACE_LOG
3366 #  undef LOGGER_LEVEL_WRITERS
3367 #  undef LOGGER_LEVEL_WRITERS_DISABLED
3368 #endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
3369 #if ELPP_COMPILER_MSVC
3370 #  define ELPP_VARIADIC_FUNC_MSVC(variadicFunction, variadicArgs) variadicFunction variadicArgs
3371 #  define ELPP_VARIADIC_FUNC_MSVC_RUN(variadicFunction, ...) ELPP_VARIADIC_FUNC_MSVC(variadicFunction, (__VA_ARGS__))
3372 #  define el_getVALength(...) ELPP_VARIADIC_FUNC_MSVC_RUN(el_resolveVALength, 0, ## __VA_ARGS__,\
3373 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
3374 #else
3375 #  if ELPP_COMPILER_CLANG
3376 #    define el_getVALength(...) el_resolveVALength(0, __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
3377 #  else
3378 #    define el_getVALength(...) el_resolveVALength(0, ## __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
3379 #  endif // ELPP_COMPILER_CLANG
3380 #endif // ELPP_COMPILER_MSVC
3381 #define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
3382 #define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \
3383 writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
3384 #define ELPP_WRITE_LOG_IF(writer, condition, level, dispatchAction, ...) if (condition) \
3385 writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
3386 #define ELPP_WRITE_LOG_EVERY_N(writer, occasion, level, dispatchAction, ...) \
3387 ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion) && \
3388 writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
3389 #define ELPP_WRITE_LOG_AFTER_N(writer, n, level, dispatchAction, ...) \
3390 ELPP->validateAfterNCounter(__FILE__, __LINE__, n) && \
3391 writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
3392 #define ELPP_WRITE_LOG_N_TIMES(writer, n, level, dispatchAction, ...) \
3393 ELPP->validateNTimesCounter(__FILE__, __LINE__, n) && \
3394 writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
3395 #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
3396 class PerformanceTrackingData {
3397  public:
3398   enum class DataType : base::type::EnumType {
3399     Checkpoint = 1, Complete = 2
3400   };
3401   // Do not use constructor, will run into multiple definition error, use init(PerformanceTracker*)
3402   explicit PerformanceTrackingData(DataType dataType) : m_performanceTracker(nullptr),
3403     m_dataType(dataType), m_firstCheckpoint(false), m_file(""), m_line(0), m_func("") {}
3404   inline const std::string* blockName(void) const;
3405   inline const struct timeval* startTime(void) const;
3406   inline const struct timeval* endTime(void) const;
3407   inline const struct timeval* lastCheckpointTime(void) const;
3408   inline const base::PerformanceTracker* performanceTracker(void) const {
3409     return m_performanceTracker;
3410   }
3411   inline PerformanceTrackingData::DataType dataType(void) const {
3412     return m_dataType;
3413   }
3414   inline bool firstCheckpoint(void) const {
3415     return m_firstCheckpoint;
3416   }
3417   inline std::string checkpointId(void) const {
3418     return m_checkpointId;
3419   }
3420   inline const char* file(void) const {
3421     return m_file;
3422   }
3423   inline base::type::LineNumber line(void) const {
3424     return m_line;
3425   }
3426   inline const char* func(void) const {
3427     return m_func;
3428   }
3429   inline const base::type::string_t* formattedTimeTaken() const {
3430     return &m_formattedTimeTaken;
3431   }
3432   inline const std::string& loggerId(void) const;
3433  private:
3434   base::PerformanceTracker* m_performanceTracker;
3435   base::type::string_t m_formattedTimeTaken;
3436   PerformanceTrackingData::DataType m_dataType;
3437   bool m_firstCheckpoint;
3438   std::string m_checkpointId;
3439   const char* m_file;
3440   base::type::LineNumber m_line;
3441   const char* m_func;
3442   inline void init(base::PerformanceTracker* performanceTracker, bool firstCheckpoint = false) {
3443     m_performanceTracker = performanceTracker;
3444     m_firstCheckpoint = firstCheckpoint;
3445   }
3446 
3447   friend class el::base::PerformanceTracker;
3448 };
3449 namespace base {
3450 /// @brief Represents performanceTracker block of code that conditionally adds performance status to log
3451 ///        either when goes outside the scope of when checkpoint() is called
3452 class PerformanceTracker : public base::threading::ThreadSafe, public Loggable {
3453  public:
3454   PerformanceTracker(const std::string& blockName,
3455                      base::TimestampUnit timestampUnit = base::TimestampUnit::Millisecond,
3456                      const std::string& loggerId = std::string(el::base::consts::kPerformanceLoggerId),
3457                      bool scopedLog = true, Level level = base::consts::kPerformanceTrackerDefaultLevel);
3458   /// @brief Copy constructor
3459   PerformanceTracker(const PerformanceTracker& t) :
3460     m_blockName(t.m_blockName), m_timestampUnit(t.m_timestampUnit), m_loggerId(t.m_loggerId), m_scopedLog(t.m_scopedLog),
3461     m_level(t.m_level), m_hasChecked(t.m_hasChecked), m_lastCheckpointId(t.m_lastCheckpointId), m_enabled(t.m_enabled),
3462     m_startTime(t.m_startTime), m_endTime(t.m_endTime), m_lastCheckpointTime(t.m_lastCheckpointTime) {
3463   }
3464   virtual ~PerformanceTracker(void);
3465   /// @brief A checkpoint for current performanceTracker block.
3466   void checkpoint(const std::string& id = std::string(), const char* file = __FILE__,
3467                   base::type::LineNumber line = __LINE__,
3468                   const char* func = "");
3469   inline Level level(void) const {
3470     return m_level;
3471   }
3472  private:
3473   std::string m_blockName;
3474   base::TimestampUnit m_timestampUnit;
3475   std::string m_loggerId;
3476   bool m_scopedLog;
3477   Level m_level;
3478   bool m_hasChecked;
3479   std::string m_lastCheckpointId;
3480   bool m_enabled;
3481   struct timeval m_startTime, m_endTime, m_lastCheckpointTime;
3482 
3483   PerformanceTracker(void);
3484 
3485   friend class el::PerformanceTrackingData;
3486   friend class base::DefaultPerformanceTrackingCallback;
3487 
3488   const inline base::type::string_t getFormattedTimeTaken() const {
3489     return getFormattedTimeTaken(m_startTime);
3490   }
3491 
3492   const base::type::string_t getFormattedTimeTaken(struct timeval startTime) const;
3493 
3494   virtual inline void log(el::base::type::ostream_t& os) const {
3495     os << getFormattedTimeTaken();
3496   }
3497 };
3498 class DefaultPerformanceTrackingCallback : public PerformanceTrackingCallback {
3499  protected:
3500   void handle(const PerformanceTrackingData* data) {
3501     m_data = data;
3502     base::type::stringstream_t ss;
3503     if (m_data->dataType() == PerformanceTrackingData::DataType::Complete) {
3504       ss << ELPP_LITERAL("Executed [") << m_data->blockName()->c_str() << ELPP_LITERAL("] in [") <<
3505          *m_data->formattedTimeTaken() << ELPP_LITERAL("]");
3506     } else {
3507       ss << ELPP_LITERAL("Performance checkpoint");
3508       if (!m_data->checkpointId().empty()) {
3509         ss << ELPP_LITERAL(" [") << m_data->checkpointId().c_str() << ELPP_LITERAL("]");
3510       }
3511       ss << ELPP_LITERAL(" for block [") << m_data->blockName()->c_str() << ELPP_LITERAL("] : [") <<
3512          *m_data->performanceTracker();
3513       if (!ELPP->hasFlag(LoggingFlag::DisablePerformanceTrackingCheckpointComparison)
3514           && m_data->performanceTracker()->m_hasChecked) {
3515         ss << ELPP_LITERAL(" ([") << *m_data->formattedTimeTaken() << ELPP_LITERAL("] from ");
3516         if (m_data->performanceTracker()->m_lastCheckpointId.empty()) {
3517           ss << ELPP_LITERAL("last checkpoint");
3518         } else {
3519           ss << ELPP_LITERAL("checkpoint '") << m_data->performanceTracker()->m_lastCheckpointId.c_str() << ELPP_LITERAL("'");
3520         }
3521         ss << ELPP_LITERAL(")]");
3522       } else {
3523         ss << ELPP_LITERAL("]");
3524       }
3525     }
3526     el::base::Writer(m_data->performanceTracker()->level(), m_data->file(), m_data->line(), m_data->func()).construct(1,
3527         m_data->loggerId().c_str()) << ss.str();
3528   }
3529  private:
3530   const PerformanceTrackingData* m_data;
3531 };
3532 }  // namespace base
3533 inline const std::string* PerformanceTrackingData::blockName() const {
3534   return const_cast<const std::string*>(&m_performanceTracker->m_blockName);
3535 }
3536 inline const struct timeval* PerformanceTrackingData::startTime() const {
3537   return const_cast<const struct timeval*>(&m_performanceTracker->m_startTime);
3538 }
3539 inline const struct timeval* PerformanceTrackingData::endTime() const {
3540   return const_cast<const struct timeval*>(&m_performanceTracker->m_endTime);
3541 }
3542 inline const struct timeval* PerformanceTrackingData::lastCheckpointTime() const {
3543   return const_cast<const struct timeval*>(&m_performanceTracker->m_lastCheckpointTime);
3544 }
3545 inline const std::string& PerformanceTrackingData::loggerId(void) const {
3546   return m_performanceTracker->m_loggerId;
3547 }
3548 #endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
3549 namespace base {
3550 /// @brief Contains some internal debugging tools like crash handler and stack tracer
3551 namespace debug {
3552 #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
3553 class StackTrace : base::NoCopy {
3554  public:
3555   static const unsigned int kMaxStack = 64;
3556   static const unsigned int kStackStart = 2;  // We want to skip c'tor and StackTrace::generateNew()
3557   class StackTraceEntry {
3558    public:
3559     StackTraceEntry(std::size_t index, const std::string& loc, const std::string& demang, const std::string& hex,
3560                     const std::string& addr);
3561     StackTraceEntry(std::size_t index, const std::string& loc) :
3562       m_index(index),
3563       m_location(loc) {
3564     }
3565     std::size_t m_index;
3566     std::string m_location;
3567     std::string m_demangled;
3568     std::string m_hex;
3569     std::string m_addr;
3570     friend std::ostream& operator<<(std::ostream& ss, const StackTraceEntry& si);
3571 
3572    private:
3573     StackTraceEntry(void);
3574   };
3575 
3576   StackTrace(void) {
3577     generateNew();
3578   }
3579 
3580   virtual ~StackTrace(void) {
3581   }
3582 
3583   inline std::vector<StackTraceEntry>& getLatestStack(void) {
3584     return m_stack;
3585   }
3586 
3587   friend std::ostream& operator<<(std::ostream& os, const StackTrace& st);
3588 
3589  private:
3590   std::vector<StackTraceEntry> m_stack;
3591 
3592   void generateNew(void);
3593 };
3594 /// @brief Handles unexpected crashes
3595 class CrashHandler : base::NoCopy {
3596  public:
3597   typedef void (*Handler)(int);
3598 
3599   explicit CrashHandler(bool useDefault);
3600   explicit CrashHandler(const Handler& cHandler) {
3601     setHandler(cHandler);
3602   }
3603   void setHandler(const Handler& cHandler);
3604 
3605  private:
3606   Handler m_handler;
3607 };
3608 #else
3609 class CrashHandler {
3610  public:
3611   explicit CrashHandler(bool) {}
3612 };
3613 #endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
3614 }  // namespace debug
3615 }  // namespace base
3616 extern base::debug::CrashHandler elCrashHandler;
3617 #define MAKE_LOGGABLE(ClassType, ClassInstance, OutputStreamInstance) \
3618 el::base::type::ostream_t& operator<<(el::base::type::ostream_t& OutputStreamInstance, const ClassType& ClassInstance)
3619 /// @brief Initializes syslog with process ID, options and facility. calls closelog() on d'tor
3620 class SysLogInitializer {
3621  public:
3622   SysLogInitializer(const char* processIdent, int options = 0, int facility = 0) {
3623 #if defined(ELPP_SYSLOG)
3624     openlog(processIdent, options, facility);
3625 #else
3626     ELPP_UNUSED(processIdent);
3627     ELPP_UNUSED(options);
3628     ELPP_UNUSED(facility);
3629 #endif  // defined(ELPP_SYSLOG)
3630   }
3631   virtual ~SysLogInitializer(void) {
3632 #if defined(ELPP_SYSLOG)
3633     closelog();
3634 #endif  // defined(ELPP_SYSLOG)
3635   }
3636 };
3637 #define ELPP_INITIALIZE_SYSLOG(id, opt, fac) el::SysLogInitializer elSyslogInit(id, opt, fac)
3638 /// @brief Static helpers for developers
3639 class Helpers : base::StaticClass {
3640  public:
3641   /// @brief Shares logging repository (base::Storage)
3642   static inline void setStorage(base::type::StoragePointer storage) {
3643     ELPP = storage;
3644   }
3645   /// @return Main storage repository
3646   static inline base::type::StoragePointer storage() {
3647     return ELPP;
3648   }
3649   /// @brief Sets application arguments and figures out whats active for logging and whats not.
3650   static inline void setArgs(int argc, char** argv) {
3651     ELPP->setApplicationArguments(argc, argv);
3652   }
3653   /// @copydoc setArgs(int argc, char** argv)
3654   static inline void setArgs(int argc, const char** argv) {
3655     ELPP->setApplicationArguments(argc, const_cast<char**>(argv));
3656   }
3657   /// @brief Sets thread name for current thread. Requires std::thread
3658   static inline void setThreadName(const std::string& name) {
3659     ELPP->setThreadName(name);
3660   }
3661   static inline std::string getThreadName() {
3662     return ELPP->getThreadName(base::threading::getCurrentThreadId());
3663   }
3664 #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
3665   /// @brief Overrides default crash handler and installs custom handler.
3666   /// @param crashHandler A functor with no return type that takes single int argument.
3667   ///        Handler is a typedef with specification: void (*Handler)(int)
3668   static inline void setCrashHandler(const el::base::debug::CrashHandler::Handler& crashHandler) {
3669     el::elCrashHandler.setHandler(crashHandler);
3670   }
3671   /// @brief Abort due to crash with signal in parameter
3672   /// @param sig Crash signal
3673   static void crashAbort(int sig, const char* sourceFile = "", unsigned int long line = 0);
3674   /// @brief Logs reason of crash as per sig
3675   /// @param sig Crash signal
3676   /// @param stackTraceIfAvailable Includes stack trace if available
3677   /// @param level Logging level
3678   /// @param logger Logger to use for logging
3679   static void logCrashReason(int sig, bool stackTraceIfAvailable = false,
3680                              Level level = Level::Fatal, const char* logger = base::consts::kDefaultLoggerId);
3681 #endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
3682   /// @brief Installs pre rollout callback, this callback is triggered when log file is about to be rolled out
3683   ///        (can be useful for backing up)
3684   static inline void installPreRollOutCallback(const PreRollOutCallback& callback) {
3685     ELPP->setPreRollOutCallback(callback);
3686   }
3687   /// @brief Uninstalls pre rollout callback
3688   static inline void uninstallPreRollOutCallback(void) {
3689     ELPP->unsetPreRollOutCallback();
3690   }
3691   /// @brief Installs post log dispatch callback, this callback is triggered when log is dispatched
3692   template <typename T>
3693   static inline bool installLogDispatchCallback(const std::string& id) {
3694     return ELPP->installLogDispatchCallback<T>(id);
3695   }
3696   /// @brief Uninstalls log dispatch callback
3697   template <typename T>
3698   static inline void uninstallLogDispatchCallback(const std::string& id) {
3699     ELPP->uninstallLogDispatchCallback<T>(id);
3700   }
3701   template <typename T>
3702   static inline T* logDispatchCallback(const std::string& id) {
3703     return ELPP->logDispatchCallback<T>(id);
3704   }
3705 #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
3706   /// @brief Installs post performance tracking callback, this callback is triggered when performance tracking is finished
3707   template <typename T>
3708   static inline bool installPerformanceTrackingCallback(const std::string& id) {
3709     return ELPP->installPerformanceTrackingCallback<T>(id);
3710   }
3711   /// @brief Uninstalls post performance tracking handler
3712   template <typename T>
3713   static inline void uninstallPerformanceTrackingCallback(const std::string& id) {
3714     ELPP->uninstallPerformanceTrackingCallback<T>(id);
3715   }
3716   template <typename T>
3717   static inline T* performanceTrackingCallback(const std::string& id) {
3718     return ELPP->performanceTrackingCallback<T>(id);
3719   }
3720 #endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
3721   /// @brief Converts template to std::string - useful for loggable classes to log containers within log(std::ostream&) const
3722   template <typename T>
3723   static std::string convertTemplateToStdString(const T& templ) {
3724     el::Logger* logger =
3725       ELPP->registeredLoggers()->get(el::base::consts::kDefaultLoggerId);
3726     if (logger == nullptr) {
3727       return std::string();
3728     }
3729     base::MessageBuilder b;
3730     b.initialize(logger);
3731     logger->acquireLock();
3732     b << templ;
3733 #if defined(ELPP_UNICODE)
3734     std::string s = std::string(logger->stream().str().begin(), logger->stream().str().end());
3735 #else
3736     std::string s = logger->stream().str();
3737 #endif  // defined(ELPP_UNICODE)
3738     logger->stream().str(ELPP_LITERAL(""));
3739     logger->releaseLock();
3740     return s;
3741   }
3742   /// @brief Returns command line arguments (pointer) provided to easylogging++
3743   static inline const el::base::utils::CommandLineArgs* commandLineArgs(void) {
3744     return ELPP->commandLineArgs();
3745   }
3746   /// @brief Reserve space for custom format specifiers for performance
3747   /// @see std::vector::reserve
3748   static inline void reserveCustomFormatSpecifiers(std::size_t size) {
3749     ELPP->m_customFormatSpecifiers.reserve(size);
3750   }
3751   /// @brief Installs user defined format specifier and handler
3752   static inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) {
3753     ELPP->installCustomFormatSpecifier(customFormatSpecifier);
3754   }
3755   /// @brief Uninstalls user defined format specifier and handler
3756   static inline bool uninstallCustomFormatSpecifier(const char* formatSpecifier) {
3757     return ELPP->uninstallCustomFormatSpecifier(formatSpecifier);
3758   }
3759   /// @brief Returns true if custom format specifier is installed
3760   static inline bool hasCustomFormatSpecifier(const char* formatSpecifier) {
3761     return ELPP->hasCustomFormatSpecifier(formatSpecifier);
3762   }
3763   static inline void validateFileRolling(Logger* logger, Level level) {
3764     if (logger == nullptr) return;
3765     logger->m_typedConfigurations->validateFileRolling(level, ELPP->preRollOutCallback());
3766   }
3767 };
3768 /// @brief Static helpers to deal with loggers and their configurations
3769 class Loggers : base::StaticClass {
3770  public:
3771   /// @brief Gets existing or registers new logger
3772   static Logger* getLogger(const std::string& identity, bool registerIfNotAvailable = true);
3773   /// @brief Changes default log builder for future loggers
3774   static void setDefaultLogBuilder(el::LogBuilderPtr& logBuilderPtr);
3775   /// @brief Installs logger registration callback, this callback is triggered when new logger is registered
3776   template <typename T>
3777   static inline bool installLoggerRegistrationCallback(const std::string& id) {
3778     return ELPP->registeredLoggers()->installLoggerRegistrationCallback<T>(id);
3779   }
3780   /// @brief Uninstalls log dispatch callback
3781   template <typename T>
3782   static inline void uninstallLoggerRegistrationCallback(const std::string& id) {
3783     ELPP->registeredLoggers()->uninstallLoggerRegistrationCallback<T>(id);
3784   }
3785   template <typename T>
3786   static inline T* loggerRegistrationCallback(const std::string& id) {
3787     return ELPP->registeredLoggers()->loggerRegistrationCallback<T>(id);
3788   }
3789   /// @brief Unregisters logger - use it only when you know what you are doing, you may unregister
3790   ///        loggers initialized / used by third-party libs.
3791   static bool unregisterLogger(const std::string& identity);
3792   /// @brief Whether or not logger with id is registered
3793   static bool hasLogger(const std::string& identity);
3794   /// @brief Reconfigures specified logger with new configurations
3795   static Logger* reconfigureLogger(Logger* logger, const Configurations& configurations);
3796   /// @brief Reconfigures logger with new configurations after looking it up using identity
3797   static Logger* reconfigureLogger(const std::string& identity, const Configurations& configurations);
3798   /// @brief Reconfigures logger's single configuration
3799   static Logger* reconfigureLogger(const std::string& identity, ConfigurationType configurationType,
3800                                    const std::string& value);
3801   /// @brief Reconfigures all the existing loggers with new configurations
3802   static void reconfigureAllLoggers(const Configurations& configurations);
3803   /// @brief Reconfigures single configuration for all the loggers
3804   static inline void reconfigureAllLoggers(ConfigurationType configurationType, const std::string& value) {
3805     reconfigureAllLoggers(Level::Global, configurationType, value);
3806   }
3807   /// @brief Reconfigures single configuration for all the loggers for specified level
3808   static void reconfigureAllLoggers(Level level, ConfigurationType configurationType,
3809                                     const std::string& value);
3810   /// @brief Sets default configurations. This configuration is used for future (and conditionally for existing) loggers
3811   static void setDefaultConfigurations(const Configurations& configurations,
3812                                        bool reconfigureExistingLoggers = false);
3813   /// @brief Returns current default
3814   static const Configurations* defaultConfigurations(void);
3815   /// @brief Returns log stream reference pointer if needed by user
3816   static const base::LogStreamsReferenceMap* logStreamsReference(void);
3817   /// @brief Default typed configuration based on existing defaultConf
3818   static base::TypedConfigurations defaultTypedConfigurations(void);
3819   /// @brief Populates all logger IDs in current repository.
3820   /// @param [out] targetList List of fill up.
3821   static std::vector<std::string>* populateAllLoggerIds(std::vector<std::string>* targetList);
3822   /// @brief Sets configurations from global configuration file.
3823   static void configureFromGlobal(const char* globalConfigurationFilePath);
3824   /// @brief Configures loggers using command line arg. Ensure you have already set command line args,
3825   /// @return False if invalid argument or argument with no value provided, true if attempted to configure logger.
3826   ///         If true is returned that does not mean it has been configured successfully, it only means that it
3827   ///         has attempeted to configure logger using configuration file provided in argument
3828   static bool configureFromArg(const char* argKey);
3829   /// @brief Flushes all loggers for all levels - Be careful if you dont know how many loggers are registered
3830   static void flushAll(void);
3831   /// @brief Adds logging flag used internally.
3832   static inline void addFlag(LoggingFlag flag) {
3833     ELPP->addFlag(flag);
3834   }
3835   /// @brief Removes logging flag used internally.
3836   static inline void removeFlag(LoggingFlag flag) {
3837     ELPP->removeFlag(flag);
3838   }
3839   /// @brief Determines whether or not certain flag is active
3840   static inline bool hasFlag(LoggingFlag flag) {
3841     return ELPP->hasFlag(flag);
3842   }
3843   /// @brief Adds flag and removes it when scope goes out
3844   class ScopedAddFlag {
3845    public:
3846     ScopedAddFlag(LoggingFlag flag) : m_flag(flag) {
3847       Loggers::addFlag(m_flag);
3848     }
3849     ~ScopedAddFlag(void) {
3850       Loggers::removeFlag(m_flag);
3851     }
3852    private:
3853     LoggingFlag m_flag;
3854   };
3855   /// @brief Removes flag and add it when scope goes out
3856   class ScopedRemoveFlag {
3857    public:
3858     ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) {
3859       Loggers::removeFlag(m_flag);
3860     }
3861     ~ScopedRemoveFlag(void) {
3862       Loggers::addFlag(m_flag);
3863     }
3864    private:
3865     LoggingFlag m_flag;
3866   };
3867   /// @brief Sets hierarchy for logging. Needs to enable logging flag (HierarchicalLogging)
3868   static void setLoggingLevel(Level level) {
3869     ELPP->setLoggingLevel(level);
3870   }
3871   /// @brief Sets verbose level on the fly
3872   static void setVerboseLevel(base::type::VerboseLevel level);
3873   /// @brief Gets current verbose level
3874   static base::type::VerboseLevel verboseLevel(void);
3875   /// @brief Sets vmodules as specified (on the fly)
3876   static void setVModules(const char* modules);
3877   /// @brief Clears vmodules
3878   static void clearVModules(void);
3879 };
3880 class VersionInfo : base::StaticClass {
3881  public:
3882   /// @brief Current version number
3883   static const std::string version(void);
3884 
3885   /// @brief Release date of current version
3886   static const std::string releaseDate(void);
3887 };
3888 }  // namespace el
3889 #undef VLOG_IS_ON
3890 /// @brief Determines whether verbose logging is on for specified level current file.
3891 #define VLOG_IS_ON(verboseLevel) (ELPP->vRegistry()->allowed(verboseLevel, __FILE__))
3892 #undef TIMED_BLOCK
3893 #undef TIMED_SCOPE
3894 #undef TIMED_SCOPE_IF
3895 #undef TIMED_FUNC
3896 #undef TIMED_FUNC_IF
3897 #undef ELPP_MIN_UNIT
3898 #if defined(ELPP_PERFORMANCE_MICROSECONDS)
3899 #  define ELPP_MIN_UNIT el::base::TimestampUnit::Microsecond
3900 #else
3901 #  define ELPP_MIN_UNIT el::base::TimestampUnit::Millisecond
3902 #endif  // (defined(ELPP_PERFORMANCE_MICROSECONDS))
3903 /// @brief Performance tracked scope. Performance gets written when goes out of scope using
3904 ///        'performance' logger.
3905 ///
3906 /// @detail Please note in order to check the performance at a certain time you can use obj->checkpoint();
3907 /// @see el::base::PerformanceTracker
3908 /// @see el::base::PerformanceTracker::checkpoint
3909 // Note: Do not surround this definition with null macro because of obj instance
3910 #define TIMED_SCOPE_IF(obj, blockname, condition) el::base::type::PerformanceTrackerPtr obj( condition ? \
3911   new el::base::PerformanceTracker(blockname, ELPP_MIN_UNIT) : nullptr )
3912 #define TIMED_SCOPE(obj, blockname) TIMED_SCOPE_IF(obj, blockname, true)
3913 #define TIMED_BLOCK(obj, blockName) for (struct { int i; el::base::type::PerformanceTrackerPtr timer; } obj = { 0, \
3914   el::base::type::PerformanceTrackerPtr(new el::base::PerformanceTracker(blockName, ELPP_MIN_UNIT)) }; obj.i < 1; ++obj.i)
3915 /// @brief Performance tracked function. Performance gets written when goes out of scope using
3916 ///        'performance' logger.
3917 ///
3918 /// @detail Please note in order to check the performance at a certain time you can use obj->checkpoint();
3919 /// @see el::base::PerformanceTracker
3920 /// @see el::base::PerformanceTracker::checkpoint
3921 #define TIMED_FUNC_IF(obj,condition) TIMED_SCOPE_IF(obj, ELPP_FUNC, condition)
3922 #define TIMED_FUNC(obj) TIMED_SCOPE(obj, ELPP_FUNC)
3923 #undef PERFORMANCE_CHECKPOINT
3924 #undef PERFORMANCE_CHECKPOINT_WITH_ID
3925 #define PERFORMANCE_CHECKPOINT(obj) obj->checkpoint(std::string(), __FILE__, __LINE__, ELPP_FUNC)
3926 #define PERFORMANCE_CHECKPOINT_WITH_ID(obj, id) obj->checkpoint(id, __FILE__, __LINE__, ELPP_FUNC)
3927 #undef ELPP_COUNTER
3928 #undef ELPP_COUNTER_POS
3929 /// @brief Gets hit counter for file/line
3930 #define ELPP_COUNTER (ELPP->hitCounters()->getCounter(__FILE__, __LINE__))
3931 /// @brief Gets hit counter position for file/line, -1 if not registered yet
3932 #define ELPP_COUNTER_POS (ELPP_COUNTER == nullptr ? -1 : ELPP_COUNTER->hitCounts())
3933 // Undef levels to support LOG(LEVEL)
3934 #undef INFO
3935 #undef WARNING
3936 #undef DEBUG
3937 #undef ERROR
3938 #undef FATAL
3939 #undef TRACE
3940 #undef VERBOSE
3941 // Undef existing
3942 #undef CINFO
3943 #undef CWARNING
3944 #undef CDEBUG
3945 #undef CFATAL
3946 #undef CERROR
3947 #undef CTRACE
3948 #undef CVERBOSE
3949 #undef CINFO_IF
3950 #undef CWARNING_IF
3951 #undef CDEBUG_IF
3952 #undef CERROR_IF
3953 #undef CFATAL_IF
3954 #undef CTRACE_IF
3955 #undef CVERBOSE_IF
3956 #undef CINFO_EVERY_N
3957 #undef CWARNING_EVERY_N
3958 #undef CDEBUG_EVERY_N
3959 #undef CERROR_EVERY_N
3960 #undef CFATAL_EVERY_N
3961 #undef CTRACE_EVERY_N
3962 #undef CVERBOSE_EVERY_N
3963 #undef CINFO_AFTER_N
3964 #undef CWARNING_AFTER_N
3965 #undef CDEBUG_AFTER_N
3966 #undef CERROR_AFTER_N
3967 #undef CFATAL_AFTER_N
3968 #undef CTRACE_AFTER_N
3969 #undef CVERBOSE_AFTER_N
3970 #undef CINFO_N_TIMES
3971 #undef CWARNING_N_TIMES
3972 #undef CDEBUG_N_TIMES
3973 #undef CERROR_N_TIMES
3974 #undef CFATAL_N_TIMES
3975 #undef CTRACE_N_TIMES
3976 #undef CVERBOSE_N_TIMES
3977 // Normal logs
3978 #if ELPP_INFO_LOG
3979 #  define CINFO(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Info, dispatchAction, __VA_ARGS__)
3980 #else
3981 #  define CINFO(writer, dispatchAction, ...) el::base::NullWriter()
3982 #endif  // ELPP_INFO_LOG
3983 #if ELPP_WARNING_LOG
3984 #  define CWARNING(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Warning, dispatchAction, __VA_ARGS__)
3985 #else
3986 #  define CWARNING(writer, dispatchAction, ...) el::base::NullWriter()
3987 #endif  // ELPP_WARNING_LOG
3988 #if ELPP_DEBUG_LOG
3989 #  define CDEBUG(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__)
3990 #else
3991 #  define CDEBUG(writer, dispatchAction, ...) el::base::NullWriter()
3992 #endif  // ELPP_DEBUG_LOG
3993 #if ELPP_ERROR_LOG
3994 #  define CERROR(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Error, dispatchAction, __VA_ARGS__)
3995 #else
3996 #  define CERROR(writer, dispatchAction, ...) el::base::NullWriter()
3997 #endif  // ELPP_ERROR_LOG
3998 #if ELPP_FATAL_LOG
3999 #  define CFATAL(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Fatal, dispatchAction, __VA_ARGS__)
4000 #else
4001 #  define CFATAL(writer, dispatchAction, ...) el::base::NullWriter()
4002 #endif  // ELPP_FATAL_LOG
4003 #if ELPP_TRACE_LOG
4004 #  define CTRACE(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Trace, dispatchAction, __VA_ARGS__)
4005 #else
4006 #  define CTRACE(writer, dispatchAction, ...) el::base::NullWriter()
4007 #endif  // ELPP_TRACE_LOG
4008 #if ELPP_VERBOSE_LOG
4009 #  define CVERBOSE(writer, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel)) writer(\
4010 el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
4011 #else
4012 #  define CVERBOSE(writer, vlevel, dispatchAction, ...) el::base::NullWriter()
4013 #endif  // ELPP_VERBOSE_LOG
4014 // Conditional logs
4015 #if ELPP_INFO_LOG
4016 #  define CINFO_IF(writer, condition_, dispatchAction, ...) \
4017 ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Info, dispatchAction, __VA_ARGS__)
4018 #else
4019 #  define CINFO_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
4020 #endif  // ELPP_INFO_LOG
4021 #if ELPP_WARNING_LOG
4022 #  define CWARNING_IF(writer, condition_, dispatchAction, ...)\
4023 ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Warning, dispatchAction, __VA_ARGS__)
4024 #else
4025 #  define CWARNING_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
4026 #endif  // ELPP_WARNING_LOG
4027 #if ELPP_DEBUG_LOG
4028 #  define CDEBUG_IF(writer, condition_, dispatchAction, ...)\
4029 ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Debug, dispatchAction, __VA_ARGS__)
4030 #else
4031 #  define CDEBUG_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
4032 #endif  // ELPP_DEBUG_LOG
4033 #if ELPP_ERROR_LOG
4034 #  define CERROR_IF(writer, condition_, dispatchAction, ...)\
4035 ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Error, dispatchAction, __VA_ARGS__)
4036 #else
4037 #  define CERROR_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
4038 #endif  // ELPP_ERROR_LOG
4039 #if ELPP_FATAL_LOG
4040 #  define CFATAL_IF(writer, condition_, dispatchAction, ...)\
4041 ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Fatal, dispatchAction, __VA_ARGS__)
4042 #else
4043 #  define CFATAL_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
4044 #endif  // ELPP_FATAL_LOG
4045 #if ELPP_TRACE_LOG
4046 #  define CTRACE_IF(writer, condition_, dispatchAction, ...)\
4047 ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Trace, dispatchAction, __VA_ARGS__)
4048 #else
4049 #  define CTRACE_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
4050 #endif  // ELPP_TRACE_LOG
4051 #if ELPP_VERBOSE_LOG
4052 #  define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel) && (condition_)) writer( \
4053 el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
4054 #else
4055 #  define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) el::base::NullWriter()
4056 #endif  // ELPP_VERBOSE_LOG
4057 // Occasional logs
4058 #if ELPP_INFO_LOG
4059 #  define CINFO_EVERY_N(writer, occasion, dispatchAction, ...)\
4060 ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Info, dispatchAction, __VA_ARGS__)
4061 #else
4062 #  define CINFO_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
4063 #endif  // ELPP_INFO_LOG
4064 #if ELPP_WARNING_LOG
4065 #  define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...)\
4066 ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Warning, dispatchAction, __VA_ARGS__)
4067 #else
4068 #  define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
4069 #endif  // ELPP_WARNING_LOG
4070 #if ELPP_DEBUG_LOG
4071 #  define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...)\
4072 ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Debug, dispatchAction, __VA_ARGS__)
4073 #else
4074 #  define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
4075 #endif  // ELPP_DEBUG_LOG
4076 #if ELPP_ERROR_LOG
4077 #  define CERROR_EVERY_N(writer, occasion, dispatchAction, ...)\
4078 ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Error, dispatchAction, __VA_ARGS__)
4079 #else
4080 #  define CERROR_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
4081 #endif  // ELPP_ERROR_LOG
4082 #if ELPP_FATAL_LOG
4083 #  define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...)\
4084 ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Fatal, dispatchAction, __VA_ARGS__)
4085 #else
4086 #  define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
4087 #endif  // ELPP_FATAL_LOG
4088 #if ELPP_TRACE_LOG
4089 #  define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...)\
4090 ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Trace, dispatchAction, __VA_ARGS__)
4091 #else
4092 #  define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
4093 #endif  // ELPP_TRACE_LOG
4094 #if ELPP_VERBOSE_LOG
4095 #  define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...)\
4096 CVERBOSE_IF(writer, ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion), vlevel, dispatchAction, __VA_ARGS__)
4097 #else
4098 #  define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...) el::base::NullWriter()
4099 #endif  // ELPP_VERBOSE_LOG
4100 // After N logs
4101 #if ELPP_INFO_LOG
4102 #  define CINFO_AFTER_N(writer, n, dispatchAction, ...)\
4103 ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)
4104 #else
4105 #  define CINFO_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
4106 #endif  // ELPP_INFO_LOG
4107 #if ELPP_WARNING_LOG
4108 #  define CWARNING_AFTER_N(writer, n, dispatchAction, ...)\
4109 ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)
4110 #else
4111 #  define CWARNING_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
4112 #endif  // ELPP_WARNING_LOG
4113 #if ELPP_DEBUG_LOG
4114 #  define CDEBUG_AFTER_N(writer, n, dispatchAction, ...)\
4115 ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)
4116 #else
4117 #  define CDEBUG_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
4118 #endif  // ELPP_DEBUG_LOG
4119 #if ELPP_ERROR_LOG
4120 #  define CERROR_AFTER_N(writer, n, dispatchAction, ...)\
4121 ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)
4122 #else
4123 #  define CERROR_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
4124 #endif  // ELPP_ERROR_LOG
4125 #if ELPP_FATAL_LOG
4126 #  define CFATAL_AFTER_N(writer, n, dispatchAction, ...)\
4127 ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)
4128 #else
4129 #  define CFATAL_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
4130 #endif  // ELPP_FATAL_LOG
4131 #if ELPP_TRACE_LOG
4132 #  define CTRACE_AFTER_N(writer, n, dispatchAction, ...)\
4133 ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)
4134 #else
4135 #  define CTRACE_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
4136 #endif  // ELPP_TRACE_LOG
4137 #if ELPP_VERBOSE_LOG
4138 #  define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...)\
4139 CVERBOSE_IF(writer, ELPP->validateAfterNCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__)
4140 #else
4141 #  define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter()
4142 #endif  // ELPP_VERBOSE_LOG
4143 // N Times logs
4144 #if ELPP_INFO_LOG
4145 #  define CINFO_N_TIMES(writer, n, dispatchAction, ...)\
4146 ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)
4147 #else
4148 #  define CINFO_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
4149 #endif  // ELPP_INFO_LOG
4150 #if ELPP_WARNING_LOG
4151 #  define CWARNING_N_TIMES(writer, n, dispatchAction, ...)\
4152 ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)
4153 #else
4154 #  define CWARNING_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
4155 #endif  // ELPP_WARNING_LOG
4156 #if ELPP_DEBUG_LOG
4157 #  define CDEBUG_N_TIMES(writer, n, dispatchAction, ...)\
4158 ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)
4159 #else
4160 #  define CDEBUG_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
4161 #endif  // ELPP_DEBUG_LOG
4162 #if ELPP_ERROR_LOG
4163 #  define CERROR_N_TIMES(writer, n, dispatchAction, ...)\
4164 ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)
4165 #else
4166 #  define CERROR_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
4167 #endif  // ELPP_ERROR_LOG
4168 #if ELPP_FATAL_LOG
4169 #  define CFATAL_N_TIMES(writer, n, dispatchAction, ...)\
4170 ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)
4171 #else
4172 #  define CFATAL_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
4173 #endif  // ELPP_FATAL_LOG
4174 #if ELPP_TRACE_LOG
4175 #  define CTRACE_N_TIMES(writer, n, dispatchAction, ...)\
4176 ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)
4177 #else
4178 #  define CTRACE_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
4179 #endif  // ELPP_TRACE_LOG
4180 #if ELPP_VERBOSE_LOG
4181 #  define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...)\
4182 CVERBOSE_IF(writer, ELPP->validateNTimesCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__)
4183 #else
4184 #  define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter()
4185 #endif  // ELPP_VERBOSE_LOG
4186 //
4187 // Custom Loggers - Requires (level, dispatchAction, loggerId/s)
4188 //
4189 // undef existing
4190 #undef CLOG
4191 #undef CLOG_VERBOSE
4192 #undef CVLOG
4193 #undef CLOG_IF
4194 #undef CLOG_VERBOSE_IF
4195 #undef CVLOG_IF
4196 #undef CLOG_EVERY_N
4197 #undef CVLOG_EVERY_N
4198 #undef CLOG_AFTER_N
4199 #undef CVLOG_AFTER_N
4200 #undef CLOG_N_TIMES
4201 #undef CVLOG_N_TIMES
4202 // Normal logs
4203 #define CLOG(LEVEL, ...)\
4204 C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4205 #define CVLOG(vlevel, ...) CVERBOSE(el::base::Writer, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4206 // Conditional logs
4207 #define CLOG_IF(condition, LEVEL, ...)\
4208 C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4209 #define CVLOG_IF(condition, vlevel, ...)\
4210 CVERBOSE_IF(el::base::Writer, condition, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4211 // Hit counts based logs
4212 #define CLOG_EVERY_N(n, LEVEL, ...)\
4213 C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4214 #define CVLOG_EVERY_N(n, vlevel, ...)\
4215 CVERBOSE_EVERY_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4216 #define CLOG_AFTER_N(n, LEVEL, ...)\
4217 C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4218 #define CVLOG_AFTER_N(n, vlevel, ...)\
4219 CVERBOSE_AFTER_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4220 #define CLOG_N_TIMES(n, LEVEL, ...)\
4221 C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4222 #define CVLOG_N_TIMES(n, vlevel, ...)\
4223 CVERBOSE_N_TIMES(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4224 //
4225 // Default Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros
4226 //
4227 // undef existing
4228 #undef LOG
4229 #undef VLOG
4230 #undef LOG_IF
4231 #undef VLOG_IF
4232 #undef LOG_EVERY_N
4233 #undef VLOG_EVERY_N
4234 #undef LOG_AFTER_N
4235 #undef VLOG_AFTER_N
4236 #undef LOG_N_TIMES
4237 #undef VLOG_N_TIMES
4238 #undef ELPP_CURR_FILE_LOGGER_ID
4239 #if defined(ELPP_DEFAULT_LOGGER)
4240 #  define ELPP_CURR_FILE_LOGGER_ID ELPP_DEFAULT_LOGGER
4241 #else
4242 #  define ELPP_CURR_FILE_LOGGER_ID el::base::consts::kDefaultLoggerId
4243 #endif
4244 #undef ELPP_TRACE
4245 #define ELPP_TRACE CLOG(TRACE, ELPP_CURR_FILE_LOGGER_ID)
4246 // Normal logs
4247 #define LOG(LEVEL) CLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4248 #define VLOG(vlevel) CVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID)
4249 // Conditional logs
4250 #define LOG_IF(condition, LEVEL) CLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4251 #define VLOG_IF(condition, vlevel) CVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID)
4252 // Hit counts based logs
4253 #define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4254 #define VLOG_EVERY_N(n, vlevel) CVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
4255 #define LOG_AFTER_N(n, LEVEL) CLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4256 #define VLOG_AFTER_N(n, vlevel) CVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
4257 #define LOG_N_TIMES(n, LEVEL) CLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4258 #define VLOG_N_TIMES(n, vlevel) CVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
4259 // Generic PLOG()
4260 #undef CPLOG
4261 #undef CPLOG_IF
4262 #undef PLOG
4263 #undef PLOG_IF
4264 #undef DCPLOG
4265 #undef DCPLOG_IF
4266 #undef DPLOG
4267 #undef DPLOG_IF
4268 #define CPLOG(LEVEL, ...)\
4269 C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4270 #define CPLOG_IF(condition, LEVEL, ...)\
4271 C##LEVEL##_IF(el::base::PErrorWriter, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4272 #define DCPLOG(LEVEL, ...)\
4273 if (ELPP_DEBUG_LOG) C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__)
4274 #define DCPLOG_IF(condition, LEVEL, ...)\
4275 C##LEVEL##_IF(el::base::PErrorWriter, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::NormalLog, __VA_ARGS__)
4276 #define PLOG(LEVEL) CPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4277 #define PLOG_IF(condition, LEVEL) CPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4278 #define DPLOG(LEVEL) DCPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4279 #define DPLOG_IF(condition, LEVEL) DCPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4280 // Generic SYSLOG()
4281 #undef CSYSLOG
4282 #undef CSYSLOG_IF
4283 #undef CSYSLOG_EVERY_N
4284 #undef CSYSLOG_AFTER_N
4285 #undef CSYSLOG_N_TIMES
4286 #undef SYSLOG
4287 #undef SYSLOG_IF
4288 #undef SYSLOG_EVERY_N
4289 #undef SYSLOG_AFTER_N
4290 #undef SYSLOG_N_TIMES
4291 #undef DCSYSLOG
4292 #undef DCSYSLOG_IF
4293 #undef DCSYSLOG_EVERY_N
4294 #undef DCSYSLOG_AFTER_N
4295 #undef DCSYSLOG_N_TIMES
4296 #undef DSYSLOG
4297 #undef DSYSLOG_IF
4298 #undef DSYSLOG_EVERY_N
4299 #undef DSYSLOG_AFTER_N
4300 #undef DSYSLOG_N_TIMES
4301 #if defined(ELPP_SYSLOG)
4302 #  define CSYSLOG(LEVEL, ...)\
4303 C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__)
4304 #  define CSYSLOG_IF(condition, LEVEL, ...)\
4305 C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::SysLog, __VA_ARGS__)
4306 #  define CSYSLOG_EVERY_N(n, LEVEL, ...) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
4307 #  define CSYSLOG_AFTER_N(n, LEVEL, ...) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
4308 #  define CSYSLOG_N_TIMES(n, LEVEL, ...) C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
4309 #  define SYSLOG(LEVEL) CSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId)
4310 #  define SYSLOG_IF(condition, LEVEL) CSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId)
4311 #  define SYSLOG_EVERY_N(n, LEVEL) CSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
4312 #  define SYSLOG_AFTER_N(n, LEVEL) CSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
4313 #  define SYSLOG_N_TIMES(n, LEVEL) CSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId)
4314 #  define DCSYSLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__)
4315 #  define DCSYSLOG_IF(condition, LEVEL, ...)\
4316 C##LEVEL##_IF(el::base::Writer, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::SysLog, __VA_ARGS__)
4317 #  define DCSYSLOG_EVERY_N(n, LEVEL, ...)\
4318 if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
4319 #  define DCSYSLOG_AFTER_N(n, LEVEL, ...)\
4320 if (ELPP_DEBUG_LOG) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
4321 #  define DCSYSLOG_N_TIMES(n, LEVEL, ...)\
4322 if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
4323 #  define DSYSLOG(LEVEL) DCSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId)
4324 #  define DSYSLOG_IF(condition, LEVEL) DCSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId)
4325 #  define DSYSLOG_EVERY_N(n, LEVEL) DCSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
4326 #  define DSYSLOG_AFTER_N(n, LEVEL) DCSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
4327 #  define DSYSLOG_N_TIMES(n, LEVEL) DCSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId)
4328 #else
4329 #  define CSYSLOG(LEVEL, ...) el::base::NullWriter()
4330 #  define CSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter()
4331 #  define CSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter()
4332 #  define CSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter()
4333 #  define CSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter()
4334 #  define SYSLOG(LEVEL) el::base::NullWriter()
4335 #  define SYSLOG_IF(condition, LEVEL) el::base::NullWriter()
4336 #  define SYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter()
4337 #  define SYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter()
4338 #  define SYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter()
4339 #  define DCSYSLOG(LEVEL, ...) el::base::NullWriter()
4340 #  define DCSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter()
4341 #  define DCSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter()
4342 #  define DCSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter()
4343 #  define DCSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter()
4344 #  define DSYSLOG(LEVEL) el::base::NullWriter()
4345 #  define DSYSLOG_IF(condition, LEVEL) el::base::NullWriter()
4346 #  define DSYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter()
4347 #  define DSYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter()
4348 #  define DSYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter()
4349 #endif  // defined(ELPP_SYSLOG)
4350 //
4351 // Custom Debug Only Loggers - Requires (level, loggerId/s)
4352 //
4353 // undef existing
4354 #undef DCLOG
4355 #undef DCVLOG
4356 #undef DCLOG_IF
4357 #undef DCVLOG_IF
4358 #undef DCLOG_EVERY_N
4359 #undef DCVLOG_EVERY_N
4360 #undef DCLOG_AFTER_N
4361 #undef DCVLOG_AFTER_N
4362 #undef DCLOG_N_TIMES
4363 #undef DCVLOG_N_TIMES
4364 // Normal logs
4365 #define DCLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG(LEVEL, __VA_ARGS__)
4366 #define DCLOG_VERBOSE(vlevel, ...) if (ELPP_DEBUG_LOG) CLOG_VERBOSE(vlevel, __VA_ARGS__)
4367 #define DCVLOG(vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG(vlevel, __VA_ARGS__)
4368 // Conditional logs
4369 #define DCLOG_IF(condition, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_IF(condition, LEVEL, __VA_ARGS__)
4370 #define DCVLOG_IF(condition, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_IF(condition, vlevel, __VA_ARGS__)
4371 // Hit counts based logs
4372 #define DCLOG_EVERY_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_EVERY_N(n, LEVEL, __VA_ARGS__)
4373 #define DCVLOG_EVERY_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_EVERY_N(n, vlevel, __VA_ARGS__)
4374 #define DCLOG_AFTER_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_AFTER_N(n, LEVEL, __VA_ARGS__)
4375 #define DCVLOG_AFTER_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_AFTER_N(n, vlevel, __VA_ARGS__)
4376 #define DCLOG_N_TIMES(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_N_TIMES(n, LEVEL, __VA_ARGS__)
4377 #define DCVLOG_N_TIMES(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_N_TIMES(n, vlevel, __VA_ARGS__)
4378 //
4379 // Default Debug Only Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros
4380 //
4381 #if !defined(ELPP_NO_DEBUG_MACROS)
4382 // undef existing
4383 #undef DLOG
4384 #undef DVLOG
4385 #undef DLOG_IF
4386 #undef DVLOG_IF
4387 #undef DLOG_EVERY_N
4388 #undef DVLOG_EVERY_N
4389 #undef DLOG_AFTER_N
4390 #undef DVLOG_AFTER_N
4391 #undef DLOG_N_TIMES
4392 #undef DVLOG_N_TIMES
4393 // Normal logs
4394 #define DLOG(LEVEL) DCLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4395 #define DVLOG(vlevel) DCVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID)
4396 // Conditional logs
4397 #define DLOG_IF(condition, LEVEL) DCLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4398 #define DVLOG_IF(condition, vlevel) DCVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID)
4399 // Hit counts based logs
4400 #define DLOG_EVERY_N(n, LEVEL) DCLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4401 #define DVLOG_EVERY_N(n, vlevel) DCVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
4402 #define DLOG_AFTER_N(n, LEVEL) DCLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4403 #define DVLOG_AFTER_N(n, vlevel) DCVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
4404 #define DLOG_N_TIMES(n, LEVEL) DCLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
4405 #define DVLOG_N_TIMES(n, vlevel) DCVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
4406 #endif // defined(ELPP_NO_DEBUG_MACROS)
4407 #if !defined(ELPP_NO_CHECK_MACROS)
4408 // Check macros
4409 #undef CCHECK
4410 #undef CPCHECK
4411 #undef CCHECK_EQ
4412 #undef CCHECK_NE
4413 #undef CCHECK_LT
4414 #undef CCHECK_GT
4415 #undef CCHECK_LE
4416 #undef CCHECK_GE
4417 #undef CCHECK_BOUNDS
4418 #undef CCHECK_NOTNULL
4419 #undef CCHECK_STRCASEEQ
4420 #undef CCHECK_STRCASENE
4421 #undef CHECK
4422 #undef PCHECK
4423 #undef CHECK_EQ
4424 #undef CHECK_NE
4425 #undef CHECK_LT
4426 #undef CHECK_GT
4427 #undef CHECK_LE
4428 #undef CHECK_GE
4429 #undef CHECK_BOUNDS
4430 #undef CHECK_NOTNULL
4431 #undef CHECK_STRCASEEQ
4432 #undef CHECK_STRCASENE
4433 #define CCHECK(condition, ...) CLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] "
4434 #define CPCHECK(condition, ...) CPLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] "
4435 #define CHECK(condition) CCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
4436 #define PCHECK(condition) CPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
4437 #define CCHECK_EQ(a, b, ...) CCHECK(a == b, __VA_ARGS__)
4438 #define CCHECK_NE(a, b, ...) CCHECK(a != b, __VA_ARGS__)
4439 #define CCHECK_LT(a, b, ...) CCHECK(a < b, __VA_ARGS__)
4440 #define CCHECK_GT(a, b, ...) CCHECK(a > b, __VA_ARGS__)
4441 #define CCHECK_LE(a, b, ...) CCHECK(a <= b, __VA_ARGS__)
4442 #define CCHECK_GE(a, b, ...) CCHECK(a >= b, __VA_ARGS__)
4443 #define CCHECK_BOUNDS(val, min, max, ...) CCHECK(val >= min && val <= max, __VA_ARGS__)
4444 #define CHECK_EQ(a, b) CCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID)
4445 #define CHECK_NE(a, b) CCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID)
4446 #define CHECK_LT(a, b) CCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID)
4447 #define CHECK_GT(a, b) CCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID)
4448 #define CHECK_LE(a, b) CCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID)
4449 #define CHECK_GE(a, b) CCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID)
4450 #define CHECK_BOUNDS(val, min, max) CCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID)
4451 #define CCHECK_NOTNULL(ptr, ...) CCHECK((ptr) != nullptr, __VA_ARGS__)
4452 #define CCHECK_STREQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \
4453 << "Check failed: [" << #str1 << " == " << #str2 << "] "
4454 #define CCHECK_STRNE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \
4455 << "Check failed: [" << #str1 << " != " << #str2 << "] "
4456 #define CCHECK_STRCASEEQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \
4457 << "Check failed: [" << #str1 << " == " << #str2 << "] "
4458 #define CCHECK_STRCASENE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \
4459 << "Check failed: [" << #str1 << " != " << #str2 << "] "
4460 #define CHECK_NOTNULL(ptr) CCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID)
4461 #define CHECK_STREQ(str1, str2) CCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
4462 #define CHECK_STRNE(str1, str2) CCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
4463 #define CHECK_STRCASEEQ(str1, str2) CCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
4464 #define CHECK_STRCASENE(str1, str2) CCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
4465 #undef DCCHECK
4466 #undef DCCHECK_EQ
4467 #undef DCCHECK_NE
4468 #undef DCCHECK_LT
4469 #undef DCCHECK_GT
4470 #undef DCCHECK_LE
4471 #undef DCCHECK_GE
4472 #undef DCCHECK_BOUNDS
4473 #undef DCCHECK_NOTNULL
4474 #undef DCCHECK_STRCASEEQ
4475 #undef DCCHECK_STRCASENE
4476 #undef DCPCHECK
4477 #undef DCHECK
4478 #undef DCHECK_EQ
4479 #undef DCHECK_NE
4480 #undef DCHECK_LT
4481 #undef DCHECK_GT
4482 #undef DCHECK_LE
4483 #undef DCHECK_GE
4484 #undef DCHECK_BOUNDS_
4485 #undef DCHECK_NOTNULL
4486 #undef DCHECK_STRCASEEQ
4487 #undef DCHECK_STRCASENE
4488 #undef DPCHECK
4489 #define DCCHECK(condition, ...) if (ELPP_DEBUG_LOG) CCHECK(condition, __VA_ARGS__)
4490 #define DCCHECK_EQ(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_EQ(a, b, __VA_ARGS__)
4491 #define DCCHECK_NE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_NE(a, b, __VA_ARGS__)
4492 #define DCCHECK_LT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LT(a, b, __VA_ARGS__)
4493 #define DCCHECK_GT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GT(a, b, __VA_ARGS__)
4494 #define DCCHECK_LE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LE(a, b, __VA_ARGS__)
4495 #define DCCHECK_GE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GE(a, b, __VA_ARGS__)
4496 #define DCCHECK_BOUNDS(val, min, max, ...) if (ELPP_DEBUG_LOG) CCHECK_BOUNDS(val, min, max, __VA_ARGS__)
4497 #define DCCHECK_NOTNULL(ptr, ...) if (ELPP_DEBUG_LOG) CCHECK_NOTNULL((ptr), __VA_ARGS__)
4498 #define DCCHECK_STREQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STREQ(str1, str2, __VA_ARGS__)
4499 #define DCCHECK_STRNE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRNE(str1, str2, __VA_ARGS__)
4500 #define DCCHECK_STRCASEEQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASEEQ(str1, str2, __VA_ARGS__)
4501 #define DCCHECK_STRCASENE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASENE(str1, str2, __VA_ARGS__)
4502 #define DCPCHECK(condition, ...) if (ELPP_DEBUG_LOG) CPCHECK(condition, __VA_ARGS__)
4503 #define DCHECK(condition) DCCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
4504 #define DCHECK_EQ(a, b) DCCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID)
4505 #define DCHECK_NE(a, b) DCCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID)
4506 #define DCHECK_LT(a, b) DCCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID)
4507 #define DCHECK_GT(a, b) DCCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID)
4508 #define DCHECK_LE(a, b) DCCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID)
4509 #define DCHECK_GE(a, b) DCCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID)
4510 #define DCHECK_BOUNDS(val, min, max) DCCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID)
4511 #define DCHECK_NOTNULL(ptr) DCCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID)
4512 #define DCHECK_STREQ(str1, str2) DCCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
4513 #define DCHECK_STRNE(str1, str2) DCCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
4514 #define DCHECK_STRCASEEQ(str1, str2) DCCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
4515 #define DCHECK_STRCASENE(str1, str2) DCCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
4516 #define DPCHECK(condition) DCPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
4517 #endif // defined(ELPP_NO_CHECK_MACROS)
4518 #if defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING)
4519 #  define ELPP_USE_DEF_CRASH_HANDLER false
4520 #else
4521 #  define ELPP_USE_DEF_CRASH_HANDLER true
4522 #endif  // defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING)
4523 #define ELPP_CRASH_HANDLER_INIT
4524 #define ELPP_INIT_EASYLOGGINGPP(val) \
4525 namespace el { \
4526 namespace base { \
4527 el::base::type::StoragePointer elStorage(val); \
4528 } \
4529 el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER); \
4530 }
4531 
4532 #if ELPP_ASYNC_LOGGING
4533 #  define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()),\
4534 new el::base::AsyncDispatchWorker()))
4535 #else
4536 #  define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder())))
4537 #endif  // ELPP_ASYNC_LOGGING
4538 #define INITIALIZE_NULL_EASYLOGGINGPP \
4539 namespace el {\
4540 namespace base {\
4541 el::base::type::StoragePointer elStorage;\
4542 }\
4543 el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\
4544 }
4545 #define SHARE_EASYLOGGINGPP(initializedStorage)\
4546 namespace el {\
4547 namespace base {\
4548 el::base::type::StoragePointer elStorage(initializedStorage);\
4549 }\
4550 el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\
4551 }
4552 
4553 #if defined(ELPP_UNICODE)
4554 #  define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv); std::locale::global(std::locale(""))
4555 #else
4556 #  define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv)
4557 #endif  // defined(ELPP_UNICODE)
4558 #endif // EASYLOGGINGPP_H