YAP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
easylogging++.h
1 //
2 // Easylogging++ v9.80
3 // Single-header only, cross-platform logging library for C++ applications
4 //
5 // Copyright (c) 2015 muflihun.com
6 //
7 // This library is released under the MIT Licence.
8 // http://easylogging.muflihun.com/licence.php
9 //
10 // easylogging@muflihun.com
11 //
12 // https://github.com/easylogging/easyloggingpp
13 // http://easylogging.muflihun.com
14 // http://muflihun.com
15 //
16 #ifndef EASYLOGGINGPP_H
17 #define EASYLOGGINGPP_H
18 // Compilers and C++0x/C++11 Evaluation
19 #if defined(__GNUC__)
20 # define ELPP_COMPILER_GCC 1
21 # define ELPP_GCC_VERSION (__GNUC__ * 10000 \
22  + __GNUC_MINOR__ * 100 \
23  + __GNUC_PATCHLEVEL__)
24 # if defined(__GXX_EXPERIMENTAL_CXX0X__)
25 # define ELPP_CXX0X 1
26 # elif(ELPP_GCC_VERSION >= 40801)
27 # define ELPP_CXX11 1
28 # endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
29 #endif // defined(__GNUC__)
30 // Visual C++
31 #if defined(_MSC_VER)
32 # define ELPP_COMPILER_MSVC 1
33 # define ELPP_CRT_DBG_WARNINGS 1
34 # if (_MSC_VER == 1600)
35 # define ELPP_CXX0X 1
36 # elif(_MSC_VER >= 1700)
37 # define ELPP_CXX11 1
38 # endif // (_MSC_VER == 1600)
39 #endif // defined(_MSC_VER)
40 // Clang++
41 #if defined(__clang__) && (__clang__ == 1)
42 # define ELPP_COMPILER_CLANG 1
43 # define ELPP_CLANG_VERSION (__clang_major__ * 10000 \
44  + __clang_minor__ * 100 \
45  + __clang_patchlevel__)
46 # if (ELPP_CLANG_VERSION >= 30300)
47 # define ELPP_CXX11 1
48 # endif // (ELPP_CLANG_VERSION >= 30300)
49 #endif // defined(__clang__) && (__clang__ == 1)
50 // MinGW
51 #if defined(__MINGW32__) || defined(__MINGW64__)
52 # define ELPP_MINGW 1
53 #endif // defined(__MINGW32__) || defined(__MINGW64__)
54 // Cygwin
55 #if defined(__CYGWIN__) && (__CYGWIN__ == 1)
56 # define ELPP_CYGWIN 1
57 #endif // defined(__CYGWIN__) && (__CYGWIN__ == 1)
58 // Intel C++
59 #if defined(__INTEL_COMPILER)
60 # define ELPP_COMPILER_INTEL 1
61 #endif
62 // Operating System Evaluation
63 // Windows
64 #if defined(_WIN32) || defined(_WIN64)
65 # define ELPP_OS_WINDOWS 1
66 #endif // defined(_WIN32) || defined(_WIN64)
67 // Linux
68 #if (defined(__linux) || defined(__linux__))
69 # define ELPP_OS_LINUX 1
70 #endif // (defined(__linux) || defined(__linux__))
71 // Mac
72 #if defined(__APPLE__)
73 # define ELPP_OS_MAC 1
74 #endif // defined(__APPLE__)
75 // FreeBSD
76 #if defined(__FreeBSD__)
77 # define ELPP_OS_FREEBSD 1
78 #endif
79 // Solaris
80 #if defined(__sun)
81 # define ELPP_OS_SOLARIS 1
82 #endif
83 // Unix
84 #if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_SOLARIS) && (!ELPP_OS_WINDOWS))
85 # define ELPP_OS_UNIX 1
86 #endif // ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_SOLARIS) && (!ELPP_OS_WINDOWS))
87 // Android
88 #if defined(__ANDROID__)
89 # define ELPP_OS_ANDROID 1
90 #endif // defined(__ANDROID__)
91 // Evaluating Cygwin as *nix OS
92 #if !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN
93 # undef ELPP_OS_UNIX
94 # undef ELPP_OS_LINUX
95 # define ELPP_OS_UNIX 1
96 # define ELPP_OS_LINUX 1
97 #endif // !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN
98 #if !defined(ELPP_INTERNAL_DEBUGGING_OUT_INFO)
99 # define ELPP_INTERNAL_DEBUGGING_OUT_INFO std::cout
100 #endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
101 #if !defined(ELPP_INTERNAL_DEBUGGING_OUT_ERROR)
102 # define ELPP_INTERNAL_DEBUGGING_OUT_ERROR std::cerr
103 #endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
104 #if !defined(ELPP_INTERNAL_DEBUGGING_ENDL)
105 # define ELPP_INTERNAL_DEBUGGING_ENDL std::endl
106 #endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
107 #if !defined(ELPP_INTERNAL_DEBUGGING_MSG)
108 # define ELPP_INTERNAL_DEBUGGING_MSG(msg) msg
109 #endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
110 // Internal Assertions and errors
111 #if !defined(ELPP_DISABLE_ASSERT)
112 # if (defined(ELPP_DEBUG_ASSERT_FAILURE))
113 # define ELPP_ASSERT(expr, msg) if (!(expr)) { \
114  std::stringstream internalInfoStream; internalInfoStream << msg; \
115  ELPP_INTERNAL_DEBUGGING_OUT_ERROR \
116  << "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" \
117  << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" << ELPP_INTERNAL_DEBUGGING_ENDL; base::utils::abort(1, \
118  "ELPP Assertion failure, please define ELPP_DEBUG_ASSERT_FAILURE"); }
119 # else
120 # define ELPP_ASSERT(expr, msg) if (!(expr)) { \
121  std::stringstream internalInfoStream; internalInfoStream << msg; \
122  ELPP_INTERNAL_DEBUGGING_OUT_ERROR\
123  << "ASSERTION FAILURE FROM EASYLOGGING++ (LINE: " \
124  << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" \
125  << ELPP_INTERNAL_DEBUGGING_ENDL; }
126 # endif // (defined(ELPP_DEBUG_ASSERT_FAILURE))
127 #else
128 # define ELPP_ASSERT(x, y)
129 #endif //(!defined(ELPP_DISABLE_ASSERT)
130 #if ELPP_COMPILER_MSVC
131 # define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \
132  { char buff[256]; strerror_s(buff, 256, errno); \
133  ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << buff << " [" << errno << "]";} (void)0
134 #else
135 # define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \
136  ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << strerror(errno) << " [" << errno << "]"; (void)0
137 #endif // ELPP_COMPILER_MSVC
138 #if defined(ELPP_DEBUG_ERRORS)
139 # if !defined(ELPP_INTERNAL_ERROR)
140 # define ELPP_INTERNAL_ERROR(msg, pe) { \
141  std::stringstream internalInfoStream; internalInfoStream << "<ERROR> " << msg; \
142  ELPP_INTERNAL_DEBUGGING_OUT_ERROR \
143  << "ERROR FROM EASYLOGGING++ (LINE: " << __LINE__ << ") " \
144  << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << ELPP_INTERNAL_DEBUGGING_ENDL; \
145  if (pe) { ELPP_INTERNAL_DEBUGGING_OUT_ERROR << " "; ELPP_INTERNAL_DEBUGGING_WRITE_PERROR; }} (void)0
146 # endif
147 #else
148 # undef ELPP_INTERNAL_INFO
149 # define ELPP_INTERNAL_ERROR(msg, pe)
150 #endif // defined(ELPP_DEBUG_ERRORS)
151 #if (defined(ELPP_DEBUG_INFO))
152 # if !(defined(ELPP_INTERNAL_INFO_LEVEL))
153 # define ELPP_INTERNAL_INFO_LEVEL 9
154 # endif // !(defined(ELPP_INTERNAL_INFO_LEVEL))
155 # if !defined(ELPP_INTERNAL_INFO)
156 # define ELPP_INTERNAL_INFO(lvl, msg) { if (lvl <= ELPP_INTERNAL_INFO_LEVEL) { \
157  std::stringstream internalInfoStream; internalInfoStream << "<INFO> " << msg; \
158  ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) \
159  << ELPP_INTERNAL_DEBUGGING_ENDL; }}
160 # endif
161 #else
162 # undef ELPP_INTERNAL_INFO
163 # define ELPP_INTERNAL_INFO(lvl, msg)
164 #endif // (defined(ELPP_DEBUG_INFO))
165 #if defined(ELPP_STACKTRACE_ON_CRASH)
166 # if (ELPP_COMPILER_GCC && !ELPP_MINGW)
167 # define ELPP_STACKTRACE 1
168 # else
169 # if ELPP_COMPILER_MSVC
170 # pragma message("Stack trace not available for this compiler")
171 # else
172 # warning "Stack trace not available for this compiler";
173 # endif // ELPP_COMPILER_MSVC
174 # endif // ELPP_COMPILER_GCC
175 #endif // (defined(ELPP_STACKTRACE_ON_CRASH))
176 // Miscellaneous macros
177 #define ELPP_UNUSED(x) (void)x
178 #if ELPP_OS_UNIX
179 // Log file permissions for unix-based systems
180 # define ELPP_LOG_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH
181 #endif // ELPP_OS_UNIX
182 #if defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC
183 # if defined(ELPP_EXPORT_SYMBOLS)
184 # define ELPP_EXPORT __declspec(dllexport)
185 # else
186 # define ELPP_EXPORT __declspec(dllimport)
187 # endif // defined(ELPP_EXPORT_SYMBOLS)
188 #else
189 # define ELPP_EXPORT
190 #endif // defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC
191 // Some special functions that are VC++ specific
192 #undef STRTOK
193 #undef STRERROR
194 #undef STRCAT
195 #undef STRCPY
196 #if ELPP_CRT_DBG_WARNINGS
197 # define STRTOK(a, b, c) strtok_s(a, b, c)
198 # define STRERROR(a, b, c) strerror_s(a, b, c)
199 # define STRCAT(a, b, len) strcat_s(a, len, b)
200 # define STRCPY(a, b, len) strcpy_s(a, len, b)
201 #else
202 # define STRTOK(a, b, c) strtok(a, b)
203 # define STRERROR(a, b, c) strerror(c)
204 # define STRCAT(a, b, len) strcat(a, b)
205 # define STRCPY(a, b, len) strcpy(a, b)
206 #endif
207 // Compiler specific support evaluations
208 #if (!ELPP_MINGW && !ELPP_COMPILER_CLANG) || defined(ELPP_FORCE_USE_STD_THREAD)
209 # define ELPP_USE_STD_THREADING 1
210 #endif // (!ELPP_MINGW && !ELPP_COMPILER_CLANG) || defined(ELPP_FORCE_USE_STD_THREAD)
211 #undef ELPP_FINAL
212 #if ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702)
213 # define ELPP_FINAL
214 #else
215 # define ELPP_FINAL final
216 #endif // ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702)
217 #if defined(ELPP_EXPERIMENTAL_ASYNC)
218 # define ELPP_ASYNC_LOGGING 1
219 #else
220 # define ELPP_ASYNC_LOGGING 0
221 #endif // defined(ELPP_EXPERIMENTAL_ASYNC)
222 #if defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING
223 # define ELPP_THREADING_ENABLED 1
224 #endif // defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING
225 // Function macro ELPP_FUNC
226 #undef ELPP_FUNC
227 #if ELPP_COMPILER_MSVC // Visual C++
228 # define ELPP_FUNC __FUNCSIG__
229 #elif ELPP_COMPILER_GCC // GCC
230 # define ELPP_FUNC __PRETTY_FUNCTION__
231 #elif ELPP_COMPILER_INTEL // Intel C++
232 # define ELPP_FUNC __PRETTY_FUNCTION__
233 #elif ELPP_COMPILER_CLANG // Clang++
234 # define ELPP_FUNC __PRETTY_FUNCTION__
235 #else
236 # if defined(__func__)
237 # define ELPP_FUNC __func__
238 # else
239 # define ELPP_FUNC ""
240 # endif // defined(__func__)
241 #endif // defined(_MSC_VER)
242 #undef ELPP_VARIADIC_TEMPLATES_SUPPORTED
243 // Keep following line commented until features are fixed
244 #if ELPP_COMPILER_GCC || ELPP_COMPILER_CLANG || ELPP_COMPILER_INTEL || (ELPP_COMPILER_MSVC && _MSC_VER >= 1800)
245 # define ELPP_VARIADIC_TEMPLATES_SUPPORTED 1
246 #endif // ELPP_COMPILER_GCC || ELPP_COMPILER_CLANG || ELPP_COMPILER_INTEL || (ELPP_COMPILER_MSVC && _MSC_VER >= 1800)
247 // Logging Enable/Disable macros
248 #if (!defined(ELPP_DISABLE_LOGS))
249 # define ELPP_LOGGING_ENABLED 1
250 #endif // (!defined(ELPP_DISABLE_LOGS))
251 #if (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED) && ((defined(_DEBUG)) || (!defined(NDEBUG))))
252 # define ELPP_DEBUG_LOG 1
253 #else
254 # define ELPP_DEBUG_LOG 0
255 #endif // (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED) && ((defined(_DEBUG)) || (!defined(NDEBUG))))
256 #if (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))
257 # define ELPP_INFO_LOG 1
258 #else
259 # define ELPP_INFO_LOG 0
260 #endif // (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))
261 #if (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))
262 # define ELPP_WARNING_LOG 1
263 #else
264 # define ELPP_WARNING_LOG 0
265 #endif // (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))
266 #if (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))
267 # define ELPP_ERROR_LOG 1
268 #else
269 # define ELPP_ERROR_LOG 0
270 #endif // (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))
271 #if (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))
272 # define ELPP_FATAL_LOG 1
273 #else
274 # define ELPP_FATAL_LOG 0
275 #endif // (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))
276 #if (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))
277 # define ELPP_TRACE_LOG 1
278 #else
279 # define ELPP_TRACE_LOG 0
280 #endif // (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))
281 #if (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED))
282 # define ELPP_VERBOSE_LOG 1
283 #else
284 # define ELPP_VERBOSE_LOG 0
285 #endif // (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED))
286 #if (!(ELPP_CXX0X || ELPP_CXX11))
287 # error "Easylogging++ 9.0+ is only compatible with C++0x (or higher) compliant compiler"
288 #endif // (!(ELPP_CXX0X || ELPP_CXX11))
289 // Headers
290 #if defined(ELPP_SYSLOG)
291 # include <syslog.h>
292 #endif // defined(ELPP_SYSLOG)
293 #include <ctime>
294 #include <cstring>
295 #include <cstdlib>
296 #include <cctype>
297 #include <cwchar>
298 #include <csignal>
299 #include <cerrno>
300 #include <cstdarg>
301 #if defined(ELPP_UNICODE)
302 # include <locale>
303 # if ELPP_OS_WINDOWS
304 # include <codecvt>
305 # endif // ELPP_OS_WINDOWS
306 #endif // defined(ELPP_UNICODE)
307 #if ELPP_STACKTRACE
308 # include <cxxabi.h>
309 # include <execinfo.h>
310 #endif // ELPP_STACKTRACE
311 #if ELPP_OS_ANDROID
312 # include <sys/system_properties.h>
313 #endif // ELPP_OS_ANDROID
314 #if ELPP_OS_UNIX
315 # include <sys/stat.h>
316 # include <sys/time.h>
317 #elif ELPP_OS_WINDOWS
318 # include <direct.h>
319 # include <windows.h>
320 # if defined(WIN32_LEAN_AND_MEAN)
321 # if defined(ELPP_WINSOCK2)
322 # include <winsock2.h>
323 # else
324 # include <winsock.h>
325 # endif // defined(ELPP_WINSOCK2)
326 # endif // defined(WIN32_LEAN_AND_MEAN)
327 #endif // ELPP_OS_UNIX
328 #include <string>
329 #include <vector>
330 #include <map>
331 #include <utility>
332 #include <functional>
333 #include <algorithm>
334 #include <fstream>
335 #include <iostream>
336 #include <sstream>
337 #include <memory>
338 #include <type_traits>
339 #if ELPP_THREADING_ENABLED
340 # if ELPP_USE_STD_THREADING
341 # include <mutex>
342 # include <thread>
343 # else
344 # if ELPP_OS_UNIX
345 # include <pthread.h>
346 # endif // ELPP_OS_UNIX
347 # endif // ELPP_USE_STD_THREADING
348 #endif // ELPP_THREADING_ENABLED
349 #if ELPP_ASYNC_LOGGING
350 # include <thread>
351 # include <queue>
352 # include <condition_variable>
353 #endif // ELPP_ASYNC_LOGGING
354 #if defined(ELPP_STL_LOGGING)
355 // For logging STL based templates
356 # include <list>
357 # include <queue>
358 # include <deque>
359 # include <set>
360 # include <bitset>
361 # include <stack>
362 # if defined(ELPP_LOG_STD_ARRAY)
363 # include <array>
364 # endif // defined(ELPP_LOG_STD_ARRAY)
365 # if defined(ELPP_LOG_UNORDERED_MAP)
366 # include <unordered_map>
367 # endif // defined(ELPP_LOG_UNORDERED_MAP)
368 # if defined(ELPP_LOG_UNORDERED_SET)
369 # include <unordered_set>
370 # endif // defined(ELPP_UNORDERED_SET)
371 #endif // defined(ELPP_STL_LOGGING)
372 #if defined(ELPP_QT_LOGGING)
373 // For logging Qt based classes & templates
374 # include <QString>
375 # include <QByteArray>
376 # include <QVector>
377 # include <QList>
378 # include <QPair>
379 # include <QMap>
380 # include <QQueue>
381 # include <QSet>
382 # include <QLinkedList>
383 # include <QHash>
384 # include <QMultiHash>
385 # include <QStack>
386 #endif // defined(ELPP_QT_LOGGING)
387 #if defined(ELPP_BOOST_LOGGING)
388 // For logging boost based classes & templates
389 # include <boost/container/vector.hpp>
390 # include <boost/container/stable_vector.hpp>
391 # include <boost/container/list.hpp>
392 # include <boost/container/deque.hpp>
393 # include <boost/container/map.hpp>
394 # include <boost/container/flat_map.hpp>
395 # include <boost/container/set.hpp>
396 # include <boost/container/flat_set.hpp>
397 #endif // defined(ELPP_BOOST_LOGGING)
398 #if defined(ELPP_WXWIDGETS_LOGGING)
399 // For logging wxWidgets based classes & templates
400 # include <wx/vector.h>
401 #endif // defined(ELPP_WXWIDGETS_LOGGING)
402 // Forward declarations
403 namespace el {
404 class Logger;
405 class LogMessage;
406 class PerformanceTrackingData;
407 class Loggers;
408 class Helpers;
409 template <typename T> class Callback;
410 class LogDispatchCallback;
411 class PerformanceTrackingCallback;
412 class LogDispatchData;
413 namespace base {
414 class Storage;
415 class RegisteredLoggers;
416 class PerformanceTracker;
417 class MessageBuilder;
418 class Writer;
419 class PErrorWriter;
420 class LogDispatcher;
421 class DefaultLogBuilder;
422 class DefaultLogDispatchCallback;
423 #if ELPP_ASYNC_LOGGING
424 class AsyncLogDispatchCallback;
425 class AsyncDispatchWorker;
426 #endif // ELPP_ASYNC_LOGGING
427 class DefaultPerformanceTrackingCallback;
428 } // namespace base
429 } // namespace el
431 namespace el {
433 namespace base {
435 namespace type {
436 #undef ELPP_LITERAL
437 #undef ELPP_STRLEN
438 #undef ELPP_COUT
439 #if defined(ELPP_UNICODE)
440 # define ELPP_LITERAL(txt) L##txt
441 # define ELPP_STRLEN wcslen
442 # if defined ELPP_CUSTOM_COUT
443 # define ELPP_COUT ELPP_CUSTOM_COUT
444 # else
445 # define ELPP_COUT std::wcout
446 # endif // defined ELPP_CUSTOM_COUT
447 typedef wchar_t char_t;
448 typedef std::wstring string_t;
449 typedef std::wstringstream stringstream_t;
450 typedef std::wfstream fstream_t;
451 typedef std::wostream ostream_t;
452 #else
453 # define ELPP_LITERAL(txt) txt
454 # define ELPP_STRLEN strlen
455 # if defined ELPP_CUSTOM_COUT
456 # define ELPP_COUT ELPP_CUSTOM_COUT
457 # else
458 # define ELPP_COUT std::cout
459 # endif // defined ELPP_CUSTOM_COUT
460 typedef char char_t;
461 typedef std::string string_t;
462 typedef std::stringstream stringstream_t;
463 typedef std::fstream fstream_t;
464 typedef std::ostream ostream_t;
465 #endif // defined(ELPP_UNICODE)
466 #if defined(ELPP_CUSTOM_COUT_LINE)
467 # define ELPP_COUT_LINE(logLine) ELPP_CUSTOM_COUT_LINE(logLine)
468 #else
469 # define ELPP_COUT_LINE(logLine) logLine << std::flush
470 #endif // defined(ELPP_CUSTOM_COUT_LINE)
471 typedef unsigned short EnumType;
472 typedef std::shared_ptr<base::Storage> StoragePointer;
473 typedef int VerboseLevel;
474 typedef std::shared_ptr<LogDispatchCallback> LogDispatchCallbackPtr;
475 typedef std::shared_ptr<PerformanceTrackingCallback> PerformanceTrackingCallbackPtr;
476 } // namespace type
480 class NoCopy
481 {
482 protected:
483  NoCopy(void) {}
484 private:
485  NoCopy(const NoCopy&);
486  NoCopy& operator=(const NoCopy&);
487 };
492 class StaticClass
493 {
494 private:
495  StaticClass(void);
496  StaticClass(const StaticClass&);
497  StaticClass& operator=(const StaticClass&);
498 };
499 } // namespace base
504 enum class Level : base::type::EnumType {
506  Global = 1,
508  Trace = 2,
510  Debug = 4,
512  Fatal = 8,
514  Error = 16,
516  Warning = 32,
518  Verbose = 64,
520  Info = 128,
522  Unknown = 1010
523 };
525 class LevelHelper : base::StaticClass
526 {
527 public:
529  static const base::type::EnumType kMinValid = static_cast<base::type::EnumType>(Level::Trace);
531  static const base::type::EnumType kMaxValid = static_cast<base::type::EnumType>(Level::Info);
533  static base::type::EnumType castToInt(Level level)
534  {
535  return static_cast<base::type::EnumType>(level);
536  }
538  static Level castFromInt(base::type::EnumType l)
539  {
540  return static_cast<Level>(l);
541  }
544  static const char* convertToString(Level level)
545  {
546  // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet.
547  if (level == Level::Global) return "GLOBAL";
548  if (level == Level::Debug) return "DEBUG";
549  if (level == Level::Info) return "INFO";
550  if (level == Level::Warning) return "WARNING";
551  if (level == Level::Error) return "ERROR";
552  if (level == Level::Fatal) return "FATAL";
553  if (level == Level::Verbose) return "VERBOSE";
554  if (level == Level::Trace) return "TRACE";
555  return "UNKNOWN";
556  }
560  static Level convertFromString(const char* levelStr)
561  {
562  if ((strcmp(levelStr, "GLOBAL") == 0) || (strcmp(levelStr, "global") == 0))
563  return Level::Global;
564  if ((strcmp(levelStr, "DEBUG") == 0) || (strcmp(levelStr, "debug") == 0))
565  return Level::Debug;
566  if ((strcmp(levelStr, "INFO") == 0) || (strcmp(levelStr, "info") == 0))
567  return Level::Info;
568  if ((strcmp(levelStr, "WARNING") == 0) || (strcmp(levelStr, "warning") == 0))
569  return Level::Warning;
570  if ((strcmp(levelStr, "ERROR") == 0) || (strcmp(levelStr, "error") == 0))
571  return Level::Error;
572  if ((strcmp(levelStr, "FATAL") == 0) || (strcmp(levelStr, "fatal") == 0))
573  return Level::Fatal;
574  if ((strcmp(levelStr, "VERBOSE") == 0) || (strcmp(levelStr, "verbose") == 0))
575  return Level::Verbose;
576  if ((strcmp(levelStr, "TRACE") == 0) || (strcmp(levelStr, "trace") == 0))
577  return Level::Trace;
578  return Level::Unknown;
579  }
584  static inline void forEachLevel(base::type::EnumType* startIndex, const std::function<bool(void)>& fn)
585  {
586  base::type::EnumType lIndexMax = LevelHelper::kMaxValid;
587  do {
588  if (fn()) {
589  break;
590  }
591  *startIndex = static_cast<base::type::EnumType>(*startIndex << 1);
592  } while (*startIndex <= lIndexMax);
593  }
594 };
597 enum class ConfigurationType : base::type::EnumType {
600  Enabled = 1,
602  ToFile = 2,
605  ToStandardOutput = 4,
607  Format = 8,
609  Filename = 16,
611  MillisecondsWidth = 32,
615  PerformanceTracking = 64,
620  MaxLogFileSize = 128,
622  LogFlushThreshold = 256,
624  Unknown = 1010
625 };
627 class ConfigurationTypeHelper : base::StaticClass
628 {
629 public:
631  static const base::type::EnumType kMinValid = static_cast<base::type::EnumType>(ConfigurationType::Enabled);
633  static const base::type::EnumType kMaxValid = static_cast<base::type::EnumType>(ConfigurationType::MaxLogFileSize);
635  static base::type::EnumType castToInt(ConfigurationType configurationType)
636  {
637  return static_cast<base::type::EnumType>(configurationType);
638  }
640  static ConfigurationType castFromInt(base::type::EnumType c)
641  {
642  return static_cast<ConfigurationType>(c);
643  }
646  static const char* convertToString(ConfigurationType configurationType)
647  {
648  // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet.
649  if (configurationType == ConfigurationType::Enabled) return "ENABLED";
650  if (configurationType == ConfigurationType::Filename) return "FILENAME";
651  if (configurationType == ConfigurationType::Format) return "FORMAT";
652  if (configurationType == ConfigurationType::ToFile) return "TO_FILE";
653  if (configurationType == ConfigurationType::ToStandardOutput) return "TO_STANDARD_OUTPUT";
654  if (configurationType == ConfigurationType::MillisecondsWidth) return "MILLISECONDS_WIDTH";
655  if (configurationType == ConfigurationType::PerformanceTracking) return "PERFORMANCE_TRACKING";
656  if (configurationType == ConfigurationType::MaxLogFileSize) return "MAX_LOG_FILE_SIZE";
657  if (configurationType == ConfigurationType::LogFlushThreshold) return "LOG_FLUSH_THRESHOLD";
658  return "UNKNOWN";
659  }
663  static ConfigurationType convertFromString(const char* configStr)
664  {
665  if ((strcmp(configStr, "ENABLED") == 0) || (strcmp(configStr, "enabled") == 0))
666  return ConfigurationType::Enabled;
667  if ((strcmp(configStr, "TO_FILE") == 0) || (strcmp(configStr, "to_file") == 0))
668  return ConfigurationType::ToFile;
669  if ((strcmp(configStr, "TO_STANDARD_OUTPUT") == 0) || (strcmp(configStr, "to_standard_output") == 0))
670  return ConfigurationType::ToStandardOutput;
671  if ((strcmp(configStr, "FORMAT") == 0) || (strcmp(configStr, "format") == 0))
672  return ConfigurationType::Format;
673  if ((strcmp(configStr, "FILENAME") == 0) || (strcmp(configStr, "filename") == 0))
674  return ConfigurationType::Filename;
675  if ((strcmp(configStr, "MILLISECONDS_WIDTH") == 0) || (strcmp(configStr, "milliseconds_width") == 0))
676  return ConfigurationType::MillisecondsWidth;
677  if ((strcmp(configStr, "PERFORMANCE_TRACKING") == 0) || (strcmp(configStr, "performance_tracking") == 0))
678  return ConfigurationType::PerformanceTracking;
679  if ((strcmp(configStr, "MAX_LOG_FILE_SIZE") == 0) || (strcmp(configStr, "max_log_file_size") == 0))
680  return ConfigurationType::MaxLogFileSize;
681  if ((strcmp(configStr, "LOG_FLUSH_THRESHOLD") == 0) || (strcmp(configStr, "log_flush_threshold") == 0))
682  return ConfigurationType::LogFlushThreshold;
683  return ConfigurationType::Unknown;
684  }
690  static inline void forEachConfigType(base::type::EnumType* startIndex, const std::function<bool(void)>& fn)
691  {
692  base::type::EnumType cIndexMax = ConfigurationTypeHelper::kMaxValid;
693  do {
694  if (fn()) {
695  break;
696  }
697  *startIndex = static_cast<base::type::EnumType>(*startIndex << 1);
698  } while (*startIndex <= cIndexMax);
699  }
700 };
702 enum class LoggingFlag : base::type::EnumType {
704  NewLineForContainer = 1,
707  AllowVerboseIfModuleNotSpecified = 2,
709  LogDetailedCrashReason = 4,
711  DisableApplicationAbortOnFatalLog = 8,
713  ImmediateFlush = 16,
715  StrictLogFileSizeCheck = 32,
717  ColoredTerminalOutput = 64,
719  MultiLoggerSupport = 128,
721  DisablePerformanceTrackingCheckpointComparison = 256,
723  DisableVModules = 512,
725  DisableVModulesExtensions = 1024,
727  HierarchicalLogging = 2048,
729  CreateLoggerAutomatically = 4096,
731  AutoSpacing = 8192,
733  FixedTimeFormat = 16384
734 };
735 namespace base {
737 namespace consts {
738 // Level log values - These are values that are replaced in place of %level format specifier
739 static const base::type::char_t* kInfoLevelLogValue = ELPP_LITERAL("INFO ");
740 static const base::type::char_t* kDebugLevelLogValue = ELPP_LITERAL("DEBUG");
741 static const base::type::char_t* kWarningLevelLogValue = ELPP_LITERAL("WARN ");
742 static const base::type::char_t* kErrorLevelLogValue = ELPP_LITERAL("ERROR");
743 static const base::type::char_t* kFatalLevelLogValue = ELPP_LITERAL("FATAL");
744 static const base::type::char_t* kVerboseLevelLogValue = ELPP_LITERAL("VER");
745 static const base::type::char_t* kTraceLevelLogValue = ELPP_LITERAL("TRACE");
746 static const base::type::char_t* kInfoLevelShortLogValue = ELPP_LITERAL("I");
747 static const base::type::char_t* kDebugLevelShortLogValue = ELPP_LITERAL("D");
748 static const base::type::char_t* kWarningLevelShortLogValue = ELPP_LITERAL("W");
749 static const base::type::char_t* kErrorLevelShortLogValue = ELPP_LITERAL("E");
750 static const base::type::char_t* kFatalLevelShortLogValue = ELPP_LITERAL("F");
751 static const base::type::char_t* kVerboseLevelShortLogValue = ELPP_LITERAL("V");
752 static const base::type::char_t* kTraceLevelShortLogValue = ELPP_LITERAL("T");
753 // Format specifiers - These are used to define log format
754 static const base::type::char_t* kAppNameFormatSpecifier = ELPP_LITERAL("%app");
755 static const base::type::char_t* kLoggerIdFormatSpecifier = ELPP_LITERAL("%logger");
756 static const base::type::char_t* kThreadIdFormatSpecifier = ELPP_LITERAL("%thread");
757 static const base::type::char_t* kSeverityLevelFormatSpecifier = ELPP_LITERAL("%level");
758 static const base::type::char_t* kSeverityLevelShortFormatSpecifier = ELPP_LITERAL("%levshort");
759 static const base::type::char_t* kDateTimeFormatSpecifier = ELPP_LITERAL("%datetime");
760 static const base::type::char_t* kLogFileFormatSpecifier = ELPP_LITERAL("%file");
761 static const base::type::char_t* kLogFileBaseFormatSpecifier = ELPP_LITERAL("%fbase");
762 static const base::type::char_t* kLogLineFormatSpecifier = ELPP_LITERAL("%line");
763 static const base::type::char_t* kLogLocationFormatSpecifier = ELPP_LITERAL("%loc");
764 static const base::type::char_t* kLogFunctionFormatSpecifier = ELPP_LITERAL("%func");
765 static const base::type::char_t* kCurrentUserFormatSpecifier = ELPP_LITERAL("%user");
766 static const base::type::char_t* kCurrentHostFormatSpecifier = ELPP_LITERAL("%host");
767 static const base::type::char_t* kMessageFormatSpecifier = ELPP_LITERAL("%msg");
768 static const base::type::char_t* kVerboseLevelFormatSpecifier = ELPP_LITERAL("%vlevel");
769 static const char* kDateTimeFormatSpecifierForFilename = "%datetime";
770 // Date/time
771 static const char* kDays[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
772 static const char* kDaysAbbrev[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
773 static const char* kMonths[12] = { "January", "February", "March", "Apri", "May", "June", "July", "August",
774  "September", "October", "November", "December"
775  };
776 static const char* kMonthsAbbrev[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
777 static const char* kDefaultDateTimeFormat = "%Y-%M-%d %H:%m:%s,%g";
778 static const char* kDefaultDateTimeFormatInFilename = "%Y-%M-%d_%H-%m";
779 static const int kYearBase = 1900;
780 static const char* kAm = "AM";
781 static const char* kPm = "PM";
782 // Miscellaneous constants
783 static const char* kDefaultLoggerId = "default";
784 static const char* kPerformanceLoggerId = "performance";
785 static const char* kSysLogLoggerId = "syslog";
786 static const char* kNullPointer = "nullptr";
787 static const char kFormatSpecifierChar = '%';
788 #if ELPP_VARIADIC_TEMPLATES_SUPPORTED
789 static const char kFormatSpecifierCharValue = 'v';
790 #endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
791 static const unsigned int kMaxLogPerContainer = 100;
792 static const unsigned int kMaxLogPerCounter = 100000;
793 static const unsigned int kDefaultMillisecondsWidth = 3;
794 static const base::type::VerboseLevel kMaxVerboseLevel = 9;
795 static const char* kUnknownUser = "user";
796 static const char* kUnknownHost = "unknown-host";
797 #if defined(ELPP_DEFAULT_LOG_FILE)
798 static const char* kDefaultLogFile = ELPP_DEFAULT_LOG_FILE;
799 #else
800 # if ELPP_OS_UNIX
801 # if ELPP_OS_ANDROID
802 static const char* kDefaultLogFile = "logs/myeasylog.log";
803 # else
804 static const char* kDefaultLogFile = "logs/myeasylog.log";
805 # endif // ELPP_OS_ANDROID
806 # elif ELPP_OS_WINDOWS
807 static const char* kDefaultLogFile = "logs\\myeasylog.log";
808 # endif // ELPP_OS_UNIX
809 #endif // defined(ELPP_DEFAULT_LOG_FILE)
810 #if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
811 static const char* kDefaultLogFileParam = "--default-log-file";
812 #endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
813 #if defined(ELPP_LOGGING_FLAGS_FROM_ARG)
814 static const char* kLoggingFlagsParam = "--logging-flags";
815 #endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG)
816 #if ELPP_OS_WINDOWS
817 static const char* kFilePathSeperator = "\\";
818 #else
819 static const char* kFilePathSeperator = "/";
820 #endif // ELPP_OS_WINDOWS
821 static const char* kValidLoggerIdSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._";
822 static const char* kConfigurationComment = "##";
823 static const char* kConfigurationLevel = "*";
824 static const char* kConfigurationLoggerId = "--";
825 static const std::size_t kSourceFilenameMaxLength = 100;
826 static const std::size_t kSourceLineMaxLength = 10;
827 static const Level kPerformanceTrackerDefaultLevel = Level::Info;
828 const struct {
829  double value;
830  const base::type::char_t* unit;
831 } kTimeFormats[] = {
832  { 1000.0f, ELPP_LITERAL("mis") },
833  { 1000.0f, ELPP_LITERAL("ms") },
834  { 60.0f, ELPP_LITERAL("seconds") },
835  { 60.0f, ELPP_LITERAL("minutes") },
836  { 24.0f, ELPP_LITERAL("hours") },
837  { 7.0f, ELPP_LITERAL("days") }
838 };
839 static const int kTimeFormatsCount = sizeof(kTimeFormats) / sizeof(kTimeFormats[0]);
840 const struct {
841  int numb;
842  const char* name;
843  const char* brief;
844  const char* detail;
845 } kCrashSignals[] = {
846  // NOTE: Do not re-order, if you do please check CrashHandler(bool) constructor and CrashHandler::setHandler(..)
847  {
848  SIGABRT, "SIGABRT", "Abnormal termination",
849  "Program was abnormally terminated."
850  },
851  {
852  SIGFPE, "SIGFPE", "Erroneous arithmetic operation",
853  "Arithemetic operation issue such as division by zero or operation resulting in overflow."
854  },
855  {
856  SIGILL, "SIGILL", "Illegal instruction",
857  "Generally due to a corruption in the code or to an attempt to execute data."
858  },
859  {
860  SIGSEGV, "SIGSEGV", "Invalid access to memory",
861  "Program is trying to read an invalid (unallocated, deleted or corrupted) or inaccessible memory."
862  },
863  {
864  SIGINT, "SIGINT", "Interactive attention signal",
865  "Interruption generated (generally) by user or operating system."
866  },
867 };
868 static const int kCrashSignalsCount = sizeof(kCrashSignals) / sizeof(kCrashSignals[0]);
869 } // namespace consts
870 } // namespace base
871 typedef std::function<void(const char*, std::size_t)> PreRollOutCallback;
872 namespace base {
873 static inline void defaultPreRollOutCallback(const char*, std::size_t) {}
875 enum class TimestampUnit : base::type::EnumType {
876  Microsecond = 0, Millisecond = 1, Second = 2, Minute = 3, Hour = 4, Day = 5
877 };
879 enum class FormatFlags : base::type::EnumType {
880  DateTime = 1 << 1, LoggerId = 1 << 2, File = 1 << 3, Line = 1 << 4, Location = 1 << 5, Function = 1 << 6,
881  User = 1 << 7, Host = 1 << 8, LogMessage = 1 << 9, VerboseLevel = 1 << 10, AppName = 1 << 11, ThreadId = 1 << 12,
882  Level = 1 << 13, FileBase = 1 << 14, LevelShort = 1 << 15
883 };
885 class MillisecondsWidth
886 {
887 public:
888  MillisecondsWidth(void) { init(base::consts::kDefaultMillisecondsWidth); }
889  explicit MillisecondsWidth(int width) { init(width); }
890  bool operator==(const MillisecondsWidth& msWidth) { return m_width == msWidth.m_width && m_offset == msWidth.m_offset; }
891  int m_width;
892  unsigned int m_offset;
893 private:
894  void init(int width)
895  {
896  if (width < 1 || width > 6) {
897  width = base::consts::kDefaultMillisecondsWidth;
898  }
899  m_width = width;
900  switch (m_width) {
901  case 3:
902  m_offset = 1000;
903  break;
904  case 4:
905  m_offset = 100;
906  break;
907  case 5:
908  m_offset = 10;
909  break;
910  case 6:
911  m_offset = 1;
912  break;
913  default:
914  m_offset = 1000;
915  break;
916  }
917  }
918 };
920 namespace utils {
922 template <typename T>
923 static inline
924 typename std::enable_if<std::is_pointer<T*>::value, void>::type
925 safeDelete(T*& pointer)
926 {
927  if (pointer == nullptr)
928  return;
929  delete pointer;
930  pointer = nullptr;
931 }
933 static inline const char* charPtrVal(const char* pointer)
934 {
935  return pointer == nullptr ? base::consts::kNullPointer : pointer;
936 }
938 static inline void abort(int status, const std::string& reason = std::string())
939 {
940  // Both status and reason params are there for debugging with tools like gdb etc
941  ELPP_UNUSED(status);
942  ELPP_UNUSED(reason);
943 #if defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG)
944  // Ignore msvc critical error dialog - break instead (on debug mode)
945  _asm int 3
946 #else
947  ::abort();
948 #endif // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG)
949 }
952 namespace bitwise {
953 template <typename Enum>
954 static inline base::type::EnumType And(Enum e, base::type::EnumType flag)
955 {
956  return static_cast<base::type::EnumType>(flag) & static_cast<base::type::EnumType>(e);
957 }
958 template <typename Enum>
959 static inline base::type::EnumType Not(Enum e, base::type::EnumType flag)
960 {
961  return static_cast<base::type::EnumType>(flag) & ~(static_cast<base::type::EnumType>(e));
962 }
963 template <typename Enum>
964 static inline base::type::EnumType Or(Enum e, base::type::EnumType flag)
965 {
966  return static_cast<base::type::EnumType>(flag) | static_cast<base::type::EnumType>(e);
967 }
968 } // namespace bitwise
969 template <typename Enum>
970 static inline void addFlag(Enum e, base::type::EnumType* flag)
971 {
972  *flag = base::utils::bitwise::Or<Enum>(e, *flag);
973 }
974 template <typename Enum>
975 static inline void removeFlag(Enum e, base::type::EnumType* flag)
976 {
977  *flag = base::utils::bitwise::Not<Enum>(e, *flag);
978 }
979 template <typename Enum>
980 static inline bool hasFlag(Enum e, base::type::EnumType flag)
981 {
982  return base::utils::bitwise::And<Enum>(e, flag) > 0x0;
983 }
984 } // namespace utils
985 namespace threading {
986 #if ELPP_THREADING_ENABLED
987 # if !ELPP_USE_STD_THREADING
988 namespace internal {
990 class Mutex : base::NoCopy
991 {
992 public:
993  Mutex(void)
994  {
995 # if ELPP_OS_UNIX
996  pthread_mutex_init(&m_underlyingMutex, nullptr);
997 # elif ELPP_OS_WINDOWS
998  InitializeCriticalSection(&m_underlyingMutex);
999 # endif // ELPP_OS_UNIX
1000  }
1001 
1002  virtual ~Mutex(void)
1003  {
1004 # if ELPP_OS_UNIX
1005  pthread_mutex_destroy(&m_underlyingMutex);
1006 # elif ELPP_OS_WINDOWS
1007  DeleteCriticalSection(&m_underlyingMutex);
1008 # endif // ELPP_OS_UNIX
1009  }
1010 
1011  inline void lock(void)
1012  {
1013 # if ELPP_OS_UNIX
1014  pthread_mutex_lock(&m_underlyingMutex);
1015 # elif ELPP_OS_WINDOWS
1016  EnterCriticalSection(&m_underlyingMutex);
1017 # endif // ELPP_OS_UNIX
1018  }
1019 
1020  inline bool try_lock(void)
1021  {
1022 # if ELPP_OS_UNIX
1023  return (pthread_mutex_trylock(&m_underlyingMutex) == 0);
1024 # elif ELPP_OS_WINDOWS
1025  return TryEnterCriticalSection(&m_underlyingMutex);
1026 # endif // ELPP_OS_UNIX
1027  }
1028 
1029  inline void unlock(void)
1030  {
1031 # if ELPP_OS_UNIX
1032  pthread_mutex_unlock(&m_underlyingMutex);
1033 # elif ELPP_OS_WINDOWS
1034  LeaveCriticalSection(&m_underlyingMutex);
1035 # endif // ELPP_OS_UNIX
1036  }
1037 
1038 private:
1039 # if ELPP_OS_UNIX
1040  pthread_mutex_t m_underlyingMutex;
1041 # elif ELPP_OS_WINDOWS
1042  CRITICAL_SECTION m_underlyingMutex;
1043 # endif // ELPP_OS_UNIX
1044 };
1046 template <typename M>
1047 class ScopedLock : base::NoCopy
1048 {
1049 public:
1050  explicit ScopedLock(M& mutex)
1051  {
1052  m_mutex = &mutex;
1053  m_mutex->lock();
1054  }
1055 
1056  virtual ~ScopedLock(void)
1057  {
1058  m_mutex->unlock();
1059  }
1060 private:
1061  M* m_mutex;
1062  ScopedLock(void);
1063 };
1064 } // namespace internal
1066 static inline std::string getCurrentThreadId(void)
1067 {
1068  std::stringstream ss;
1069 # if (ELPP_OS_WINDOWS)
1070  ss << GetCurrentThreadId();
1071 # endif // (ELPP_OS_WINDOWS)
1072  return ss.str();
1073 }
1074 static inline void msleep(int)
1075 {
1076  // No implementation for non std::thread version
1077 }
1078 typedef base::threading::internal::Mutex Mutex;
1079 typedef base::threading::internal::ScopedLock<base::threading::Mutex> ScopedLock;
1080 # else
1081 static inline std::string getCurrentThreadId(void)
1083 {
1084  std::stringstream ss;
1085  ss << std::this_thread::get_id();
1086  return ss.str();
1087 }
1088 static inline void msleep(int ms)
1089 {
1090  // Only when async logging enabled - this is because async is strict on compiler
1091 #if ELPP_ASYNC_LOGGING
1092  std::this_thread::sleep_for(std::chrono::milliseconds(ms));
1093 #endif // ELPP_ASYNC_LOGGING
1094 }
1095 typedef std::mutex Mutex;
1096 typedef std::lock_guard<std::mutex> ScopedLock;
1097 # endif // !ELPP_USE_STD_THREADING
1098 #else
1099 namespace internal {
1101 class NoMutex : base::NoCopy
1102 {
1103 public:
1104  NoMutex(void) {}
1105  inline void lock(void) {}
1106  inline bool try_lock(void) { return true; }
1107  inline void unlock(void) {}
1108 };
1110 template <typename Mutex>
1111 class NoScopedLock : base::NoCopy
1112 {
1113 public:
1114  explicit NoScopedLock(Mutex&)
1115  {
1116  }
1117  virtual ~NoScopedLock(void)
1118  {
1119  }
1120 private:
1121  NoScopedLock(void);
1122 };
1123 } // namespace internal
1124 static inline std::string getCurrentThreadId(void)
1125 {
1126  return std::string();
1127 }
1128 static inline void msleep(int)
1129 {
1130  // No custom implementation
1131 }
1132 typedef base::threading::internal::NoMutex Mutex;
1133 typedef base::threading::internal::NoScopedLock<base::threading::Mutex> ScopedLock;
1134 #endif // ELPP_THREADING_ENABLED
1135 class ThreadSafe
1137 {
1138 public:
1139  virtual inline void acquireLock(void) ELPP_FINAL { m_mutex.lock(); }
1140  virtual inline void releaseLock(void) ELPP_FINAL { m_mutex.unlock(); }
1141  virtual inline base::threading::Mutex& lock(void) ELPP_FINAL { return m_mutex; }
1142 protected:
1143  ThreadSafe(void) {}
1144  virtual ~ThreadSafe(void) {}
1145 private:
1146  base::threading::Mutex m_mutex;
1147 };
1148 } // namespace threading
1149 namespace utils {
1150 class File : base::StaticClass
1151 {
1152 public:
1155  static base::type::fstream_t* newFileStream(const std::string& filename)
1156  {
1157  base::type::fstream_t* fs = new base::type::fstream_t(filename.c_str(),
1158  base::type::fstream_t::out | base::type::fstream_t::app);
1159 #if defined(ELPP_UNICODE)
1160  std::locale elppUnicodeLocale("");
1161 #if ELPP_OS_WINDOWS
1162  std::locale elppUnicodeLocaleWindows(elppUnicodeLocale, new std::codecvt_utf8_utf16<wchar_t>);
1163  elppUnicodeLocale = elppUnicodeLocaleWindows;
1164 #endif
1165  fs->imbue(elppUnicodeLocale);
1166 #endif // defined(ELPP_UNICODE)
1167  if (fs->is_open()) {
1168  fs->flush();
1169  } else {
1170  base::utils::safeDelete(fs);
1171  ELPP_INTERNAL_ERROR("Bad file [" << filename << "]", true);
1172  }
1173  return fs;
1174  }
1175 
1177  static std::size_t getSizeOfFile(base::type::fstream_t* fs)
1178  {
1179  if (fs == nullptr) {
1180  return 0;
1181  }
1182  std::streampos currPos = fs->tellg();
1183  fs->seekg(0, fs->end);
1184  std::size_t size = static_cast<std::size_t>(fs->tellg());
1185  fs->seekg(currPos);
1186  return size;
1187  }
1188 
1190  static inline bool pathExists(const char* path, bool considerFile = false)
1191  {
1192  if (path == nullptr) {
1193  return false;
1194  }
1195 #if ELPP_OS_UNIX
1196  ELPP_UNUSED(considerFile);
1197  struct stat st;
1198  return (stat(path, &st) == 0);
1199 #elif ELPP_OS_WINDOWS
1200  DWORD fileType = GetFileAttributesA(path);
1201  if (fileType == INVALID_FILE_ATTRIBUTES) {
1202  return false;
1203  }
1204  return considerFile ? true : ((fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true);
1205 #endif // ELPP_OS_UNIX
1206  }
1207 
1210  static bool createPath(const std::string& path)
1211  {
1212  if (path.empty()) {
1213  return false;
1214  }
1215  if (base::utils::File::pathExists(path.c_str())) {
1216  return true;
1217  }
1218  int status = -1;
1219 
1220  char* currPath = const_cast<char*>(path.c_str());
1221  std::string builtPath = std::string();
1222 #if ELPP_OS_UNIX
1223  if (path[0] == '/') {
1224  builtPath = "/";
1225  }
1226  currPath = STRTOK(currPath, base::consts::kFilePathSeperator, 0);
1227 #elif ELPP_OS_WINDOWS
1228  // Use secure functions API
1229  char* nextTok_ = nullptr;
1230  currPath = STRTOK(currPath, base::consts::kFilePathSeperator, &nextTok_);
1231  ELPP_UNUSED(nextTok_);
1232 #endif // ELPP_OS_UNIX
1233  while (currPath != nullptr) {
1234  builtPath.append(currPath);
1235  builtPath.append(base::consts::kFilePathSeperator);
1236 #if ELPP_OS_UNIX
1237  status = mkdir(builtPath.c_str(), ELPP_LOG_PERMS);
1238  currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, 0);
1239 #elif ELPP_OS_WINDOWS
1240  status = _mkdir(builtPath.c_str());
1241  currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, &nextTok_);
1242 #endif // ELPP_OS_UNIX
1243  }
1244  if (status == -1) {
1245  ELPP_INTERNAL_ERROR("Error while creating path [" << path << "]", true);
1246  return false;
1247  }
1248  return true;
1249  }
1251  static std::string extractPathFromFilename(const std::string& fullPath,
1252  const char* seperator = base::consts::kFilePathSeperator)
1253  {
1254  if ((fullPath == "") || (fullPath.find(seperator) == std::string::npos)) {
1255  return fullPath;
1256  }
1257  std::size_t lastSlashAt = fullPath.find_last_of(seperator);
1258  if (lastSlashAt == 0) {
1259  return std::string(seperator);
1260  }
1261  return fullPath.substr(0, lastSlashAt + 1);
1262  }
1264  static void buildStrippedFilename(const char* filename, char buff[],
1265  std::size_t limit = base::consts::kSourceFilenameMaxLength)
1266  {
1267  std::size_t sizeOfFilename = strlen(filename);
1268  if (sizeOfFilename >= limit) {
1269  filename += (sizeOfFilename - limit);
1270  if (filename[0] != '.' && filename[1] != '.') { // prepend if not already
1271  filename += 3; // 3 = '..'
1272  STRCAT(buff, "..", limit);
1273  }
1274  }
1275  STRCAT(buff, filename, limit);
1276  }
1278  static void buildBaseFilename(const std::string& fullPath, char buff[],
1279  std::size_t limit = base::consts::kSourceFilenameMaxLength,
1280  const char* seperator = base::consts::kFilePathSeperator)
1281  {
1282  const char* filename = fullPath.c_str();
1283  std::size_t lastSlashAt = fullPath.find_last_of(seperator);
1284  filename += lastSlashAt ? lastSlashAt + 1 : 0;
1285  std::size_t sizeOfFilename = strlen(filename);
1286  if (sizeOfFilename >= limit) {
1287  filename += (sizeOfFilename - limit);
1288  if (filename[0] != '.' && filename[1] != '.') { // prepend if not already
1289  filename += 3; // 3 = '..'
1290  STRCAT(buff, "..", limit);
1291  }
1292  }
1293  STRCAT(buff, filename, limit);
1294  }
1295 };
1297 class Str : base::StaticClass
1298 {
1299 public:
1301  static inline bool isDigit(char c)
1302  {
1303  return c >= '0' && c <= '9';
1304  }
1305 
1307  static bool wildCardMatch(const char* str, const char* pattern)
1308  {
1309  while (*pattern) {
1310  switch (*pattern) {
1311  case '?':
1312  if (!*str)
1313  return false;
1314  ++str;
1315  ++pattern;
1316  break;
1317  case '*':
1318  if (wildCardMatch(str, pattern + 1))
1319  return true;
1320  if (*str && wildCardMatch(str + 1, pattern))
1321  return true;
1322  return false;
1323  break;
1324  default:
1325  if (*str++ != *pattern++)
1326  return false;
1327  break;
1328  }
1329  }
1330  return !*str && !*pattern;
1331  }
1332 
1335  static inline std::string& ltrim(std::string& str)
1336  {
1337  str.erase(str.begin(), std::find_if(str.begin(), str.end(), std::not1(std::ptr_fun<int, int>(&std::isspace))));
1338  return str;
1339  }
1340 
1343  static inline std::string& rtrim(std::string& str)
1344  {
1345  str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::ptr_fun<int, int>(&std::isspace))).base(), str.end());
1346  return str;
1347  }
1348 
1351  static inline std::string& trim(std::string& str)
1352  {
1353  return ltrim(rtrim(str));
1354  }
1355 
1360  static inline bool startsWith(const std::string& str, const std::string& start)
1361  {
1362  return (str.length() >= start.length()) && (str.compare(0, start.length(), start) == 0);
1363  }
1364 
1369  static inline bool endsWith(const std::string& str, const std::string& end)
1370  {
1371  return (str.length() >= end.length()) && (str.compare(str.length() - end.length(), end.length(), end) == 0);
1372  }
1373 
1379  static inline std::string& replaceAll(std::string& str, char replaceWhat, char replaceWith)
1380  {
1381  std::replace(str.begin(), str.end(), replaceWhat, replaceWith);
1382  return str;
1383  }
1384 
1390  static inline std::string& replaceAll(std::string& str, const std::string& replaceWhat, // NOLINT
1391  const std::string& replaceWith)
1392  {
1393  if (replaceWhat == replaceWith)
1394  return str;
1395  std::size_t foundAt = std::string::npos;
1396  while ((foundAt = str.find(replaceWhat, foundAt + 1)) != std::string::npos) {
1397  str.replace(foundAt, replaceWhat.length(), replaceWith);
1398  }
1399  return str;
1400  }
1401 
1402  static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, // NOLINT
1403  const base::type::string_t& replaceWith)
1404  {
1405  std::size_t foundAt = base::type::string_t::npos;
1406  while ((foundAt = str.find(replaceWhat, foundAt + 1)) != base::type::string_t::npos) {
1407  if (foundAt > 0 && str[foundAt - 1] == base::consts::kFormatSpecifierChar) {
1408  str.erase(foundAt > 0 ? foundAt - 1 : 0, 1);
1409  ++foundAt;
1410  } else {
1411  str.replace(foundAt, replaceWhat.length(), replaceWith);
1412  return;
1413  }
1414  }
1415  }
1416 #if defined(ELPP_UNICODE)
1417  static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, // NOLINT
1418  const std::string& replaceWith)
1419  {
1420  replaceFirstWithEscape(str, replaceWhat, base::type::string_t(replaceWith.begin(), replaceWith.end()));
1421  }
1422 #endif // defined(ELPP_UNICODE)
1423  static inline std::string& toUpper(std::string& str)
1427  {
1428  std::transform(str.begin(), str.end(), str.begin(), ::toupper);
1429  return str;
1430  }
1431 
1433  static inline bool cStringEq(const char* s1, const char* s2)
1434  {
1435  if (s1 == nullptr && s2 == nullptr) return true;
1436  if (s1 == nullptr || s2 == nullptr) return false;
1437  return strcmp(s1, s2) == 0;
1438  }
1439 
1442  static bool cStringCaseEq(const char* s1, const char* s2)
1443  {
1444  if (s1 == nullptr && s2 == nullptr) return true;
1445  if (s1 == nullptr || s2 == nullptr) return false;
1446  if (strlen(s1) != strlen(s2)) return false;
1447  while (*s1 != '\0' && *s2 != '\0') {
1448  if (::toupper(*s1) != ::toupper(*s2)) return false;
1449  ++s1;
1450  ++s2;
1451  }
1452  return true;
1453  }
1454 
1456  static inline bool contains(const char* str, char c)
1457  {
1458  for (; *str; ++str) {
1459  if (*str == c)
1460  return true;
1461  }
1462  return false;
1463  }
1464 
1465  static inline char* convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded = true)
1466  {
1467  char localBuff[10] = "";
1468  char* p = localBuff + sizeof(localBuff) - 2;
1469  if (n > 0) {
1470  for (; n > 0 && p > localBuff && len > 0; n /= 10, --len)
1471  * --p = static_cast<char>(n % 10 + '0');
1472  } else {
1473  *--p = '0';
1474  --len;
1475  }
1476  if (zeroPadded)
1477  while (p > localBuff && len-- > 0) *--p = static_cast<char>('0');
1478  return addToBuff(p, buf, bufLim);
1479  }
1480 
1481  static inline char* addToBuff(const char* str, char* buf, const char* bufLim)
1482  {
1483  while ((buf < bufLim) && ((*buf = *str++) != '\0'))
1484  ++buf;
1485  return buf;
1486  }
1487 
1488  static inline char* clearBuff(char buff[], std::size_t lim)
1489  {
1490  STRCPY(buff, "", lim);
1491  ELPP_UNUSED(lim); // For *nix we dont have anything using lim in above STRCPY macro
1492  return buff;
1493  }
1494 
1497  static char* wcharPtrToCharPtr(const wchar_t* line)
1498  {
1499  std::size_t len_ = wcslen(line) + 1;
1500  char* buff_ = static_cast<char*>(malloc(len_ + 1));
1501 # if ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS)
1502  std::wcstombs(buff_, line, len_);
1503 # elif ELPP_OS_WINDOWS
1504  std::size_t convCount_ = 0;
1505  mbstate_t mbState_;
1506  ::memset(static_cast<void*>(&mbState_), 0, sizeof(mbState_));
1507  wcsrtombs_s(&convCount_, buff_, len_, &line, len_, &mbState_);
1508 # endif // ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS)
1509  return buff_;
1510  }
1511 };
1513 class OS : base::StaticClass
1514 {
1515 public:
1516 #if ELPP_OS_WINDOWS
1517  static const char* getWindowsEnvironmentVariable(const char* varname)
1522  {
1523  const DWORD bufferLen = 50;
1524  static char buffer[bufferLen];
1525  if (GetEnvironmentVariableA(varname, buffer, bufferLen)) {
1526  return buffer;
1527  }
1528  return nullptr;
1529  }
1530 #endif // ELPP_OS_WINDOWS
1531 #if ELPP_OS_ANDROID
1532  static inline std::string getProperty(const char* prop)
1534  {
1535  char propVal[PROP_VALUE_MAX + 1];
1536  int ret = __system_property_get(prop, propVal);
1537  return ret == 0 ? std::string() : std::string(propVal);
1538  }
1539 
1541  static std::string getDeviceName(void)
1542  {
1543  std::stringstream ss;
1544  std::string manufacturer = getProperty("ro.product.manufacturer");
1545  std::string model = getProperty("ro.product.model");
1546  if (manufacturer.empty() || model.empty()) {
1547  return std::string();
1548  }
1549  ss << manufacturer << "-" << model;
1550  return ss.str();
1551  }
1552 #endif // ELPP_OS_ANDROID
1553 
1559  static const std::string getBashOutput(const char* command)
1560  {
1561 #if (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN)
1562  if (command == nullptr) {
1563  return std::string();
1564  }
1565  FILE* proc = nullptr;
1566  if ((proc = popen(command, "r")) == nullptr) {
1567  ELPP_INTERNAL_ERROR("\nUnable to run command [" << command << "]", true);
1568  return std::string();
1569  }
1570  char hBuff[4096];
1571  if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) {
1572  pclose(proc);
1573  if (hBuff[strlen(hBuff) - 1] == '\n') {
1574  hBuff[strlen(hBuff) - 1] = '\0';
1575  }
1576  return std::string(hBuff);
1577  }
1578  return std::string();
1579 #else
1580  ELPP_UNUSED(command);
1581  return std::string();
1582 #endif // (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN)
1583  }
1584 
1590  static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal, const char* alternativeBashCommand = nullptr)
1591  {
1592 #if ELPP_OS_UNIX
1593  const char* val = getenv(variableName);
1594 #elif ELPP_OS_WINDOWS
1595  const char* val = getWindowsEnvironmentVariable(variableName);
1596 #endif // ELPP_OS_UNIX
1597  if ((val == nullptr) || ((strcmp(val, "") == 0))) {
1598 #if ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH)
1599  // Try harder on unix-based systems
1600  std::string valBash = base::utils::OS::getBashOutput(alternativeBashCommand);
1601  if (valBash.empty()) {
1602  return std::string(defaultVal);
1603  } else {
1604  return valBash;
1605  }
1606 #elif ELPP_OS_WINDOWS || ELPP_OS_UNIX
1607  ELPP_UNUSED(alternativeBashCommand);
1608  return std::string(defaultVal);
1609 #endif // ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH)
1610  }
1611  return std::string(val);
1612  }
1614  static inline std::string currentUser(void)
1615  {
1616 #if ELPP_OS_UNIX && !ELPP_OS_ANDROID
1617  return getEnvironmentVariable("USER", base::consts::kUnknownUser, "whoami");
1618 #elif ELPP_OS_WINDOWS
1619  return getEnvironmentVariable("USERNAME", base::consts::kUnknownUser);
1620 #elif ELPP_OS_ANDROID
1621  ELPP_UNUSED(base::consts::kUnknownUser);
1622  return std::string("android");
1623 #else
1624  return std::string();
1625 #endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID
1626  }
1627 
1631  static inline std::string currentHost(void)
1632  {
1633 #if ELPP_OS_UNIX && !ELPP_OS_ANDROID
1634  return getEnvironmentVariable("HOSTNAME", base::consts::kUnknownHost, "hostname");
1635 #elif ELPP_OS_WINDOWS
1636  return getEnvironmentVariable("COMPUTERNAME", base::consts::kUnknownHost);
1637 #elif ELPP_OS_ANDROID
1638  ELPP_UNUSED(base::consts::kUnknownHost);
1639  return getDeviceName();
1640 #else
1641  return std::string();
1642 #endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID
1643  }
1645  static inline bool termSupportsColor(void)
1646  {
1647  std::string term = getEnvironmentVariable("TERM", "");
1648  return term == "xterm" || term == "xterm-color" || term == "xterm-256color" ||
1649  term == "screen" || term == "linux" || term == "cygwin";
1650  }
1651 };
1652 extern std::string s_currentUser;
1653 extern std::string s_currentHost;
1654 extern bool s_termSupportsColor;
1655 #define ELPP_INITI_BASIC_DECLR \
1656  namespace el {\
1657  namespace base {\
1658  namespace utils {\
1659  std::string s_currentUser = el::base::utils::OS::currentUser(); \
1660  std::string s_currentHost = el::base::utils::OS::currentHost(); \
1661  bool s_termSupportsColor = el::base::utils::OS::termSupportsColor(); \
1662  }\
1663  }\
1664  }
1665 class DateTime : base::StaticClass
1667 {
1668 public:
1673  static void gettimeofday(struct timeval* tv)
1674  {
1675 #if ELPP_OS_WINDOWS
1676  if (tv != nullptr) {
1677 # if ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS)
1678  const unsigned __int64 delta_ = 11644473600000000Ui64;
1679 # else
1680  const unsigned __int64 delta_ = 11644473600000000ULL;
1681 # endif // ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS)
1682  const double secOffSet = 0.000001;
1683  const unsigned long usecOffSet = 1000000;
1684  FILETIME fileTime;
1685  GetSystemTimeAsFileTime(&fileTime);
1686  unsigned __int64 present = 0;
1687  present |= fileTime.dwHighDateTime;
1688  present = present << 32;
1689  present |= fileTime.dwLowDateTime;
1690  present /= 10; // mic-sec
1691  // Subtract the difference
1692  present -= delta_;
1693  tv->tv_sec = static_cast<long>(present * secOffSet);
1694  tv->tv_usec = static_cast<long>(present % usecOffSet);
1695  }
1696 #else
1697  ::gettimeofday(tv, nullptr);
1698 #endif // ELPP_OS_WINDOWS
1699  }
1700 
1705  static inline std::string getDateTime(const char* format, const base::MillisecondsWidth* msWidth)
1706  {
1707  struct timeval currTime;
1708  gettimeofday(&currTime);
1709  struct ::tm timeInfo;
1710  buildTimeInfo(&currTime, &timeInfo);
1711  const int kBuffSize = 30;
1712  char buff_[kBuffSize] = "";
1713  parseFormat(buff_, kBuffSize, format, &timeInfo, static_cast<std::size_t>(currTime.tv_usec / msWidth->m_offset), msWidth);
1714  return std::string(buff_);
1715  }
1716 
1718  static base::type::string_t formatTime(unsigned long long time, base::TimestampUnit timestampUnit)
1719  {
1720  double result = static_cast<double>(time);
1721  base::type::EnumType start = static_cast<base::type::EnumType>(timestampUnit);
1722  const base::type::char_t* unit = base::consts::kTimeFormats[start].unit;
1723  for (base::type::EnumType i = start; i < base::consts::kTimeFormatsCount - 1; ++i) {
1724  if (result <= base::consts::kTimeFormats[i].value) {
1725  break;
1726  }
1727  result /= base::consts::kTimeFormats[i].value;
1728  unit = base::consts::kTimeFormats[i + 1].unit;
1729  }
1730  base::type::stringstream_t ss;
1731  ss << result << " " << unit;
1732  return ss.str();
1733  }
1734 
1736  static inline unsigned long long getTimeDifference(const struct timeval& endTime, const struct timeval& startTime, base::TimestampUnit timestampUnit)
1737  {
1738  if (timestampUnit == base::TimestampUnit::Microsecond) {
1739  return static_cast<unsigned long long>(static_cast<unsigned long long>(1000000 * endTime.tv_sec + endTime.tv_usec) -
1740  static_cast<unsigned long long>(1000000 * startTime.tv_sec + startTime.tv_usec));
1741  } else {
1742  return static_cast<unsigned long long>((((endTime.tv_sec - startTime.tv_sec) * 1000000) + (endTime.tv_usec - startTime.tv_usec)) / 1000);
1743  }
1744  }
1745 
1746 private:
1747  static inline struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo)
1748  {
1749 #if ELPP_OS_UNIX
1750  time_t rawTime = currTime->tv_sec;
1751  ::localtime_r(&rawTime, timeInfo);
1752  return timeInfo;
1753 #else
1754 # if ELPP_COMPILER_MSVC
1755  ELPP_UNUSED(currTime);
1756  time_t t;
1757  _time64(&t);
1758  localtime_s(timeInfo, &t);
1759  return timeInfo;
1760 # else
1761  // For any other compilers that don't have CRT warnings issue e.g, MinGW or TDM GCC- we use different method
1762  time_t rawTime = currTime->tv_sec;
1763  struct tm* tmInf = localtime(&rawTime);
1764  *timeInfo = *tmInf;
1765  return timeInfo;
1766 # endif // ELPP_COMPILER_MSVC
1767 #endif // ELPP_OS_UNIX
1768  }
1769  static char* parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo,
1770  std::size_t msec, const base::MillisecondsWidth* msWidth)
1771  {
1772  const char* bufLim = buf + bufSz;
1773  for (; *format; ++format) {
1774  if (*format == base::consts::kFormatSpecifierChar) {
1775  switch (*++format) {
1776  case base::consts::kFormatSpecifierChar: // Escape
1777  break;
1778  case '\0': // End
1779  --format;
1780  break;
1781  case 'd': // Day
1782  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mday, 2, buf, bufLim);
1783  continue;
1784  case 'a': // Day of week (short)
1785  buf = base::utils::Str::addToBuff(base::consts::kDaysAbbrev[tInfo->tm_wday], buf, bufLim);
1786  continue;
1787  case 'A': // Day of week (long)
1788  buf = base::utils::Str::addToBuff(base::consts::kDays[tInfo->tm_wday], buf, bufLim);
1789  continue;
1790  case 'M': // month
1791  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mon + 1, 2, buf, bufLim);
1792  continue;
1793  case 'b': // month (short)
1794  buf = base::utils::Str::addToBuff(base::consts::kMonthsAbbrev[tInfo->tm_mon], buf, bufLim);
1795  continue;
1796  case 'B': // month (long)
1797  buf = base::utils::Str::addToBuff(base::consts::kMonths[tInfo->tm_mon], buf, bufLim);
1798  continue;
1799  case 'y': // year (two digits)
1800  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 2, buf, bufLim);
1801  continue;
1802  case 'Y': // year (four digits)
1803  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 4, buf, bufLim);
1804  continue;
1805  case 'h': // hour (12-hour)
1806  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour % 12, 2, buf, bufLim);
1807  continue;
1808  case 'H': // hour (24-hour)
1809  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour, 2, buf, bufLim);
1810  continue;
1811  case 'm': // minute
1812  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_min, 2, buf, bufLim);
1813  continue;
1814  case 's': // second
1815  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_sec, 2, buf, bufLim);
1816  continue;
1817  case 'z': // milliseconds
1818  case 'g':
1819  buf = base::utils::Str::convertAndAddToBuff(msec, msWidth->m_width, buf, bufLim);
1820  continue;
1821  case 'F': // AM/PM
1822  buf = base::utils::Str::addToBuff((tInfo->tm_hour >= 12) ? base::consts::kPm : base::consts::kAm, buf, bufLim);
1823  continue;
1824  default:
1825  continue;
1826  }
1827  }
1828  if (buf == bufLim) break;
1829  *buf++ = *format;
1830  }
1831  return buf;
1832  }
1833 };
1835 class CommandLineArgs
1836 {
1837 public:
1838  CommandLineArgs(void)
1839  {
1840  setArgs(0, static_cast<char**>(nullptr));
1841  }
1842  CommandLineArgs(int argc, const char** argv)
1843  {
1844  setArgs(argc, argv);
1845  }
1846  CommandLineArgs(int argc, char** argv)
1847  {
1848  setArgs(argc, argv);
1849  }
1850  virtual ~CommandLineArgs(void) {}
1852  inline void setArgs(int argc, const char** argv)
1853  {
1854  setArgs(argc, const_cast<char**>(argv));
1855  }
1857  inline void setArgs(int argc, char** argv)
1858  {
1859  m_params.clear();
1860  m_paramsWithValue.clear();
1861  if (argc == 0 || argv == nullptr) {
1862  return;
1863  }
1864  m_argc = argc;
1865  m_argv = argv;
1866  for (int i = 1; i < m_argc; ++i) {
1867  const char* v = (strstr(m_argv[i], "="));
1868  if (v != nullptr && strlen(v) > 0) {
1869  std::string key = std::string(m_argv[i]);
1870  key = key.substr(0, key.find_first_of('='));
1871  if (hasParamWithValue(key.c_str())) {
1872  ELPP_INTERNAL_INFO(1, "Skipping [" << key << "] arg since it already has value ["
1873  << getParamValue(key.c_str()) << "]");
1874  } else {
1875  m_paramsWithValue.insert(std::make_pair(key, std::string(v + 1)));
1876  }
1877  }
1878  if (v == nullptr) {
1879  if (hasParam(m_argv[i])) {
1880  ELPP_INTERNAL_INFO(1, "Skipping [" << m_argv[i] << "] arg since it already exists");
1881  } else {
1882  m_params.push_back(std::string(m_argv[i]));
1883  }
1884  }
1885  }
1886  }
1888  inline bool hasParamWithValue(const char* paramKey) const
1889  {
1890  return m_paramsWithValue.find(std::string(paramKey)) != m_paramsWithValue.end();
1891  }
1894  inline const char* getParamValue(const char* paramKey) const
1895  {
1896  return m_paramsWithValue.find(std::string(paramKey))->second.c_str();
1897  }
1899  inline bool hasParam(const char* paramKey) const
1900  {
1901  return std::find(m_params.begin(), m_params.end(), std::string(paramKey)) != m_params.end();
1902  }
1904  inline bool empty(void) const
1905  {
1906  return m_params.empty() && m_paramsWithValue.empty();
1907  }
1909  inline std::size_t size(void) const
1910  {
1911  return m_params.size() + m_paramsWithValue.size();
1912  }
1913  inline friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c)
1914  {
1915  for (int i = 1; i < c.m_argc; ++i) {
1916  os << ELPP_LITERAL("[") << c.m_argv[i] << ELPP_LITERAL("]");
1917  if (i < c.m_argc - 1) {
1918  os << ELPP_LITERAL(" ");
1919  }
1920  }
1921  return os;
1922  }
1923 
1924 private:
1925  int m_argc;
1926  char** m_argv;
1927  std::map<std::string, std::string> m_paramsWithValue;
1928  std::vector<std::string> m_params;
1929 };
1936 template <typename T_Ptr, typename Container>
1937 class AbstractRegistry : public base::threading::ThreadSafe
1938 {
1939 public:
1940  typedef typename Container::iterator iterator;
1941  typedef typename Container::const_iterator const_iterator;
1942 
1944  AbstractRegistry(void) {}
1945 
1947  AbstractRegistry(AbstractRegistry&& sr)
1948  {
1949  if (this == &sr) {
1950  return;
1951  }
1952  unregisterAll();
1953  m_list = std::move(sr.m_list);
1954  }
1955 
1956  bool operator==(const AbstractRegistry<T_Ptr, Container>& other)
1957  {
1958  if (size() != other.size()) {
1959  return false;
1960  }
1961  for (std::size_t i = 0; i < m_list.size(); ++i) {
1962  if (m_list.at(i) != other.m_list.at(i)) {
1963  return false;
1964  }
1965  }
1966  return true;
1967  }
1968 
1969  bool operator!=(const AbstractRegistry<T_Ptr, Container>& other)
1970  {
1971  if (size() != other.size()) {
1972  return true;
1973  }
1974  for (std::size_t i = 0; i < m_list.size(); ++i) {
1975  if (m_list.at(i) != other.m_list.at(i)) {
1976  return true;
1977  }
1978  }
1979  return false;
1980  }
1981 
1983  AbstractRegistry& operator=(AbstractRegistry&& sr)
1984  {
1985  if (this == &sr) {
1986  return *this;
1987  }
1988  unregisterAll();
1989  m_list = std::move(sr.m_list);
1990  return *this;
1991  }
1992 
1993  virtual ~AbstractRegistry(void)
1994  {
1995  }
1996 
1998  virtual inline iterator begin(void) ELPP_FINAL {
1999  return m_list.begin();
2000  }
2001 
2003  virtual inline iterator end(void) ELPP_FINAL {
2004  return m_list.end();
2005  }
2006 
2007 
2009  virtual inline const_iterator cbegin(void) const ELPP_FINAL
2010  {
2011  return m_list.cbegin();
2012  }
2013 
2015  virtual inline const_iterator cend(void) const ELPP_FINAL
2016  {
2017  return m_list.cend();
2018  }
2019 
2021  virtual inline bool empty(void) const ELPP_FINAL
2022  {
2023  return m_list.empty();
2024  }
2025 
2027  virtual inline std::size_t size(void) const ELPP_FINAL
2028  {
2029  return m_list.size();
2030  }
2031 
2033  virtual inline Container& list(void) ELPP_FINAL {
2034  return m_list;
2035  }
2036 
2038  virtual inline const Container& list(void) const ELPP_FINAL
2039  {
2040  return m_list;
2041  }
2042 
2044  virtual void unregisterAll(void) = 0;
2045 
2046 protected:
2047  virtual void deepCopy(const AbstractRegistry<T_Ptr, Container>&) = 0;
2048  void reinitDeepCopy(const AbstractRegistry<T_Ptr, Container>& sr)
2049  {
2050  unregisterAll();
2051  deepCopy(sr);
2052  }
2053 
2054 private:
2055  Container m_list;
2056 };
2057 
2063 template <typename T_Ptr, typename T_Key = const char*>
2064 class Registry : public AbstractRegistry<T_Ptr, std::map<T_Key, T_Ptr*>>
2065 {
2066 public:
2067  typedef typename Registry<T_Ptr, T_Key>::iterator iterator;
2068  typedef typename Registry<T_Ptr, T_Key>::const_iterator const_iterator;
2069 
2070  Registry(void) {}
2071 
2073  Registry(const Registry& sr) : AbstractRegistry<T_Ptr, std::vector<T_Ptr * >>()
2074  {
2075  if (this == &sr) {
2076  return;
2077  }
2078  this->reinitDeepCopy(sr);
2079  }
2080 
2084  Registry& operator=(const Registry& sr)
2085  {
2086  if (this == &sr) {
2087  return *this;
2088  }
2089  this->reinitDeepCopy(sr);
2090  return *this;
2091  }
2092 
2093  virtual ~Registry(void)
2094  {
2095  unregisterAll();
2096  }
2097 
2098 protected:
2099  virtual inline void unregisterAll(void) ELPP_FINAL {
2100  if (!this->empty())
2101  {
2102  for (auto && curr : this->list()) {
2103  base::utils::safeDelete(curr.second);
2104  }
2105  this->list().clear();
2106  }
2107  }
2108 
2110  virtual inline void registerNew(const T_Key& uniqKey, T_Ptr* ptr) ELPP_FINAL {
2111  unregister(uniqKey);
2112  this->list().insert(std::make_pair(uniqKey, ptr));
2113  }
2114 
2116  inline void unregister(const T_Key& uniqKey)
2117  {
2118  T_Ptr* existing = get(uniqKey);
2119  if (existing != nullptr) {
2120  base::utils::safeDelete(existing);
2121  this->list().erase(uniqKey);
2122  }
2123  }
2124 
2126  inline T_Ptr* get(const T_Key& uniqKey)
2127  {
2128  iterator it = this->list().find(uniqKey);
2129  return it == this->list().end()
2130  ? nullptr
2131  : it->second;
2132  }
2133 
2134 private:
2135  virtual inline void deepCopy(const AbstractRegistry<T_Ptr, std::map<T_Key, T_Ptr*>>& sr) ELPP_FINAL {
2136  for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it)
2137  {
2138  registerNew(it->first, new T_Ptr(*it->second));
2139  }
2140  }
2141 };
2142 
2147 template <typename T_Ptr, typename Pred>
2148 class RegistryWithPred : public AbstractRegistry<T_Ptr, std::vector<T_Ptr*>>
2149 {
2150 public:
2151  typedef typename RegistryWithPred<T_Ptr, Pred>::iterator iterator;
2152  typedef typename RegistryWithPred<T_Ptr, Pred>::const_iterator const_iterator;
2153 
2154  RegistryWithPred(void)
2155  {
2156  }
2157 
2158  virtual ~RegistryWithPred(void)
2159  {
2160  unregisterAll();
2161  }
2162 
2164  RegistryWithPred(const RegistryWithPred& sr) : AbstractRegistry<T_Ptr, std::vector<T_Ptr * >>()
2165  {
2166  if (this == &sr) {
2167  return;
2168  }
2169  this->reinitDeepCopy(sr);
2170  }
2171 
2175  RegistryWithPred& operator=(const RegistryWithPred& sr)
2176  {
2177  if (this == &sr) {
2178  return *this;
2179  }
2180  this->reinitDeepCopy(sr);
2181  return *this;
2182  }
2183 
2184  friend inline base::type::ostream_t& operator<<(base::type::ostream_t& os, const RegistryWithPred& sr)
2185  {
2186  for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
2187  os << ELPP_LITERAL(" ") << **it << ELPP_LITERAL("\n");
2188  }
2189  return os;
2190  }
2191 
2192 protected:
2193  virtual inline void unregisterAll(void) ELPP_FINAL {
2194  if (!this->empty())
2195  {
2196  for (auto && curr : this->list()) {
2197  base::utils::safeDelete(curr);
2198  }
2199  this->list().clear();
2200  }
2201  }
2202 
2203  virtual void unregister(T_Ptr*& ptr) ELPP_FINAL {
2204  if (ptr)
2205  {
2206  iterator iter = this->begin();
2207  for (; iter != this->end(); ++iter) {
2208  if (ptr == *iter) {
2209  break;
2210  }
2211  }
2212  if (iter != this->end() && *iter != nullptr) {
2213  this->list().erase(iter);
2214  base::utils::safeDelete(*iter);
2215  }
2216  }
2217  }
2218 
2219  virtual inline void registerNew(T_Ptr* ptr) ELPP_FINAL {
2220  this->list().push_back(ptr);
2221  }
2222 
2225  template <typename T, typename T2>
2226  inline T_Ptr* get(const T& arg1, const T2 arg2)
2227  {
2228  iterator iter = std::find_if(this->list().begin(), this->list().end(), Pred(arg1, arg2));
2229  if (iter != this->list().end() && *iter != nullptr) {
2230  return *iter;
2231  }
2232  return nullptr;
2233  }
2234 
2235 private:
2236  virtual inline void deepCopy(const AbstractRegistry<T_Ptr, std::vector<T_Ptr*>>& sr)
2237  {
2238  for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
2239  registerNew(new T_Ptr(**it));
2240  }
2241  }
2242 };
2243 
2244 } // namespace utils
2245 } // namespace base
2249 class Loggable
2250 {
2251 public:
2252  virtual ~Loggable(void) {}
2253  virtual void log(el::base::type::ostream_t&) const = 0;
2254 private:
2255  friend inline el::base::type::ostream_t& operator<<(el::base::type::ostream_t& os, const Loggable& loggable)
2256  {
2257  loggable.log(os);
2258  return os;
2259  }
2260 };
2261 namespace base {
2263 class LogFormat : public Loggable
2264 {
2265 public:
2266  LogFormat(void) :
2267  m_level(Level::Unknown),
2268  m_userFormat(base::type::string_t()),
2269  m_format(base::type::string_t()),
2270  m_dateTimeFormat(std::string()),
2271  m_flags(0x0)
2272  {
2273  }
2274 
2275  LogFormat(Level level, const base::type::string_t& format)
2276  : m_level(level), m_userFormat(format)
2277  {
2278  parseFromFormat(m_userFormat);
2279  }
2280 
2281  LogFormat(const LogFormat& logFormat)
2282  {
2283  m_level = logFormat.m_level;
2284  m_userFormat = logFormat.m_userFormat;
2285  m_format = logFormat.m_format;
2286  m_dateTimeFormat = logFormat.m_dateTimeFormat;
2287  m_flags = logFormat.m_flags;
2288  }
2289 
2290  LogFormat(LogFormat&& logFormat)
2291  {
2292  m_level = std::move(logFormat.m_level);
2293  m_userFormat = std::move(logFormat.m_userFormat);
2294  m_format = std::move(logFormat.m_format);
2295  m_dateTimeFormat = std::move(logFormat.m_dateTimeFormat);
2296  m_flags = std::move(logFormat.m_flags);
2297  }
2298 
2299  LogFormat& operator=(const LogFormat& logFormat)
2300  {
2301  m_level = logFormat.m_level;
2302  m_userFormat = logFormat.m_userFormat;
2303  m_dateTimeFormat = logFormat.m_dateTimeFormat;
2304  m_flags = logFormat.m_flags;
2305  return *this;
2306  }
2307 
2308  virtual ~LogFormat(void)
2309  {
2310  }
2311 
2312  inline bool operator==(const LogFormat& other)
2313  {
2314  return m_level == other.m_level && m_userFormat == other.m_userFormat && m_format == other.m_format &&
2315  m_dateTimeFormat == other.m_dateTimeFormat && m_flags == other.m_flags;
2316  }
2317 
2320  void parseFromFormat(const base::type::string_t& userFormat)
2321  {
2322  // We make copy because we will be changing the format
2323  // i.e, removing user provided date format from original format
2324  // and then storing it.
2325  base::type::string_t formatCopy = userFormat;
2326  m_flags = 0x0;
2327  auto conditionalAddFlag = [&](const base::type::char_t* specifier, base::FormatFlags flag) {
2328  std::size_t foundAt = base::type::string_t::npos;
2329  while ((foundAt = formatCopy.find(specifier, foundAt + 1)) != base::type::string_t::npos) {
2330  if (foundAt > 0 && formatCopy[foundAt - 1] == base::consts::kFormatSpecifierChar) {
2331  if (hasFlag(flag)) {
2332  // If we already have flag we remove the escape chars so that '%%' is turned to '%'
2333  // even after specifier resolution - this is because we only replaceFirst specifier
2334  formatCopy.erase(foundAt > 0 ? foundAt - 1 : 0, 1);
2335  ++foundAt;
2336  }
2337  } else {
2338  if (!hasFlag(flag)) addFlag(flag);
2339  }
2340  }
2341  };
2342  conditionalAddFlag(base::consts::kAppNameFormatSpecifier, base::FormatFlags::AppName);
2343  conditionalAddFlag(base::consts::kSeverityLevelFormatSpecifier, base::FormatFlags::Level);
2344  conditionalAddFlag(base::consts::kSeverityLevelShortFormatSpecifier, base::FormatFlags::LevelShort);
2345  conditionalAddFlag(base::consts::kLoggerIdFormatSpecifier, base::FormatFlags::LoggerId);
2346  conditionalAddFlag(base::consts::kThreadIdFormatSpecifier, base::FormatFlags::ThreadId);
2347  conditionalAddFlag(base::consts::kLogFileFormatSpecifier, base::FormatFlags::File);
2348  conditionalAddFlag(base::consts::kLogFileBaseFormatSpecifier, base::FormatFlags::FileBase);
2349  conditionalAddFlag(base::consts::kLogLineFormatSpecifier, base::FormatFlags::Line);
2350  conditionalAddFlag(base::consts::kLogLocationFormatSpecifier, base::FormatFlags::Location);
2351  conditionalAddFlag(base::consts::kLogFunctionFormatSpecifier, base::FormatFlags::Function);
2352  conditionalAddFlag(base::consts::kCurrentUserFormatSpecifier, base::FormatFlags::User);
2353  conditionalAddFlag(base::consts::kCurrentHostFormatSpecifier, base::FormatFlags::Host);
2354  conditionalAddFlag(base::consts::kMessageFormatSpecifier, base::FormatFlags::LogMessage);
2355  conditionalAddFlag(base::consts::kVerboseLevelFormatSpecifier, base::FormatFlags::VerboseLevel);
2356  // For date/time we need to extract user's date format first
2357  std::size_t dateIndex = std::string::npos;
2358  if ((dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier)) != std::string::npos) {
2359  while (dateIndex > 0 && formatCopy[dateIndex - 1] == base::consts::kFormatSpecifierChar) {
2360  dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier, dateIndex + 1);
2361  }
2362  if (dateIndex != std::string::npos) {
2363  addFlag(base::FormatFlags::DateTime);
2364  updateDateFormat(dateIndex, formatCopy);
2365  }
2366  }
2367  m_format = formatCopy;
2368  updateFormatSpec();
2369  }
2370 
2371  inline Level level(void) const
2372  {
2373  return m_level;
2374  }
2375 
2376  inline const base::type::string_t& userFormat(void) const
2377  {
2378  return m_userFormat;
2379  }
2380 
2381  inline const base::type::string_t& format(void) const
2382  {
2383  return m_format;
2384  }
2385 
2386  inline const std::string& dateTimeFormat(void) const
2387  {
2388  return m_dateTimeFormat;
2389  }
2390 
2391  inline base::type::EnumType flags(void) const
2392  {
2393  return m_flags;
2394  }
2395 
2396  inline bool hasFlag(base::FormatFlags flag) const
2397  {
2398  return base::utils::hasFlag(flag, m_flags);
2399  }
2400 
2401  virtual void log(el::base::type::ostream_t& os) const
2402  {
2403  os << m_format;
2404  }
2405 
2406 protected:
2410  virtual void updateDateFormat(std::size_t index, base::type::string_t& currFormat) ELPP_FINAL {
2411  if (hasFlag(base::FormatFlags::DateTime))
2412  {
2413  index += ELPP_STRLEN(base::consts::kDateTimeFormatSpecifier);
2414  }
2415  const base::type::char_t* ptr = currFormat.c_str() + index;
2416  if ((currFormat.size() > index) && (ptr[0] == '{'))
2417  {
2418  // User has provided format for date/time
2419  ++ptr;
2420  int count = 1; // Start by 1 in order to remove starting brace
2421  std::stringstream ss;
2422  for (; *ptr; ++ptr, ++count) {
2423  if (*ptr == '}') {
2424  ++count; // In order to remove ending brace
2425  break;
2426  }
2427  ss << *ptr;
2428  }
2429  currFormat.erase(index, count);
2430  m_dateTimeFormat = ss.str();
2431  } else {
2432  // No format provided, use default
2433  if (hasFlag(base::FormatFlags::DateTime))
2434  {
2435  m_dateTimeFormat = std::string(base::consts::kDefaultDateTimeFormat);
2436  }
2437  }
2438  }
2439 
2441  virtual void updateFormatSpec(void) ELPP_FINAL {
2442  // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet.
2443  if (m_level == Level::Debug)
2444  {
2445  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
2446  base::consts::kDebugLevelLogValue);
2447  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
2448  base::consts::kDebugLevelShortLogValue);
2449  } else if (m_level == Level::Info)
2450  {
2451  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
2452  base::consts::kInfoLevelLogValue);
2453  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
2454  base::consts::kInfoLevelShortLogValue);
2455  } else if (m_level == Level::Warning)
2456  {
2457  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
2458  base::consts::kWarningLevelLogValue);
2459  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
2460  base::consts::kWarningLevelShortLogValue);
2461  } else if (m_level == Level::Error)
2462  {
2463  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
2464  base::consts::kErrorLevelLogValue);
2465  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
2466  base::consts::kErrorLevelShortLogValue);
2467  } else if (m_level == Level::Fatal)
2468  {
2469  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
2470  base::consts::kFatalLevelLogValue);
2471  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
2472  base::consts::kFatalLevelShortLogValue);
2473  } else if (m_level == Level::Verbose)
2474  {
2475  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
2476  base::consts::kVerboseLevelLogValue);
2477  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
2478  base::consts::kVerboseLevelShortLogValue);
2479  } else if (m_level == Level::Trace)
2480  {
2481  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
2482  base::consts::kTraceLevelLogValue);
2483  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
2484  base::consts::kTraceLevelShortLogValue);
2485  }
2486  if (hasFlag(base::FormatFlags::User))
2487  {
2488  std::string s = base::utils::s_currentUser;
2489  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentUserFormatSpecifier,
2490  base::utils::s_currentUser);
2491  }
2492  if (hasFlag(base::FormatFlags::Host))
2493  {
2494  base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentHostFormatSpecifier,
2495  base::utils::s_currentHost);
2496  }
2497  // Ignore Level::Global and Level::Unknown
2498  }
2499 
2500  inline void addFlag(base::FormatFlags flag)
2501  {
2502  base::utils::addFlag(flag, &m_flags);
2503  }
2504 
2505 private:
2506  Level m_level;
2507  base::type::string_t m_userFormat;
2508  base::type::string_t m_format;
2509  std::string m_dateTimeFormat;
2510  base::type::EnumType m_flags;
2511  friend class el::Logger; // To resolve loggerId format specifier easily
2512 };
2513 } // namespace base
2515 typedef std::function<const char* (void)> FormatSpecifierValueResolver;
2519 class CustomFormatSpecifier
2520 {
2521 public:
2522  CustomFormatSpecifier(const char* formatSpecifier, const FormatSpecifierValueResolver& resolver) :
2523  m_formatSpecifier(formatSpecifier), m_resolver(resolver) {}
2524  inline const char* formatSpecifier(void) const { return m_formatSpecifier; }
2525  inline const FormatSpecifierValueResolver& resolver(void) const { return m_resolver; }
2526  inline bool operator==(const char* formatSpecifier)
2527  {
2528  return strcmp(m_formatSpecifier, formatSpecifier) == 0;
2529  }
2530 
2531 private:
2532  const char* m_formatSpecifier;
2533  FormatSpecifierValueResolver m_resolver;
2534 };
2544 class Configuration : public Loggable
2545 {
2546 public:
2547  Configuration(const Configuration& c) :
2548  m_level(c.m_level),
2549  m_configurationType(c.m_configurationType),
2550  m_value(c.m_value)
2551  {
2552  }
2553 
2554  Configuration& operator=(const Configuration& c)
2555  {
2556  m_level = c.m_level;
2557  m_configurationType = c.m_configurationType;
2558  m_value = c.m_value;
2559  return *this;
2560  }
2561 
2562  virtual ~Configuration(void)
2563  {
2564  }
2565 
2567  Configuration(Level level, ConfigurationType configurationType, const std::string& value) :
2568  m_level(level),
2569  m_configurationType(configurationType),
2570  m_value(value)
2571  {
2572  }
2573 
2575  inline Level level(void) const
2576  {
2577  return m_level;
2578  }
2579 
2581  inline ConfigurationType configurationType(void) const
2582  {
2583  return m_configurationType;
2584  }
2585 
2587  inline const std::string& value(void) const
2588  {
2589  return m_value;
2590  }
2591 
2595  inline void setValue(const std::string& value)
2596  {
2597  m_value = value;
2598  }
2599 
2600  virtual inline void log(el::base::type::ostream_t& os) const
2601  {
2602  os << LevelHelper::convertToString(m_level)
2603  << ELPP_LITERAL(" ") << ConfigurationTypeHelper::convertToString(m_configurationType)
2604  << ELPP_LITERAL(" = ") << m_value.c_str();
2605  }
2606 
2608  class Predicate
2609  {
2610  public:
2611  Predicate(Level level, ConfigurationType configurationType) :
2612  m_level(level),
2613  m_configurationType(configurationType)
2614  {
2615  }
2616 
2617  inline bool operator()(const Configuration* conf) const
2618  {
2619  return ((conf != nullptr) && (conf->level() == m_level) && (conf->configurationType() == m_configurationType));
2620  }
2621 
2622  private:
2623  Level m_level;
2624  ConfigurationType m_configurationType;
2625  };
2626 
2627 private:
2628  Level m_level;
2629  ConfigurationType m_configurationType;
2630  std::string m_value;
2631 };
2632 
2636 class Configurations : public base::utils::RegistryWithPred<Configuration, Configuration::Predicate>
2637 {
2638 public:
2640  Configurations(void) :
2641  m_configurationFile(std::string()),
2642  m_isFromFile(false)
2643  {
2644  }
2645 
2652  Configurations(const std::string& configurationFile, bool useDefaultsForRemaining = true, Configurations* base = nullptr) :
2653  m_configurationFile(configurationFile),
2654  m_isFromFile(false)
2655  {
2656  parseFromFile(configurationFile, base);
2657  if (useDefaultsForRemaining) {
2658  setRemainingToDefault();
2659  }
2660  }
2661 
2662  virtual ~Configurations(void)
2663  {
2664  }
2665 
2672  inline bool parseFromFile(const std::string& configurationFile, Configurations* base = nullptr)
2673  {
2674  // We initial assertion with true because if we have assertion diabled, we want to pass this
2675  // check and if assertion is enabled we will have values re-assigned any way.
2676  bool assertionPassed = true;
2677  ELPP_ASSERT((assertionPassed = base::utils::File::pathExists(configurationFile.c_str(), true)),
2678  "Configuration file [" << configurationFile << "] does not exist!");
2679  if (!assertionPassed) {
2680  return false;
2681  }
2682  bool success = Parser::parseFromFile(configurationFile, this, base);
2683  m_isFromFile = success;
2684  return success;
2685  }
2686 
2695  inline bool parseFromText(const std::string& configurationsString, Configurations* base = nullptr)
2696  {
2697  bool success = Parser::parseFromText(configurationsString, this, base);
2698  if (success) {
2699  m_isFromFile = false;
2700  }
2701  return success;
2702  }
2703 
2706  inline void setFromBase(Configurations* base)
2707  {
2708  if (base == nullptr || base == this) {
2709  return;
2710  }
2711  base::threading::ScopedLock scopedLock(base->lock());
2712  for (Configuration*& conf : base->list()) {
2713  set(conf);
2714  }
2715  }
2716 
2721  bool hasConfiguration(ConfigurationType configurationType)
2722  {
2723  base::type::EnumType lIndex = LevelHelper::kMinValid;
2724  bool result = false;
2725  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
2726  if (hasConfiguration(LevelHelper::castFromInt(lIndex), configurationType))
2727  {
2728  result = true;
2729  }
2730  return result;
2731  });
2732  return result;
2733  }
2734 
2738  inline bool hasConfiguration(Level level, ConfigurationType configurationType)
2739  {
2740  base::threading::ScopedLock scopedLock(lock());
2741 #if ELPP_COMPILER_INTEL
2742  // We cant specify template types here, Intel C++ throws compilation error
2743  // "error: type name is not allowed"
2744  return RegistryWithPred::get(level, configurationType) != nullptr;
2745 #else
2746  return RegistryWithPred<Configuration, Configuration::Predicate>::get(level, configurationType) != nullptr;
2747 #endif // ELPP_COMPILER_INTEL
2748  }
2749 
2762  inline void set(Level level, ConfigurationType configurationType, const std::string& value)
2763  {
2764  base::threading::ScopedLock scopedLock(lock());
2765  unsafeSet(level, configurationType, value); // This is not unsafe anymore as we have locked mutex
2766  if (level == Level::Global) {
2767  unsafeSetGlobally(configurationType, value, false); // Again this is not unsafe either
2768  }
2769  }
2770 
2773  inline void set(Configuration* conf)
2774  {
2775  if (conf == nullptr) {
2776  return;
2777  }
2778  set(conf->level(), conf->configurationType(), conf->value());
2779  }
2780 
2781  inline Configuration* get(Level level, ConfigurationType configurationType)
2782  {
2783  base::threading::ScopedLock scopedLock(lock());
2784  return RegistryWithPred<Configuration, Configuration::Predicate>::get(level, configurationType);
2785  }
2786 
2791  inline void setGlobally(ConfigurationType configurationType, const std::string& value)
2792  {
2793  setGlobally(configurationType, value, false);
2794  }
2795 
2797  inline void clear(void)
2798  {
2799  base::threading::ScopedLock scopedLock(lock());
2800  unregisterAll();
2801  }
2802 
2806  inline const std::string& configurationFile(void) const
2807  {
2808  return m_configurationFile;
2809  }
2810 
2812  void setToDefault(void)
2813  {
2814  setGlobally(ConfigurationType::Enabled, std::string("true"), true);
2815 #if !defined(ELPP_NO_DEFAULT_LOG_FILE)
2816  setGlobally(ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile), true);
2817 #else
2818  ELPP_UNUSED(base::consts::kDefaultLogFile);
2819 #endif // !defined(ELPP_NO_DEFAULT_LOG_FILE)
2820  setGlobally(ConfigurationType::ToFile, std::string("false"), true);
2821  setGlobally(ConfigurationType::ToStandardOutput, std::string("true"), true);
2822  setGlobally(ConfigurationType::MillisecondsWidth, std::string("3"), true);
2823  setGlobally(ConfigurationType::PerformanceTracking, std::string("true"), true);
2824  setGlobally(ConfigurationType::MaxLogFileSize, std::string("10000000"), true);
2825  setGlobally(ConfigurationType::LogFlushThreshold, std::string("0"), true);
2826 
2827  setGlobally(ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"), true);
2828  set(Level::Debug, ConfigurationType::Format, std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg"));
2829  // INFO and WARNING are set to default by Level::Global
2830  set(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
2831  set(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
2832  set(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg"));
2833  set(Level::Trace, ConfigurationType::Format, std::string("%datetime %level [%logger] [%func] [%loc] %msg"));
2834  }
2835 
2843  void setRemainingToDefault(void)
2844  {
2845  base::threading::ScopedLock scopedLock(lock());
2846  unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("true"));
2847 #if !defined(ELPP_NO_DEFAULT_LOG_FILE)
2848  unsafeSetIfNotExist(Level::Global, ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile));
2849 #endif // !defined(ELPP_NO_DEFAULT_LOG_FILE)
2850  unsafeSetIfNotExist(Level::Global, ConfigurationType::ToFile, std::string("false"));
2851  unsafeSetIfNotExist(Level::Global, ConfigurationType::ToStandardOutput, std::string("true"));
2852  unsafeSetIfNotExist(Level::Global, ConfigurationType::MillisecondsWidth, std::string("3"));
2853  unsafeSetIfNotExist(Level::Global, ConfigurationType::PerformanceTracking, std::string("true"));
2854  unsafeSetIfNotExist(Level::Global, ConfigurationType::MaxLogFileSize, std::string("10000000"));
2855  unsafeSetIfNotExist(Level::Global, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
2856  unsafeSetIfNotExist(Level::Debug, ConfigurationType::Format,
2857  std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg"));
2858  // INFO and WARNING are set to default by Level::Global
2859  unsafeSetIfNotExist(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
2860  unsafeSetIfNotExist(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
2861  unsafeSetIfNotExist(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg"));
2862  unsafeSetIfNotExist(Level::Trace, ConfigurationType::Format, std::string("%datetime %level [%logger] [%func] [%loc] %msg"));
2863  }
2864 
2869  class Parser : base::StaticClass
2870  {
2871  public:
2879  static bool parseFromFile(const std::string& configurationFile, Configurations* sender, Configurations* base = nullptr)
2880  {
2881  sender->setFromBase(base);
2882  std::ifstream fileStream_(configurationFile.c_str(), std::ifstream::in);
2883  ELPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file [" << configurationFile << "] for parsing.");
2884  bool parsedSuccessfully = false;
2885  std::string line = std::string();
2886  Level currLevel = Level::Unknown;
2887  std::string currConfigStr = std::string();
2888  std::string currLevelStr = std::string();
2889  while (fileStream_.good()) {
2890  std::getline(fileStream_, line);
2891  parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender);
2892  ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line);
2893  }
2894  return parsedSuccessfully;
2895  }
2896 
2907  static bool parseFromText(const std::string& configurationsString, Configurations* sender, Configurations* base = nullptr)
2908  {
2909  sender->setFromBase(base);
2910  bool parsedSuccessfully = false;
2911  std::stringstream ss(configurationsString);
2912  std::string line = std::string();
2913  Level currLevel = Level::Unknown;
2914  std::string currConfigStr = std::string();
2915  std::string currLevelStr = std::string();
2916  while (std::getline(ss, line)) {
2917  parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender);
2918  ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line);
2919  }
2920  return parsedSuccessfully;
2921  }
2922 
2923  private:
2924  friend class el::Loggers;
2925  static void ignoreComments(std::string* line)
2926  {
2927  std::size_t foundAt = 0;
2928  std::size_t quotesStart = line->find("\"");
2929  std::size_t quotesEnd = std::string::npos;
2930  if (quotesStart != std::string::npos) {
2931  quotesEnd = line->find("\"", quotesStart + 1);
2932  while (quotesEnd != std::string::npos && line->at(quotesEnd - 1) == '\\') {
2933  // Do not erase slash yet - we will erase it in parseLine(..) while loop
2934  quotesEnd = line->find("\"", quotesEnd + 2);
2935  }
2936  }
2937  if ((foundAt = line->find(base::consts::kConfigurationComment)) != std::string::npos) {
2938  if (foundAt < quotesEnd) {
2939  foundAt = line->find(base::consts::kConfigurationComment, quotesEnd + 1);
2940  }
2941  *line = line->substr(0, foundAt);
2942  }
2943  }
2944  static inline bool isLevel(const std::string& line)
2945  {
2946  return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLevel));
2947  }
2948 
2949  static inline bool isComment(const std::string& line)
2950  {
2951  return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationComment));
2952  }
2953 
2954  static inline bool isConfig(const std::string& line)
2955  {
2956  std::size_t assignment = line.find('=');
2957  return line != "" &&
2958  (line[0] >= 65 || line[0] <= 90 || line[0] >= 97 || line[0] <= 122) &&
2959  (assignment != std::string::npos) &&
2960  (line.size() > assignment);
2961  }
2962 
2963  static bool parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, Level* currLevel, Configurations* conf)
2964  {
2965  ConfigurationType currConfig = ConfigurationType::Unknown;
2966  std::string currValue = std::string();
2967  *line = base::utils::Str::trim(*line);
2968  if (isComment(*line)) return true;
2969  ignoreComments(line);
2970  *line = base::utils::Str::trim(*line);
2971  if (line->empty()) {
2972  // Comment ignored
2973  return true;
2974  }
2975  if (isLevel(*line)) {
2976  if (line->size() <= 2) {
2977  return true;
2978  }
2979  *currLevelStr = line->substr(1, line->size() - 2);
2980  *currLevelStr = base::utils::Str::toUpper(*currLevelStr);
2981  *currLevelStr = base::utils::Str::trim(*currLevelStr);
2982  *currLevel = LevelHelper::convertFromString(currLevelStr->c_str());
2983  return true;
2984  }
2985  if (isConfig(*line)) {
2986  std::size_t assignment = line->find('=');
2987  *currConfigStr = line->substr(0, assignment);
2988  *currConfigStr = base::utils::Str::toUpper(*currConfigStr);
2989  *currConfigStr = base::utils::Str::trim(*currConfigStr);
2990  currConfig = ConfigurationTypeHelper::convertFromString(currConfigStr->c_str());
2991  currValue = line->substr(assignment + 1);
2992  currValue = base::utils::Str::trim(currValue);
2993  std::size_t quotesStart = currValue.find("\"", 0);
2994  std::size_t quotesEnd = std::string::npos;
2995  if (quotesStart != std::string::npos) {
2996  quotesEnd = currValue.find("\"", quotesStart + 1);
2997  while (quotesEnd != std::string::npos && currValue.at(quotesEnd - 1) == '\\') {
2998  currValue = currValue.erase(quotesEnd - 1, 1);
2999  quotesEnd = currValue.find("\"", quotesEnd + 2);
3000  }
3001  }
3002  if (quotesStart != std::string::npos && quotesEnd != std::string::npos) {
3003  // Quote provided - check and strip if valid
3004  ELPP_ASSERT((quotesStart < quotesEnd), "Configuration error - No ending quote found in ["
3005  << currConfigStr << "]");
3006  ELPP_ASSERT((quotesStart + 1 != quotesEnd), "Empty configuration value for [" << currConfigStr << "]");
3007  if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) {
3008  // Explicit check in case if assertion is disabled
3009  currValue = currValue.substr(quotesStart + 1, quotesEnd - 1);
3010  }
3011  }
3012  }
3013  ELPP_ASSERT(*currLevel != Level::Unknown, "Unrecognized severity level [" << *currLevelStr << "]");
3014  ELPP_ASSERT(currConfig != ConfigurationType::Unknown, "Unrecognized configuration [" << *currConfigStr << "]");
3015  if (*currLevel == Level::Unknown || currConfig == ConfigurationType::Unknown) {
3016  return false; // unrecognizable level or config
3017  }
3018  conf->set(*currLevel, currConfig, currValue);
3019  return true;
3020  }
3021  };
3022 
3023 private:
3024  std::string m_configurationFile;
3025  bool m_isFromFile;
3026  friend class el::Loggers;
3027 
3029  void unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value)
3030  {
3031  Configuration* conf = RegistryWithPred<Configuration, Configuration::Predicate>::get(level, configurationType);
3032  if (conf == nullptr) {
3033  unsafeSet(level, configurationType, value);
3034  }
3035  }
3036 
3038  void unsafeSet(Level level, ConfigurationType configurationType, const std::string& value)
3039  {
3040  Configuration* conf = RegistryWithPred<Configuration, Configuration::Predicate>::get(level, configurationType);
3041  if (conf == nullptr) {
3042  registerNew(new Configuration(level, configurationType, value));
3043  } else {
3044  conf->setValue(value);
3045  }
3046  if (level == Level::Global) {
3047  unsafeSetGlobally(configurationType, value, false);
3048  }
3049  }
3050 
3053  void setGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel)
3054  {
3055  if (includeGlobalLevel) {
3056  set(Level::Global, configurationType, value);
3057  }
3058  base::type::EnumType lIndex = LevelHelper::kMinValid;
3059  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
3060  set(LevelHelper::castFromInt(lIndex), configurationType, value);
3061  return false; // Do not break lambda function yet as we need to set all levels regardless
3062  });
3063  }
3064 
3067  void unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel)
3068  {
3069  if (includeGlobalLevel) {
3070  unsafeSet(Level::Global, configurationType, value);
3071  }
3072  base::type::EnumType lIndex = LevelHelper::kMinValid;
3073  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
3074  unsafeSet(LevelHelper::castFromInt(lIndex), configurationType, value);
3075  return false; // Do not break lambda function yet as we need to set all levels regardless
3076  });
3077  }
3078 };
3079 
3080 namespace base {
3081 typedef std::shared_ptr<base::type::fstream_t> FileStreamPtr;
3082 typedef std::map<std::string, FileStreamPtr> LogStreamsReferenceMap;
3089 class TypedConfigurations : public base::threading::ThreadSafe
3090 {
3091 public:
3095  TypedConfigurations(Configurations* configurations, base::LogStreamsReferenceMap* logStreamsReference)
3096  {
3097  m_configurations = configurations;
3098  m_logStreamsReference = logStreamsReference;
3099  build(m_configurations);
3100  }
3101 
3102  TypedConfigurations(const TypedConfigurations& other)
3103  {
3104  this->m_configurations = other.m_configurations;
3105  this->m_logStreamsReference = other.m_logStreamsReference;
3106  build(m_configurations);
3107  }
3108 
3109  virtual ~TypedConfigurations(void)
3110  {
3111  }
3112 
3113  const Configurations* configurations(void) const
3114  {
3115  return m_configurations;
3116  }
3117 
3118  inline bool enabled(Level level)
3119  {
3120  return getConfigByVal<bool>(level, &m_enabledMap, "enabled");
3121  }
3122 
3123  inline bool toFile(Level level)
3124  {
3125  return getConfigByVal<bool>(level, &m_toFileMap, "toFile");
3126  }
3127 
3128  inline const std::string& filename(Level level)
3129  {
3130  return getConfigByRef<std::string>(level, &m_filenameMap, "filename");
3131  }
3132 
3133  inline bool toStandardOutput(Level level)
3134  {
3135  return getConfigByVal<bool>(level, &m_toStandardOutputMap, "toStandardOutput");
3136  }
3137 
3138  inline const base::LogFormat& logFormat(Level level)
3139  {
3140  return getConfigByRef<base::LogFormat>(level, &m_logFormatMap, "logFormat");
3141  }
3142 
3143  inline const base::MillisecondsWidth& millisecondsWidth(Level level = Level::Global)
3144  {
3145  return getConfigByRef<base::MillisecondsWidth>(level, &m_millisecondsWidthMap, "millisecondsWidth");
3146  }
3147 
3148  inline bool performanceTracking(Level level = Level::Global)
3149  {
3150  return getConfigByVal<bool>(level, &m_performanceTrackingMap, "performanceTracking");
3151  }
3152 
3153  inline base::type::fstream_t* fileStream(Level level)
3154  {
3155  return getConfigByRef<base::FileStreamPtr>(level, &m_fileStreamMap, "fileStream").get();
3156  }
3157 
3158  inline std::size_t maxLogFileSize(Level level)
3159  {
3160  return getConfigByVal<std::size_t>(level, &m_maxLogFileSizeMap, "maxLogFileSize");
3161  }
3162 
3163  inline std::size_t logFlushThreshold(Level level)
3164  {
3165  return getConfigByVal<std::size_t>(level, &m_logFlushThresholdMap, "logFlushThreshold");
3166  }
3167 
3168 private:
3169  Configurations* m_configurations;
3170  std::map<Level, bool> m_enabledMap;
3171  std::map<Level, bool> m_toFileMap;
3172  std::map<Level, std::string> m_filenameMap;
3173  std::map<Level, bool> m_toStandardOutputMap;
3174  std::map<Level, base::LogFormat> m_logFormatMap;
3175  std::map<Level, base::MillisecondsWidth> m_millisecondsWidthMap;
3176  std::map<Level, bool> m_performanceTrackingMap;
3177  std::map<Level, base::FileStreamPtr> m_fileStreamMap;
3178  std::map<Level, std::size_t> m_maxLogFileSizeMap;
3179  std::map<Level, std::size_t> m_logFlushThresholdMap;
3180  base::LogStreamsReferenceMap* m_logStreamsReference;
3181 
3182  friend class el::Helpers;
3183  friend class el::base::MessageBuilder;
3184  friend class el::base::Writer;
3185  friend class el::base::DefaultLogDispatchCallback;
3186  friend class el::base::LogDispatcher;
3187 
3188  template <typename Conf_T>
3189  inline Conf_T getConfigByVal(Level level, const std::map<Level, Conf_T>* confMap, const char* confName)
3190  {
3191  base::threading::ScopedLock scopedLock(lock());
3192  return unsafeGetConfigByVal(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope
3193  }
3194 
3195  template <typename Conf_T>
3196  inline Conf_T& getConfigByRef(Level level, std::map<Level, Conf_T>* confMap, const char* confName)
3197  {
3198  base::threading::ScopedLock scopedLock(lock());
3199  return unsafeGetConfigByRef(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope
3200  }
3201 
3202  template <typename Conf_T>
3203  inline Conf_T unsafeGetConfigByVal(Level level, const std::map<Level, Conf_T>* confMap, const char* confName)
3204  {
3205  ELPP_UNUSED(confName);
3206  typename std::map<Level, Conf_T>::const_iterator it = confMap->find(level);
3207  if (it == confMap->end()) {
3208  try {
3209  return confMap->at(Level::Global);
3210  } catch (...) {
3211  ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level ["
3212  << LevelHelper::convertToString(level) << "]"
3213  << std::endl << "Please ensure you have properly configured logger.", false);
3214  return Conf_T();
3215  }
3216  }
3217  return it->second;
3218  }
3219 
3220  template <typename Conf_T>
3221  inline Conf_T& unsafeGetConfigByRef(Level level, std::map<Level, Conf_T>* confMap, const char* confName)
3222  {
3223  ELPP_UNUSED(confName);
3224  typename std::map<Level, Conf_T>::iterator it = confMap->find(level);
3225  if (it == confMap->end()) {
3226  try {
3227  return confMap->at(Level::Global);
3228  } catch (...) {
3229  ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level ["
3230  << LevelHelper::convertToString(level) << "]"
3231  << std::endl << "Please ensure you have properly configured logger.", false);
3232  }
3233  }
3234  return it->second;
3235  }
3236 
3237  template <typename Conf_T>
3238  void setValue(Level level, const Conf_T& value, std::map<Level, Conf_T>* confMap, bool includeGlobalLevel = true)
3239  {
3240  // If map is empty and we are allowed to add into generic level (Level::Global), do it!
3241  if (confMap->empty() && includeGlobalLevel) {
3242  confMap->insert(std::make_pair(Level::Global, value));
3243  return;
3244  }
3245  // If same value exist in generic level already, dont add it to explicit level
3246  typename std::map<Level, Conf_T>::iterator it = confMap->find(Level::Global);
3247  if (it != confMap->end() && it->second == value) {
3248  return;
3249  }
3250  // Now make sure we dont double up values if we really need to add it to explicit level
3251  it = confMap->find(level);
3252  if (it == confMap->end()) {
3253  // Value not found for level, add new
3254  confMap->insert(std::make_pair(level, value));
3255  } else {
3256  // Value found, just update value
3257  confMap->at(level) = value;
3258  }
3259  }
3260 
3261  void build(Configurations* configurations)
3262  {
3263  base::threading::ScopedLock scopedLock(lock());
3264  auto getBool = [] (std::string boolStr) -> bool { // Pass by value for trimming
3265  base::utils::Str::trim(boolStr);
3266  return (boolStr == "TRUE" || boolStr == "true" || boolStr == "1");
3267  };
3268  std::vector<Configuration*> withFileSizeLimit;
3269  for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) {
3270  Configuration* conf = *it;
3271  // We cannot use switch on strong enums because Intel C++ dont support them yet
3272  if (conf->configurationType() == ConfigurationType::Enabled) {
3273  setValue(conf->level(), getBool(conf->value()), &m_enabledMap);
3274  } else if (conf->configurationType() == ConfigurationType::ToFile) {
3275  setValue(conf->level(), getBool(conf->value()), &m_toFileMap);
3276  } else if (conf->configurationType() == ConfigurationType::ToStandardOutput) {
3277  setValue(conf->level(), getBool(conf->value()), &m_toStandardOutputMap);
3278  } else if (conf->configurationType() == ConfigurationType::Filename) {
3279  // We do not yet configure filename but we will configure in another
3280  // loop. This is because if file cannot be created, we will force ToFile
3281  // to be false. Because configuring logger is not necessarily performance
3282  // sensative operation, we can live with another loop; (by the way this loop
3283  // is not very heavy either)
3284  } else if (conf->configurationType() == ConfigurationType::Format) {
3285  setValue(conf->level(), base::LogFormat(conf->level(),
3286  base::type::string_t(conf->value().begin(), conf->value().end())), &m_logFormatMap);
3287  } else if (conf->configurationType() == ConfigurationType::MillisecondsWidth) {
3288  setValue(Level::Global,
3289  base::MillisecondsWidth(static_cast<int>(getULong(conf->value()))), &m_millisecondsWidthMap);
3290  } else if (conf->configurationType() == ConfigurationType::PerformanceTracking) {
3291  setValue(Level::Global, getBool(conf->value()), &m_performanceTrackingMap);
3292  } else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) {
3293  setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())), &m_maxLogFileSizeMap);
3294 #if !defined(ELPP_NO_DEFAULT_LOG_FILE)
3295  withFileSizeLimit.push_back(conf);
3296 #endif // !defined(ELPP_NO_DEFAULT_LOG_FILE)
3297  } else if (conf->configurationType() == ConfigurationType::LogFlushThreshold) {
3298  setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())), &m_logFlushThresholdMap);
3299  }
3300  }
3301  // As mentioned early, we will now set filename configuration in separate loop to deal with non-existent files
3302  for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) {
3303  Configuration* conf = *it;
3304  if (conf->configurationType() == ConfigurationType::Filename) {
3305  insertFile(conf->level(), conf->value());
3306  }
3307  }
3308  for (std::vector<Configuration*>::iterator conf = withFileSizeLimit.begin();
3309  conf != withFileSizeLimit.end(); ++conf) {
3310  // This is not unsafe as mutex is locked in currect scope
3311  unsafeValidateFileRolling((*conf)->level(), base::defaultPreRollOutCallback);
3312  }
3313  }
3314 
3315  unsigned long getULong(std::string confVal)
3316  {
3317  bool valid = true;
3318  base::utils::Str::trim(confVal);
3319  valid = !confVal.empty() && std::find_if(confVal.begin(), confVal.end(),
3320  [](char c) { return !base::utils::Str::isDigit(c); }) == confVal.end();
3321  if (!valid) {
3322  valid = false;
3323  ELPP_ASSERT(valid, "Configuration value not a valid integer [" << confVal << "]");
3324  return 0;
3325  }
3326  return atol(confVal.c_str());
3327  }
3328 
3329  std::string resolveFilename(const std::string& filename)
3330  {
3331  std::string resultingFilename = filename;
3332  std::size_t dateIndex = std::string::npos;
3333  std::string dateTimeFormatSpecifierStr = std::string(base::consts::kDateTimeFormatSpecifierForFilename);
3334  if ((dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str())) != std::string::npos) {
3335  while (dateIndex > 0 && resultingFilename[dateIndex - 1] == base::consts::kFormatSpecifierChar) {
3336  dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str(), dateIndex + 1);
3337  }
3338  if (dateIndex != std::string::npos) {
3339  const char* ptr = resultingFilename.c_str() + dateIndex;
3340  // Goto end of specifier
3341  ptr += dateTimeFormatSpecifierStr.size();
3342  std::string fmt;
3343  if ((resultingFilename.size() > dateIndex) && (ptr[0] == '{')) {
3344  // User has provided format for date/time
3345  ++ptr;
3346  int count = 1; // Start by 1 in order to remove starting brace
3347  std::stringstream ss;
3348  for (; *ptr; ++ptr, ++count) {
3349  if (*ptr == '}') {
3350  ++count; // In order to remove ending brace
3351  break;
3352  }
3353  ss << *ptr;
3354  }
3355  resultingFilename.erase(dateIndex + dateTimeFormatSpecifierStr.size(), count);
3356  fmt = ss.str();
3357  } else {
3358  fmt = std::string(base::consts::kDefaultDateTimeFormatInFilename);
3359  }
3360  base::MillisecondsWidth msWidth(3);
3361  std::string now = base::utils::DateTime::getDateTime(fmt.c_str(), &msWidth);
3362  base::utils::Str::replaceAll(now, '/', '-'); // Replace path element since we are dealing with filename
3363  base::utils::Str::replaceAll(resultingFilename, dateTimeFormatSpecifierStr, now);
3364  }
3365  }
3366  return resultingFilename;
3367  }
3368 
3369  void insertFile(Level level, const std::string& fullFilename)
3370  {
3371  std::string resolvedFilename = resolveFilename(fullFilename);
3372  if (resolvedFilename.empty()) {
3373  std::cerr << "Could not load empty file for logging, please re-check your configurations for level ["
3374  << LevelHelper::convertToString(level) << "]";
3375  }
3376  std::string filePath = base::utils::File::extractPathFromFilename(resolvedFilename, base::consts::kFilePathSeperator);
3377  if (filePath.size() < resolvedFilename.size()) {
3378  base::utils::File::createPath(filePath);
3379  }
3380  auto create = [&](Level level) {
3381  base::LogStreamsReferenceMap::iterator filestreamIter = m_logStreamsReference->find(resolvedFilename);
3382  base::type::fstream_t* fs = nullptr;
3383  if (filestreamIter == m_logStreamsReference->end()) {
3384  // We need a completely new stream, nothing to share with
3385  fs = base::utils::File::newFileStream(resolvedFilename);
3386  m_filenameMap.insert(std::make_pair(level, resolvedFilename));
3387  m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(fs)));
3388  m_logStreamsReference->insert(std::make_pair(resolvedFilename, base::FileStreamPtr(m_fileStreamMap.at(level))));
3389  } else {
3390  // Woops! we have an existing one, share it!
3391  m_filenameMap.insert(std::make_pair(level, filestreamIter->first));
3392  m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(filestreamIter->second)));
3393  fs = filestreamIter->second.get();
3394  }
3395  if (fs == nullptr) {
3396  // We display bad file error from newFileStream()
3397  ELPP_INTERNAL_ERROR("Setting [TO_FILE] of ["
3398  << LevelHelper::convertToString(level) << "] to FALSE", false);
3399  setValue(level, false, &m_toFileMap);
3400  }
3401  };
3402  // If we dont have file conf for any level, create it for Level::Global first
3403  // otherwise create for specified level
3404  create(m_filenameMap.empty() && m_fileStreamMap.empty() ? Level::Global : level);
3405  }
3406 
3407  bool unsafeValidateFileRolling(Level level, const PreRollOutCallback& PreRollOutCallback)
3408  {
3409  base::type::fstream_t* fs = unsafeGetConfigByRef(level, &m_fileStreamMap, "fileStream").get();
3410  if (fs == nullptr) {
3411  return true;
3412  }
3413  std::size_t maxLogFileSize = unsafeGetConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize");
3414  std::size_t currFileSize = base::utils::File::getSizeOfFile(fs);
3415  if (maxLogFileSize != 0 && currFileSize >= maxLogFileSize) {
3416  std::string fname = unsafeGetConfigByRef(level, &m_filenameMap, "filename");
3417  ELPP_INTERNAL_INFO(1, "Truncating log file [" << fname << "] as a result of configurations for level ["
3418  << LevelHelper::convertToString(level) << "]");
3419  fs->close();
3420  PreRollOutCallback(fname.c_str(), currFileSize);
3421  fs->open(fname, std::fstream::out | std::fstream::trunc);
3422  return true;
3423  }
3424  return false;
3425  }
3426 
3427  bool validateFileRolling(Level level, const PreRollOutCallback& PreRollOutCallback)
3428  {
3429  base::threading::ScopedLock scopedLock(lock());
3430  return unsafeValidateFileRolling(level, PreRollOutCallback);
3431  }
3432 };
3434 class HitCounter
3435 {
3436 public:
3437  HitCounter(void) :
3438  m_filename(""),
3439  m_lineNumber(0),
3440  m_hitCounts(0)
3441  {
3442  }
3443 
3444  HitCounter(const char* filename, unsigned long int lineNumber) :
3445  m_filename(filename),
3446  m_lineNumber(lineNumber),
3447  m_hitCounts(0)
3448  {
3449  }
3450 
3451  HitCounter(const HitCounter& hitCounter) :
3452  m_filename(hitCounter.m_filename),
3453  m_lineNumber(hitCounter.m_lineNumber),
3454  m_hitCounts(hitCounter.m_hitCounts)
3455  {
3456  }
3457 
3458  HitCounter& operator=(const HitCounter& hitCounter)
3459  {
3460  m_filename = hitCounter.m_filename;
3461  m_lineNumber = hitCounter.m_lineNumber;
3462  m_hitCounts = hitCounter.m_hitCounts;
3463  return *this;
3464  }
3465 
3466  virtual ~HitCounter(void)
3467  {
3468  }
3469 
3471  inline void resetLocation(const char* filename, unsigned long int lineNumber)
3472  {
3473  m_filename = filename;
3474  m_lineNumber = lineNumber;
3475  }
3476 
3478  inline void validateHitCounts(std::size_t n)
3479  {
3480  if (m_hitCounts >= base::consts::kMaxLogPerCounter) {
3481  m_hitCounts = (n >= 1 ? base::consts::kMaxLogPerCounter % n : 0);
3482  }
3483  ++m_hitCounts;
3484  }
3485 
3486  inline const char* filename(void) const
3487  {
3488  return m_filename;
3489  }
3490 
3491  inline unsigned long int lineNumber(void) const
3492  {
3493  return m_lineNumber;
3494  }
3495 
3496  inline std::size_t hitCounts(void) const
3497  {
3498  return m_hitCounts;
3499  }
3500 
3501  inline void increment(void)
3502  {
3503  ++m_hitCounts;
3504  }
3505 
3506  class Predicate
3507  {
3508  public:
3509  Predicate(const char* filename, unsigned long int lineNumber)
3510  : m_filename(filename),
3511  m_lineNumber(lineNumber)
3512  {
3513  }
3514  inline bool operator()(const HitCounter* counter)
3515  {
3516  return ((counter != nullptr) &&
3517  (strcmp(counter->m_filename, m_filename) == 0) &&
3518  (counter->m_lineNumber == m_lineNumber));
3519  }
3520 
3521  private:
3522  const char* m_filename;
3523  unsigned long int m_lineNumber;
3524  };
3525 
3526 private:
3527  const char* m_filename;
3528  unsigned long int m_lineNumber;
3529  std::size_t m_hitCounts;
3530 };
3532 class RegisteredHitCounters : public base::utils::RegistryWithPred<base::HitCounter, base::HitCounter::Predicate>
3533 {
3534 public:
3537  bool validateEveryN(const char* filename, unsigned long int lineNumber, std::size_t n)
3538  {
3539  base::threading::ScopedLock scopedLock(lock());
3540  base::HitCounter* counter = get(filename, lineNumber);
3541  if (counter == nullptr) {
3542  registerNew(counter = new base::HitCounter(filename, lineNumber));
3543  }
3544  counter->validateHitCounts(n);
3545  bool result = (n >= 1 && counter->hitCounts() != 0 && counter->hitCounts() % n == 0);
3546  return result;
3547  }
3548 
3551  bool validateAfterN(const char* filename, unsigned long int lineNumber, std::size_t n)
3552  {
3553  base::threading::ScopedLock scopedLock(lock());
3554  base::HitCounter* counter = get(filename, lineNumber);
3555  if (counter == nullptr) {
3556  registerNew(counter = new base::HitCounter(filename, lineNumber));
3557  }
3558  // Do not use validateHitCounts here since we do not want to reset counter here
3559  // Note the >= instead of > because we are incrementing
3560  // after this check
3561  if (counter->hitCounts() >= n)
3562  return true;
3563  counter->increment();
3564  return false;
3565  }
3566 
3569  bool validateNTimes(const char* filename, unsigned long int lineNumber, std::size_t n)
3570  {
3571  base::threading::ScopedLock scopedLock(lock());
3572  base::HitCounter* counter = get(filename, lineNumber);
3573  if (counter == nullptr) {
3574  registerNew(counter = new base::HitCounter(filename, lineNumber));
3575  }
3576  counter->increment();
3577  // Do not use validateHitCounts here since we do not want to reset counter here
3578  if (counter->hitCounts() <= n)
3579  return true;
3580  return false;
3581  }
3582 
3584  inline const base::HitCounter* getCounter(const char* filename, unsigned long int lineNumber)
3585  {
3586  base::threading::ScopedLock scopedLock(lock());
3587  return get(filename, lineNumber);
3588  }
3589 };
3591 enum class DispatchAction : base::type::EnumType {
3592  None = 1, NormalLog = 2, SysLog = 4
3593 };
3594 } // namespace base
3595 template <typename T>
3596 class Callback : protected base::threading::ThreadSafe
3597 {
3598 public:
3599  Callback(void) : m_enabled(true) {}
3600  inline bool enabled(void) const { return m_enabled; }
3601  inline void setEnabled(bool enabled)
3602  {
3603  base::threading::ScopedLock scopedLock(lock());
3604  m_enabled = enabled;
3605  }
3606 protected:
3607  virtual void handle(const T* handlePtr) = 0;
3608 private:
3609  bool m_enabled;
3610 };
3611 class LogDispatchData
3612 {
3613 public:
3614  LogDispatchData() : m_logMessage(nullptr), m_dispatchAction(base::DispatchAction::None) {}
3615  inline const LogMessage* logMessage(void) const { return m_logMessage; }
3616  inline base::DispatchAction dispatchAction(void) const { return m_dispatchAction; }
3617 private:
3618  LogMessage* m_logMessage;
3619  base::DispatchAction m_dispatchAction;
3620  friend class base::LogDispatcher;
3621 
3622  inline void setLogMessage(LogMessage* logMessage) { m_logMessage = logMessage; }
3623  inline void setDispatchAction(base::DispatchAction dispatchAction) { m_dispatchAction = dispatchAction; }
3624 };
3625 class LogDispatchCallback : public Callback<LogDispatchData>
3626 {
3627 private:
3628  friend class base::LogDispatcher;
3629 };
3630 class PerformanceTrackingCallback : public Callback<PerformanceTrackingData>
3631 {
3632 private:
3633  friend class base::PerformanceTracker;
3634 };
3635 class LogBuilder : base::NoCopy
3636 {
3637 public:
3638  virtual ~LogBuilder(void) { ELPP_INTERNAL_INFO(3, "Destroying log builder...")}
3639  virtual base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const = 0;
3640  void convertToColoredOutput(base::type::string_t* logLine, Level level)
3641  {
3642  if (!base::utils::s_termSupportsColor) return;
3643  const base::type::char_t* resetColor = ELPP_LITERAL("\x1b[0m");
3644  if (level == Level::Error || level == Level::Fatal)
3645  *logLine = ELPP_LITERAL("\x1b[31m") + *logLine + resetColor;
3646  else if (level == Level::Warning)
3647  *logLine = ELPP_LITERAL("\x1b[33m") + *logLine + resetColor;
3648  }
3649 private:
3650  friend class el::base::DefaultLogDispatchCallback;
3651 };
3652 typedef std::shared_ptr<LogBuilder> LogBuilderPtr;
3656 class Logger : public base::threading::ThreadSafe, public Loggable
3657 {
3658 public:
3659  Logger(const std::string& id, base::LogStreamsReferenceMap* logStreamsReference) :
3660  m_id(id),
3661  m_typedConfigurations(nullptr),
3662  m_parentApplicationName(std::string()),
3663  m_isConfigured(false),
3664  m_logStreamsReference(logStreamsReference)
3665  {
3666  initUnflushedCount();
3667  }
3668 
3669  Logger(const std::string& id, const Configurations& configurations, base::LogStreamsReferenceMap* logStreamsReference) :
3670  m_id(id),
3671  m_typedConfigurations(nullptr),
3672  m_parentApplicationName(std::string()),
3673  m_isConfigured(false),
3674  m_logStreamsReference(logStreamsReference)
3675  {
3676  initUnflushedCount();
3677  configure(configurations);
3678  }
3679 
3680  Logger(const Logger& logger)
3681  {
3682  base::utils::safeDelete(m_typedConfigurations);
3683  m_id = logger.m_id;
3684  m_typedConfigurations = logger.m_typedConfigurations;
3685  m_parentApplicationName = logger.m_parentApplicationName;
3686  m_isConfigured = logger.m_isConfigured;
3687  m_configurations = logger.m_configurations;
3688  m_unflushedCount = logger.m_unflushedCount;
3689  m_logStreamsReference = logger.m_logStreamsReference;
3690  }
3691 
3692  Logger& operator=(const Logger& logger)
3693  {
3694  base::utils::safeDelete(m_typedConfigurations);
3695  m_id = logger.m_id;
3696  m_typedConfigurations = logger.m_typedConfigurations;
3697  m_parentApplicationName = logger.m_parentApplicationName;
3698  m_isConfigured = logger.m_isConfigured;
3699  m_configurations = logger.m_configurations;
3700  m_unflushedCount = logger.m_unflushedCount;
3701  m_logStreamsReference = logger.m_logStreamsReference;
3702  return *this;
3703  }
3704 
3705  virtual ~Logger(void)
3706  {
3707  base::utils::safeDelete(m_typedConfigurations);
3708  }
3709 
3710  virtual inline void log(el::base::type::ostream_t& os) const
3711  {
3712  os << m_id.c_str();
3713  }
3714 
3716  void configure(const Configurations& configurations)
3717  {
3718  m_isConfigured = false; // we set it to false in case if we fail
3719  initUnflushedCount();
3720  if (m_typedConfigurations != nullptr) {
3721  Configurations* c = const_cast<Configurations*>(m_typedConfigurations->configurations());
3722  if (c->hasConfiguration(Level::Global, ConfigurationType::Filename)) {
3723  // This check is definitely needed for cases like ELPP_NO_DEFAULT_LOG_FILE
3724  flush();
3725  }
3726  }
3727  base::threading::ScopedLock scopedLock(lock());
3728  if (m_configurations != configurations) {
3729  m_configurations.setFromBase(const_cast<Configurations*>(&configurations));
3730  }
3731  base::utils::safeDelete(m_typedConfigurations);
3732  m_typedConfigurations = new base::TypedConfigurations(&m_configurations, m_logStreamsReference);
3733  resolveLoggerFormatSpec();
3734  m_isConfigured = true;
3735  }
3736 
3738  inline void reconfigure(void)
3739  {
3740  ELPP_INTERNAL_INFO(1, "Reconfiguring logger [" << m_id << "]");
3741  configure(m_configurations);
3742  }
3743 
3744  inline const std::string& id(void) const
3745  {
3746  return m_id;
3747  }
3748 
3749  inline const std::string& parentApplicationName(void) const
3750  {
3751  return m_parentApplicationName;
3752  }
3753 
3754  inline void setParentApplicationName(const std::string& parentApplicationName)
3755  {
3756  m_parentApplicationName = parentApplicationName;
3757  }
3758 
3759  inline Configurations* configurations(void)
3760  {
3761  return &m_configurations;
3762  }
3763 
3764  inline base::TypedConfigurations* typedConfigurations(void)
3765  {
3766  return m_typedConfigurations;
3767  }
3768 
3769  static inline bool isValidId(const std::string& id)
3770  {
3771  for (std::string::const_iterator it = id.begin(); it != id.end(); ++it) {
3772  if (!base::utils::Str::contains(base::consts::kValidLoggerIdSymbols, *it)) {
3773  return false;
3774  }
3775  }
3776  return true;
3777  }
3779  inline void flush(void)
3780  {
3781  ELPP_INTERNAL_INFO(3, "Flushing logger [" << m_id << "] all levels");
3782  base::threading::ScopedLock scopedLock(lock());
3783  base::type::EnumType lIndex = LevelHelper::kMinValid;
3784  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
3785  flush(LevelHelper::castFromInt(lIndex), nullptr);
3786  return false;
3787  });
3788  }
3789 
3790  inline void flush(Level level, base::type::fstream_t* fs)
3791  {
3792  if (fs == nullptr && m_typedConfigurations->toFile(level)) {
3793  fs = m_typedConfigurations->fileStream(level);
3794  }
3795  if (fs != nullptr) {
3796  fs->flush();
3797  m_unflushedCount.find(level)->second = 0;
3798  }
3799  }
3800 
3801  inline bool isFlushNeeded(Level level)
3802  {
3803  return ++m_unflushedCount.find(level)->second >= m_typedConfigurations->logFlushThreshold(level);
3804  }
3805 
3806  inline LogBuilder* logBuilder(void) const
3807  {
3808  return m_logBuilder.get();
3809  }
3810 
3811  inline void setLogBuilder(const LogBuilderPtr& logBuilder)
3812  {
3813  m_logBuilder = logBuilder;
3814  }
3815 
3816  inline bool enabled(Level level) const
3817  {
3818  return m_typedConfigurations->enabled(level);
3819  }
3820 
3821 #if ELPP_VARIADIC_TEMPLATES_SUPPORTED
3822 # define LOGGER_LEVEL_WRITERS_SIGNATURES(FUNCTION_NAME)\
3823  template <typename T, typename... Args>\
3824  inline void FUNCTION_NAME(const char*, const T&, const Args&...);\
3825  template <typename T>\
3826  inline void FUNCTION_NAME(const T&);
3827 
3828  template <typename T, typename... Args>
3829  inline void verbose(int, const char*, const T&, const Args& ...);
3830 
3831  template <typename T>
3832  inline void verbose(int, const T&);
3833 
3834  LOGGER_LEVEL_WRITERS_SIGNATURES(info)
3835  LOGGER_LEVEL_WRITERS_SIGNATURES(debug)
3836  LOGGER_LEVEL_WRITERS_SIGNATURES(warn)
3837  LOGGER_LEVEL_WRITERS_SIGNATURES(error)
3838  LOGGER_LEVEL_WRITERS_SIGNATURES(fatal)
3839  LOGGER_LEVEL_WRITERS_SIGNATURES(trace)
3840 # undef LOGGER_LEVEL_WRITERS_SIGNATURES
3841 #endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
3842 private:
3843  std::string m_id;
3844  base::TypedConfigurations* m_typedConfigurations;
3845  base::type::stringstream_t m_stream;
3846  std::string m_parentApplicationName;
3847  bool m_isConfigured;
3848  Configurations m_configurations;
3849  std::map<Level, unsigned int> m_unflushedCount;
3850  base::LogStreamsReferenceMap* m_logStreamsReference;
3851  LogBuilderPtr m_logBuilder;
3852 
3853  friend class el::LogMessage;
3854  friend class el::Loggers;
3855  friend class el::Helpers;
3856  friend class el::base::RegisteredLoggers;
3857  friend class el::base::DefaultLogDispatchCallback;
3858  friend class el::base::MessageBuilder;
3859  friend class el::base::Writer;
3860  friend class el::base::PErrorWriter;
3861  friend class el::base::Storage;
3862  friend class el::base::PerformanceTracker;
3863  friend class el::base::LogDispatcher;
3864 
3865  Logger(void);
3866 
3867 #if ELPP_VARIADIC_TEMPLATES_SUPPORTED
3868  template <typename T, typename... Args>
3869  void log_(Level, int, const char*, const T&, const Args& ...);
3870 
3871  template <typename T>
3872  inline void log_(Level, int, const T&);
3873 
3874  template <typename T, typename... Args>
3875  void log(Level, const char*, const T&, const Args& ...);
3876 
3877  template <typename T>
3878  inline void log(Level, const T&);
3879 #endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
3880 
3881  void initUnflushedCount(void)
3882  {
3883  m_unflushedCount.clear();
3884  base::type::EnumType lIndex = LevelHelper::kMinValid;
3885  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
3886  m_unflushedCount.insert(std::make_pair(LevelHelper::castFromInt(lIndex), 0));
3887  return false;
3888  });
3889  }
3890 
3891  inline base::type::stringstream_t& stream(void)
3892  {
3893  return m_stream;
3894  }
3895 
3896  void resolveLoggerFormatSpec(void) const
3897  {
3898  base::type::EnumType lIndex = LevelHelper::kMinValid;
3899  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
3900  base::LogFormat* logFormat =
3901  const_cast<base::LogFormat*>(&m_typedConfigurations->logFormat(LevelHelper::castFromInt(lIndex)));
3902  base::utils::Str::replaceFirstWithEscape(logFormat->m_format, base::consts::kLoggerIdFormatSpecifier, m_id);
3903  return false;
3904  });
3905  }
3906 };
3907 namespace base {
3909 class RegisteredLoggers : public base::utils::Registry<Logger, std::string>
3910 {
3911 public:
3912  explicit RegisteredLoggers(const LogBuilderPtr& defaultLogBuilder) :
3913  m_defaultLogBuilder(defaultLogBuilder)
3914  {
3915  m_defaultConfigurations.setToDefault();
3916  }
3917 
3918  virtual ~RegisteredLoggers(void)
3919  {
3920  flushAll();
3921  }
3922 
3923  inline void setDefaultConfigurations(const Configurations& configurations)
3924  {
3925  base::threading::ScopedLock scopedLock(lock());
3926  m_defaultConfigurations.setFromBase(const_cast<Configurations*>(&configurations));
3927  }
3928 
3929  inline Configurations* defaultConfigurations(void)
3930  {
3931  return &m_defaultConfigurations;
3932  }
3933 
3934  Logger* get(const std::string& id, bool forceCreation = true)
3935  {
3936  base::threading::ScopedLock scopedLock(lock());
3937  Logger* logger_ = base::utils::Registry<Logger, std::string>::get(id);
3938  if (logger_ == nullptr && forceCreation) {
3939  bool validId = Logger::isValidId(id);
3940  if (!validId) {
3941  ELPP_ASSERT(validId, "Invalid logger ID [" << id << "]. Not registering this logger.");
3942  return nullptr;
3943  }
3944  logger_ = new Logger(id, m_defaultConfigurations, &m_logStreamsReference);
3945  logger_->m_logBuilder = m_defaultLogBuilder;
3946  registerNew(id, logger_);
3947  }
3948  return logger_;
3949  }
3950 
3951  bool remove(const std::string& id)
3952  {
3953  if (id == "default") {
3954  return false;
3955  }
3956  Logger* logger = base::utils::Registry<Logger, std::string>::get(id);
3957  if (logger != nullptr) {
3958  unregister(logger);
3959  }
3960  return true;
3961  }
3962 
3963  inline bool has(const std::string& id)
3964  {
3965  return get(id, false) != nullptr;
3966  }
3967 
3968  inline void unregister(Logger*& logger)
3969  {
3970  base::threading::ScopedLock scopedLock(lock());
3971  base::utils::Registry<Logger, std::string>::unregister(logger->id());
3972  }
3973 
3974  inline base::LogStreamsReferenceMap* logStreamsReference(void)
3975  {
3976  return &m_logStreamsReference;
3977  }
3978 
3979  inline void flushAll(void)
3980  {
3981  ELPP_INTERNAL_INFO(1, "Flushing all log files");
3982  base::threading::ScopedLock scopedLock(lock());
3983  for (base::LogStreamsReferenceMap::iterator it = m_logStreamsReference.begin();
3984  it != m_logStreamsReference.end(); ++it) {
3985  if (it->second.get() == nullptr) continue;
3986  it->second->flush();
3987  }
3988  }
3989 
3990 private:
3991  LogBuilderPtr m_defaultLogBuilder;
3992  Configurations m_defaultConfigurations;
3993  base::LogStreamsReferenceMap m_logStreamsReference;
3994  friend class el::base::Storage;
3995 };
3997 class VRegistry : base::NoCopy, public base::threading::ThreadSafe
3998 {
3999 public:
4000  explicit VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags) : m_level(level), m_pFlags(pFlags)
4001  {
4002  }
4003 
4005  inline void setLevel(base::type::VerboseLevel level)
4006  {
4007  base::threading::ScopedLock scopedLock(lock());
4008  if (level < 0)
4009  m_level = 0;
4010  else if (level > 9)
4011  m_level = base::consts::kMaxVerboseLevel;
4012  else
4013  m_level = level;
4014  }
4015 
4016  inline base::type::VerboseLevel level(void) const
4017  {
4018  return m_level;
4019  }
4020 
4021  inline void clearModules(void)
4022  {
4023  base::threading::ScopedLock scopedLock(lock());
4024  m_modules.clear();
4025  }
4026 
4027  void setModules(const char* modules)
4028  {
4029  base::threading::ScopedLock scopedLock(lock());
4030  auto addSuffix = [](std::stringstream & ss, const char* sfx, const char* prev) {
4031  if (prev != nullptr && base::utils::Str::endsWith(ss.str(), std::string(prev))) {
4032  std::string chr(ss.str().substr(0, ss.str().size() - strlen(prev)));
4033  ss.str(std::string(""));
4034  ss << chr;
4035  }
4036  if (base::utils::Str::endsWith(ss.str(), std::string(sfx))) {
4037  std::string chr(ss.str().substr(0, ss.str().size() - strlen(sfx)));
4038  ss.str(std::string(""));
4039  ss << chr;
4040  }
4041  ss << sfx;
4042  };
4043  auto insert = [&](std::stringstream & ss, base::type::VerboseLevel level) {
4044  if (!base::utils::hasFlag(LoggingFlag::DisableVModulesExtensions, *m_pFlags)) {
4045  addSuffix(ss, ".h", nullptr);
4046  m_modules.insert(std::make_pair(ss.str(), level));
4047  addSuffix(ss, ".c", ".h");
4048  m_modules.insert(std::make_pair(ss.str(), level));
4049  addSuffix(ss, ".cpp", ".c");
4050  m_modules.insert(std::make_pair(ss.str(), level));
4051  addSuffix(ss, ".cc", ".cpp");
4052  m_modules.insert(std::make_pair(ss.str(), level));
4053  addSuffix(ss, ".cxx", ".cc");
4054  m_modules.insert(std::make_pair(ss.str(), level));
4055  addSuffix(ss, ".-inl.h", ".cxx");
4056  m_modules.insert(std::make_pair(ss.str(), level));
4057  addSuffix(ss, ".hxx", ".-inl.h");
4058  m_modules.insert(std::make_pair(ss.str(), level));
4059  addSuffix(ss, ".hpp", ".hxx");
4060  m_modules.insert(std::make_pair(ss.str(), level));
4061  addSuffix(ss, ".hh", ".hpp");
4062  }
4063  m_modules.insert(std::make_pair(ss.str(), level));
4064  };
4065  bool isMod = true;
4066  bool isLevel = false;
4067  std::stringstream ss;
4068  int level = -1;
4069  for (; *modules; ++modules) {
4070  switch (*modules) {
4071  case '=':
4072  isLevel = true;
4073  isMod = false;
4074  break;
4075  case ',':
4076  isLevel = false;
4077  isMod = true;
4078  if (!ss.str().empty() && level != -1) {
4079  insert(ss, level);
4080  ss.str(std::string(""));
4081  level = -1;
4082  }
4083  break;
4084  default:
4085  if (isMod) {
4086  ss << *modules;
4087  } else if (isLevel) {
4088  if (isdigit(*modules)) {
4089  level = static_cast<base::type::VerboseLevel>(*modules) - 48;
4090  }
4091  }
4092  break;
4093  }
4094  }
4095  if (!ss.str().empty() && level != -1) {
4096  insert(ss, level);
4097  }
4098  }
4099 
4100  bool allowed(base::type::VerboseLevel vlevel, const char* file)
4101  {
4102  base::threading::ScopedLock scopedLock(lock());
4103  if (m_modules.empty() || file == nullptr) {
4104  return vlevel <= m_level;
4105  } else {
4106  std::map<std::string, base::type::VerboseLevel>::iterator it = m_modules.begin();
4107  for (; it != m_modules.end(); ++it) {
4108  if (base::utils::Str::wildCardMatch(file, it->first.c_str())) {
4109  return vlevel <= it->second;
4110  }
4111  }
4112  if (base::utils::hasFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified, *m_pFlags)) {
4113  return true;
4114  }
4115  return false;
4116  }
4117  }
4118 
4119  inline const std::map<std::string, base::type::VerboseLevel>& modules(void) const
4120  {
4121  return m_modules;
4122  }
4123 
4124  void setFromArgs(const base::utils::CommandLineArgs* commandLineArgs)
4125  {
4126  if (commandLineArgs->hasParam("-v") || commandLineArgs->hasParam("--verbose") ||
4127  commandLineArgs->hasParam("-V") || commandLineArgs->hasParam("--VERBOSE")) {
4128  setLevel(base::consts::kMaxVerboseLevel);
4129  } else if (commandLineArgs->hasParamWithValue("--v")) {
4130  setLevel(atoi(commandLineArgs->getParamValue("--v")));
4131  } else if (commandLineArgs->hasParamWithValue("--V")) {
4132  setLevel(atoi(commandLineArgs->getParamValue("--V")));
4133  } else if ((commandLineArgs->hasParamWithValue("-vmodule")) && vModulesEnabled()) {
4134  setModules(commandLineArgs->getParamValue("-vmodule"));
4135  } else if (commandLineArgs->hasParamWithValue("-VMODULE") && vModulesEnabled()) {
4136  setModules(commandLineArgs->getParamValue("-VMODULE"));
4137  }
4138  }
4139 
4141  inline bool vModulesEnabled(void)
4142  {
4143  return !base::utils::hasFlag(LoggingFlag::DisableVModules, *m_pFlags);
4144  }
4145 
4146 private:
4147  base::type::VerboseLevel m_level;
4148  base::type::EnumType* m_pFlags;
4149  std::map<std::string, base::type::VerboseLevel> m_modules;
4150 };
4151 } // namespace base
4152 class LogMessage
4153 {
4154 public:
4155  LogMessage(Level level, const std::string& file, unsigned long int line, const std::string& func,
4156  base::type::VerboseLevel verboseLevel, Logger* logger) :
4157  m_level(level), m_file(file), m_line(line), m_func(func),
4158  m_verboseLevel(verboseLevel), m_logger(logger), m_message(logger->stream().str())
4159  {
4160  }
4161  inline Level level(void) const { return m_level; }
4162  inline const std::string& file(void) const { return m_file; }
4163  inline unsigned long int line(void) const { return m_line; } // NOLINT
4164  inline const std::string& func(void) const { return m_func; }
4165  inline base::type::VerboseLevel verboseLevel(void) const { return m_verboseLevel; }
4166  inline Logger* logger(void) const { return m_logger; }
4167  inline const base::type::string_t& message(void) const { return m_message; }
4168 private:
4169  Level m_level;
4170  std::string m_file;
4171  unsigned long int m_line;
4172  std::string m_func;
4173  base::type::VerboseLevel m_verboseLevel;
4174  Logger* m_logger;
4175  base::type::string_t m_message;
4176 };
4177 namespace base {
4178 #if ELPP_ASYNC_LOGGING
4179 class AsyncLogItem
4180 {
4181 public:
4182  explicit AsyncLogItem(const LogMessage& logMessage, const LogDispatchData& data, const base::type::string_t& logLine)
4183  : m_logMessage(logMessage), m_dispatchData(data), m_logLine(logLine) {}
4184  virtual ~AsyncLogItem() {}
4185  inline LogMessage* logMessage(void) { return &m_logMessage; }
4186  inline LogDispatchData* data(void) { return &m_dispatchData; }
4187  inline base::type::string_t logLine(void) { return m_logLine; }
4188 private:
4189  LogMessage m_logMessage;
4190  LogDispatchData m_dispatchData;
4191  base::type::string_t m_logLine;
4192 };
4193 class AsyncLogQueue : public base::threading::ThreadSafe
4194 {
4195 public:
4196  virtual ~AsyncLogQueue()
4197  {
4198  ELPP_INTERNAL_INFO(6, "~AsyncLogQueue");
4199  }
4200 
4201  inline AsyncLogItem next(void)
4202  {
4203  base::threading::ScopedLock scopedLock(lock());
4204  AsyncLogItem result = m_queue.front();
4205  m_queue.pop();
4206  return result;
4207  }
4208 
4209  inline void push(const AsyncLogItem& item)
4210  {
4211  base::threading::ScopedLock scopedLock(lock());
4212  m_queue.push(item);
4213  }
4214  inline void pop(void)
4215  {
4216  base::threading::ScopedLock scopedLock(lock());
4217  m_queue.pop();
4218  }
4219  inline AsyncLogItem front(void)
4220  {
4221  base::threading::ScopedLock scopedLock(lock());
4222  return m_queue.front();
4223  }
4224  inline bool empty(void)
4225  {
4226  base::threading::ScopedLock scopedLock(lock());
4227  return m_queue.empty();
4228  }
4229 private:
4230  std::queue<AsyncLogItem> m_queue;
4231 };
4232 class IWorker
4233 {
4234 public:
4235  virtual ~IWorker() {}
4236  virtual void start() = 0;
4237 };
4238 #endif // ELPP_ASYNC_LOGGING
4239 class Storage : base::NoCopy, public base::threading::ThreadSafe
4241 {
4242 public:
4243 #if ELPP_ASYNC_LOGGING
4244  Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker) :
4245 #else
4246  explicit Storage(const LogBuilderPtr & defaultLogBuilder) :
4247 #endif // ELPP_ASYNC_LOGGING
4248  m_registeredHitCounters(new base::RegisteredHitCounters()),
4249  m_registeredLoggers(new base::RegisteredLoggers(defaultLogBuilder)),
4250  m_flags(0x0),
4251  m_vRegistry(new base::VRegistry(0, &m_flags)),
4252 #if ELPP_ASYNC_LOGGING
4253  m_asyncLogQueue(new base::AsyncLogQueue()),
4254  m_asyncDispatchWorker(asyncDispatchWorker),
4255 #endif // ELPP_ASYNC_LOGGING
4256  m_preRollOutCallback(base::defaultPreRollOutCallback)
4257  {
4258  // Register default logger
4259  m_registeredLoggers->get(std::string(base::consts::kDefaultLoggerId));
4260  // Register performance logger and reconfigure format
4261  Logger* performanceLogger = m_registeredLoggers->get(std::string(base::consts::kPerformanceLoggerId));
4262  performanceLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%datetime %level %msg"));
4263  performanceLogger->reconfigure();
4264 #if defined(ELPP_SYSLOG)
4265  // Register syslog logger and reconfigure format
4266  Logger* sysLogLogger = m_registeredLoggers->get(std::string(base::consts::kSysLogLoggerId));
4267  sysLogLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%level: %msg"));
4268  sysLogLogger->reconfigure();
4269 #else
4270  ELPP_UNUSED(base::consts::kSysLogLoggerId);
4271 #endif // defined(ELPP_SYSLOG)
4272  addFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified);
4273 #if ELPP_ASYNC_LOGGING
4274  installLogDispatchCallback<base::AsyncLogDispatchCallback>(std::string("AsyncLogDispatchCallback"));
4275 #else
4276  installLogDispatchCallback<base::DefaultLogDispatchCallback>(std::string("DefaultLogDispatchCallback"));
4277 #endif // ELPP_ASYNC_LOGGING
4278  installPerformanceTrackingCallback<base::DefaultPerformanceTrackingCallback>(std::string("DefaultPerformanceTrackingCallback"));
4279  ELPP_INTERNAL_INFO(1, "Easylogging++ has been initialized");
4280 #if ELPP_ASYNC_LOGGING
4281  m_asyncDispatchWorker->start();
4282 #endif // ELPP_ASYNC_LOGGING
4283  }
4284 
4285  virtual ~Storage(void)
4286  {
4287  ELPP_INTERNAL_INFO(4, "Destroying storage");
4288 #if ELPP_ASYNC_LOGGING
4289  ELPP_INTERNAL_INFO(5, "Replacing log dispatch callback to synchronous");
4290  uninstallLogDispatchCallback<base::AsyncLogDispatchCallback>(std::string("AsyncLogDispatchCallback"));
4291  installLogDispatchCallback<base::DefaultLogDispatchCallback>(std::string("DefaultLogDispatchCallback"));
4292  ELPP_INTERNAL_INFO(5, "Destroying asyncDispatchWorker");
4293  base::utils::safeDelete(m_asyncDispatchWorker);
4294  ELPP_INTERNAL_INFO(5, "Destroying asyncLogQueue");
4295  base::utils::safeDelete(m_asyncLogQueue);
4296 #endif // ELPP_ASYNC_LOGGING
4297  ELPP_INTERNAL_INFO(5, "Destroying registeredHitCounters");
4298  base::utils::safeDelete(m_registeredHitCounters);
4299  ELPP_INTERNAL_INFO(5, "Destroying registeredLoggers");
4300  base::utils::safeDelete(m_registeredLoggers);
4301  ELPP_INTERNAL_INFO(5, "Destroying vRegistry");
4302  base::utils::safeDelete(m_vRegistry);
4303  }
4304 
4305  inline bool validateEveryNCounter(const char* filename, unsigned long int lineNumber, std::size_t occasion)
4306  {
4307  return hitCounters()->validateEveryN(filename, lineNumber, occasion);
4308  }
4309 
4310  inline bool validateAfterNCounter(const char* filename, unsigned long int lineNumber, std::size_t n) // NOLINT
4311  {
4312  return hitCounters()->validateAfterN(filename, lineNumber, n);
4313  }
4314 
4315  inline bool validateNTimesCounter(const char* filename, unsigned long int lineNumber, std::size_t n) // NOLINT
4316  {
4317  return hitCounters()->validateNTimes(filename, lineNumber, n);
4318  }
4319 
4320  inline base::RegisteredHitCounters* hitCounters(void) const
4321  {
4322  return m_registeredHitCounters;
4323  }
4324 
4325  inline base::RegisteredLoggers* registeredLoggers(void) const
4326  {
4327  return m_registeredLoggers;
4328  }
4329 
4330  inline base::VRegistry* vRegistry(void) const
4331  {
4332  return m_vRegistry;
4333  }
4334 
4335 #if ELPP_ASYNC_LOGGING
4336  inline base::AsyncLogQueue* asyncLogQueue(void) const
4337  {
4338  return m_asyncLogQueue;
4339  }
4340 #endif // ELPP_ASYNC_LOGGING
4341 
4342  inline const base::utils::CommandLineArgs* commandLineArgs(void) const
4343  {
4344  return &m_commandLineArgs;
4345  }
4346 
4347  inline void addFlag(LoggingFlag flag)
4348  {
4349  base::utils::addFlag(flag, &m_flags);
4350  }
4351 
4352  inline void removeFlag(LoggingFlag flag)
4353  {
4354  base::utils::removeFlag(flag, &m_flags);
4355  }
4356 
4357  inline bool hasFlag(LoggingFlag flag) const
4358  {
4359  return base::utils::hasFlag(flag, m_flags);
4360  }
4361 
4362  inline base::type::EnumType flags(void) const
4363  {
4364  return m_flags;
4365  }
4366 
4367  inline void setFlags(base::type::EnumType flags)
4368  {
4369  m_flags = flags;
4370  }
4371 
4372  inline void setPreRollOutCallback(const PreRollOutCallback& callback)
4373  {
4374  m_preRollOutCallback = callback;
4375  }
4376 
4377  inline void unsetPreRollOutCallback(void)
4378  {
4379  m_preRollOutCallback = base::defaultPreRollOutCallback;
4380  }
4381 
4382  inline PreRollOutCallback& preRollOutCallback(void)
4383  {
4384  return m_preRollOutCallback;
4385  }
4386 
4387  inline bool hasCustomFormatSpecifier(const char* formatSpecifier)
4388  {
4389  base::threading::ScopedLock scopedLock(lock());
4390  return std::find(m_customFormatSpecifiers.begin(), m_customFormatSpecifiers.end(),
4391  formatSpecifier) != m_customFormatSpecifiers.end();
4392  }
4393 
4394  inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier)
4395  {
4396  if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) {
4397  return;
4398  }
4399  base::threading::ScopedLock scopedLock(lock());
4400  m_customFormatSpecifiers.push_back(customFormatSpecifier);
4401  }
4402 
4403  inline bool uninstallCustomFormatSpecifier(const char* formatSpecifier)
4404  {
4405  base::threading::ScopedLock scopedLock(lock());
4406  std::vector<CustomFormatSpecifier>::iterator it = std::find(m_customFormatSpecifiers.begin(),
4407  m_customFormatSpecifiers.end(), formatSpecifier);
4408  if (it != m_customFormatSpecifiers.end() && strcmp(formatSpecifier, it->formatSpecifier()) == 0) {
4409  m_customFormatSpecifiers.erase(it);
4410  return true;
4411  }
4412  return false;
4413  }
4414 
4415  const std::vector<CustomFormatSpecifier>* customFormatSpecifiers(void) const
4416  {
4417  return &m_customFormatSpecifiers;
4418  }
4419 
4420  inline void setLoggingLevel(Level level)
4421  {
4422  m_loggingLevel = level;
4423  }
4424 
4425  template <typename T>
4426  inline bool installLogDispatchCallback(const std::string& id)
4427  {
4428  return installCallback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
4429  }
4430 
4431  template <typename T>
4432  inline void uninstallLogDispatchCallback(const std::string& id)
4433  {
4434  uninstallCallback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
4435  }
4436  template <typename T>
4437  inline T* logDispatchCallback(const std::string& id)
4438  {
4439  return callback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
4440  }
4441 
4442  template <typename T>
4443  inline bool installPerformanceTrackingCallback(const std::string& id)
4444  {
4445  return installCallback<T, base::type::PerformanceTrackingCallbackPtr>(id, &m_performanceTrackingCallbacks);
4446  }
4447 
4448  template <typename T>
4449  inline void uninstallPerformanceTrackingCallback(const std::string& id)
4450  {
4451  uninstallCallback<T, base::type::PerformanceTrackingCallbackPtr>(id, &m_performanceTrackingCallbacks);
4452  }
4453 
4454  template <typename T>
4455  inline T* performanceTrackingCallback(const std::string& id)
4456  {
4457  return callback<T, base::type::PerformanceTrackingCallbackPtr>(id, &m_performanceTrackingCallbacks);
4458  }
4459 private:
4460  base::RegisteredHitCounters* m_registeredHitCounters;
4461  base::RegisteredLoggers* m_registeredLoggers;
4462  base::type::EnumType m_flags;
4463  base::VRegistry* m_vRegistry;
4464 #if ELPP_ASYNC_LOGGING
4465  base::AsyncLogQueue* m_asyncLogQueue;
4466  base::IWorker* m_asyncDispatchWorker;
4467 #endif // ELPP_ASYNC_LOGGING
4468  base::utils::CommandLineArgs m_commandLineArgs;
4469  PreRollOutCallback m_preRollOutCallback;
4470  std::map<std::string, base::type::LogDispatchCallbackPtr> m_logDispatchCallbacks;
4471  std::map<std::string, base::type::PerformanceTrackingCallbackPtr> m_performanceTrackingCallbacks;
4472  std::vector<CustomFormatSpecifier> m_customFormatSpecifiers;
4473  Level m_loggingLevel;
4474 
4475  friend class el::Helpers;
4476  friend class el::base::DefaultLogDispatchCallback;
4477  friend class el::LogBuilder;
4478  friend class el::base::MessageBuilder;
4479  friend class el::base::Writer;
4480  friend class el::base::PerformanceTracker;
4481  friend class el::base::LogDispatcher;
4482 
4483  void setApplicationArguments(int argc, char** argv)
4484  {
4485  m_commandLineArgs.setArgs(argc, argv);
4486  m_vRegistry->setFromArgs(commandLineArgs());
4487  // default log file
4488 #if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
4489  if (m_commandLineArgs.hasParamWithValue(base::consts::kDefaultLogFileParam)) {
4490  Configurations c;
4491  c.setGlobally(ConfigurationType::Filename, std::string(m_commandLineArgs.getParamValue(base::consts::kDefaultLogFileParam)));
4492  registeredLoggers()->setDefaultConfigurations(c);
4493  for (base::RegisteredLoggers::iterator it = registeredLoggers()->begin();
4494  it != registeredLoggers()->end(); ++it) {
4495  it->second->configure(c);
4496  }
4497  }
4498 #endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
4499 #if defined(ELPP_LOGGING_FLAGS_FROM_ARG)
4500  if (m_commandLineArgs.hasParamWithValue(base::consts::kLoggingFlagsParam)) {
4501  m_flags = atoi(m_commandLineArgs.getParamValue(base::consts::kLoggingFlagsParam));
4502  }
4503 #endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG)
4504  }
4505 
4506  inline void setApplicationArguments(int argc, const char** argv)
4507  {
4508  setApplicationArguments(argc, const_cast<char**>(argv));
4509  }
4510 
4511  template <typename T, typename TPtr>
4512  inline bool installCallback(const std::string& id, std::map<std::string, TPtr>* mapT)
4513  {
4514  if (mapT->find(id) == mapT->end()) {
4515  mapT->insert(std::make_pair(id, TPtr(new T())));
4516  return true;
4517  }
4518  return false;
4519  }
4520 
4521  template <typename T, typename TPtr>
4522  inline void uninstallCallback(const std::string& id, std::map<std::string, TPtr>* mapT)
4523  {
4524  if (mapT->find(id) != mapT->end()) {
4525  mapT->erase(id);
4526  }
4527  }
4528 
4529  template <typename T, typename TPtr>
4530  inline T* callback(const std::string& id, std::map<std::string, TPtr>* mapT)
4531  {
4532  typename std::map<std::string, TPtr>::iterator iter = mapT->find(id);
4533  if (iter != mapT->end()) {
4534  return static_cast<T*>(iter->second.get());
4535  }
4536  return nullptr;
4537  }
4538 };
4539 extern ELPP_EXPORT base::type::StoragePointer elStorage;
4540 #define ELPP el::base::elStorage
4541 class DefaultLogDispatchCallback : public LogDispatchCallback
4542 {
4543 protected:
4544  void handle(const LogDispatchData* data)
4545  {
4546  m_data = data;
4547  dispatch(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(),
4548  m_data->dispatchAction() == base::DispatchAction::NormalLog));
4549  }
4550 private:
4551  const LogDispatchData* m_data;
4552  void dispatch(base::type::string_t&& logLine)
4553  {
4554  if (m_data->dispatchAction() == base::DispatchAction::NormalLog) {
4555  if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) {
4556  base::type::fstream_t* fs = m_data->logMessage()->logger()->m_typedConfigurations->fileStream(m_data->logMessage()->level());
4557  if (fs != nullptr) {
4558  fs->write(logLine.c_str(), logLine.size());
4559  if (fs->fail()) {
4560  ELPP_INTERNAL_ERROR("Unable to write log to file ["
4561  << m_data->logMessage()->logger()->m_typedConfigurations->filename(m_data->logMessage()->level()) << "].\n"
4562  << "Few possible reasons (could be something else):\n" << " * Permission denied\n"
4563  << " * Disk full\n" << " * Disk is not writable", true);
4564  } else {
4565  if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || (m_data->logMessage()->logger()->isFlushNeeded(m_data->logMessage()->level()))) {
4566  m_data->logMessage()->logger()->flush(m_data->logMessage()->level(), fs);
4567  }
4568  }
4569  } else {
4570  ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(m_data->logMessage()->level()) << "] "
4571  << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: "
4572  << m_data->logMessage()->logger()->id() << "]", false);
4573  }
4574  }
4575  if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput(m_data->logMessage()->level())) {
4576  if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput))
4577  m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, m_data->logMessage()->level());
4578  ELPP_COUT << ELPP_COUT_LINE(logLine);
4579  }
4580  }
4581 #if defined(ELPP_SYSLOG)
4582  else if (m_data->dispatchAction() == base::DispatchAction::SysLog) {
4583  // Determine syslog priority
4584  int sysLogPriority = 0;
4585  if (m_data->logMessage()->level() == Level::Fatal)
4586  sysLogPriority = LOG_EMERG;
4587  else if (m_data->logMessage()->level() == Level::Error)
4588  sysLogPriority = LOG_ERR;
4589  else if (m_data->logMessage()->level() == Level::Warning)
4590  sysLogPriority = LOG_WARNING;
4591  else if (m_data->logMessage()->level() == Level::Info)
4592  sysLogPriority = LOG_INFO;
4593  else if (m_data->logMessage()->level() == Level::Debug)
4594  sysLogPriority = LOG_DEBUG;
4595  else
4596  sysLogPriority = LOG_NOTICE;
4597 # if defined(ELPP_UNICODE)
4598  char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str());
4599  syslog(sysLogPriority, "%s", line);
4600  free(line);
4601 # else
4602  syslog(sysLogPriority, "%s", logLine.c_str());
4603 # endif
4604  }
4605 #endif // defined(ELPP_SYSLOG)
4606  }
4607 };
4608 #if ELPP_ASYNC_LOGGING
4609 class AsyncLogDispatchCallback : public LogDispatchCallback
4610 {
4611 protected:
4612  void handle(const LogDispatchData* data)
4613  {
4614  base::type::string_t logLine = data->logMessage()->logger()->logBuilder()->build(data->logMessage(), data->dispatchAction() == base::DispatchAction::NormalLog);
4615  if (data->dispatchAction() == base::DispatchAction::NormalLog && data->logMessage()->logger()->typedConfigurations()->toStandardOutput(data->logMessage()->level())) {
4616  if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput))
4617  data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, data->logMessage()->level());
4618  ELPP_COUT << ELPP_COUT_LINE(logLine);
4619  }
4620  // Save resources and only queue if we want to write to file otherwise just ignore handler
4621  if (data->logMessage()->logger()->typedConfigurations()->toFile(data->logMessage()->level())) {
4622  ELPP->asyncLogQueue()->push(AsyncLogItem(*(data->logMessage()), *data, logLine));
4623  }
4624  }
4625 };
4626 class AsyncDispatchWorker : public base::IWorker, public base::threading::ThreadSafe
4627 {
4628 public:
4629  AsyncDispatchWorker()
4630  {
4631  setContinueRunning(false);
4632  }
4633 
4634  virtual ~AsyncDispatchWorker()
4635  {
4636  setContinueRunning(false);
4637  ELPP_INTERNAL_INFO(6, "Stopping dispatch worker - Cleaning log queue");
4638  clean();
4639  ELPP_INTERNAL_INFO(6, "Log queue cleaned");
4640  }
4641 
4642  inline bool clean()
4643  {
4644  std::mutex m;
4645  std::unique_lock<std::mutex> lk(m);
4646  cv.wait(lk, [] { return !ELPP->asyncLogQueue()->empty(); });
4647  emptyQueue();
4648  lk.unlock();
4649  cv.notify_one();
4650  return ELPP->asyncLogQueue()->empty();
4651  }
4652 
4653  inline void emptyQueue()
4654  {
4655  while (!ELPP->asyncLogQueue()->empty()) {
4656  AsyncLogItem data = ELPP->asyncLogQueue()->next();
4657  handle(&data);
4658  base::threading::msleep(100);
4659  }
4660  }
4661 
4662  virtual inline void start()
4663  {
4664  base::threading::msleep(5000); // Wait extra few seconds
4665  setContinueRunning(true);
4666  std::thread t1(&AsyncDispatchWorker::runner, this);
4667  t1.join();
4668  }
4669 
4670  void handle(AsyncLogItem* logItem)
4671  {
4672  LogDispatchData* data = logItem->data();
4673  LogMessage* logMessage = logItem->logMessage();
4674  Logger* logger = logMessage->logger();
4675  base::TypedConfigurations* conf = logger->typedConfigurations();
4676  base::type::string_t logLine = logItem->logLine();
4677  if (data->dispatchAction() == base::DispatchAction::NormalLog) {
4678  if (conf->toFile(logMessage->level())) {
4679  base::type::fstream_t* fs = conf->fileStream(logMessage->level());
4680  if (fs != nullptr) {
4681  fs->write(logLine.c_str(), logLine.size());
4682  if (fs->fail()) {
4683  ELPP_INTERNAL_ERROR("Unable to write log to file ["
4684  << conf->filename(logMessage->level()) << "].\n"
4685  << "Few possible reasons (could be something else):\n" << " * Permission denied\n"
4686  << " * Disk full\n" << " * Disk is not writable", true);
4687  } else {
4688  if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || (logger->isFlushNeeded(logMessage->level()))) {
4689  logger->flush(logMessage->level(), fs);
4690  }
4691  }
4692  } else {
4693  ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(logMessage->level()) << "] "
4694  << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " << logger->id() << "]", false);
4695  }
4696  }
4697  }
4698 # if defined(ELPP_SYSLOG)
4699  else if (data->dispatchAction() == base::DispatchAction::SysLog) {
4700  // Determine syslog priority
4701  int sysLogPriority = 0;
4702  if (logMessage->level() == Level::Fatal)
4703  sysLogPriority = LOG_EMERG;
4704  else if (logMessage->level() == Level::Error)
4705  sysLogPriority = LOG_ERR;
4706  else if (logMessage->level() == Level::Warning)
4707  sysLogPriority = LOG_WARNING;
4708  else if (logMessage->level() == Level::Info)
4709  sysLogPriority = LOG_INFO;
4710  else if (logMessage->level() == Level::Debug)
4711  sysLogPriority = LOG_DEBUG;
4712  else
4713  sysLogPriority = LOG_NOTICE;
4714 # if defined(ELPP_UNICODE)
4715  char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str());
4716  syslog(sysLogPriority, "%s", line);
4717  free(line);
4718 # else
4719  syslog(sysLogPriority, "%s", logLine.c_str());
4720 # endif
4721  }
4722 # endif // defined(ELPP_SYSLOG)
4723  }
4724 
4725  void run()
4726  {
4727  while (continueRunning()) {
4728  emptyQueue();
4729  base::threading::msleep(10); // 10ms
4730  }
4731  }
4732 
4733  static void* runner(void* context)
4734  {
4735  static_cast<AsyncDispatchWorker*>(context)->run();
4736  return NULL;
4737  }
4738 
4739  void setContinueRunning(bool value)
4740  {
4741  base::threading::ScopedLock scopedLock(m_continueRunningMutex);
4742  m_continueRunning = value;
4743  }
4744  bool continueRunning(void)
4745  {
4746  return m_continueRunning;
4747  }
4748 private:
4749  std::condition_variable cv;
4750  bool m_continueRunning;
4751  base::threading::Mutex m_continueRunningMutex;
4752 };
4753 #endif // ELPP_ASYNC_LOGGING
4754 } // namespace base
4755 namespace base {
4756 class DefaultLogBuilder : public LogBuilder
4757 {
4758 public:
4759  base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const
4760  {
4761  base::TypedConfigurations* tc = logMessage->logger()->typedConfigurations();
4762  const base::LogFormat* logFormat = &tc->logFormat(logMessage->level());
4763  base::type::string_t logLine = logFormat->format();
4764  char buff[base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength] = "";
4765  const char* bufLim = buff + sizeof(buff);
4766  if (logFormat->hasFlag(base::FormatFlags::AppName)) {
4767  // App name
4768  base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kAppNameFormatSpecifier,
4769  logMessage->logger()->parentApplicationName());
4770  }
4771  if (logFormat->hasFlag(base::FormatFlags::ThreadId)) {
4772  // Thread ID
4773  base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kThreadIdFormatSpecifier,
4774  base::threading::getCurrentThreadId());
4775  }
4776  if (logFormat->hasFlag(base::FormatFlags::DateTime)) {
4777  // DateTime
4778  base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kDateTimeFormatSpecifier,
4779  base::utils::DateTime::getDateTime(logFormat->dateTimeFormat().c_str(),
4780  &tc->millisecondsWidth(logMessage->level())));
4781  }
4782  if (logFormat->hasFlag(base::FormatFlags::Function)) {
4783  // Function
4784  base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFunctionFormatSpecifier, logMessage->func());
4785  }
4786  if (logFormat->hasFlag(base::FormatFlags::File)) {
4787  // File
4788  char* buf = base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength);
4789  base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff);
4790  buf = base::utils::Str::addToBuff(buff, buf, bufLim);
4791  base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileFormatSpecifier, std::string(buff));
4792  }
4793  if (logFormat->hasFlag(base::FormatFlags::FileBase)) {
4794  // FileBase
4795  char* buf = base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength);
4796  base::utils::File::buildBaseFilename(logMessage->file(), buff);
4797  buf = base::utils::Str::addToBuff(buff, buf, bufLim);
4798  base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileBaseFormatSpecifier, std::string(buff));
4799  }
4800  if (logFormat->hasFlag(base::FormatFlags::Line)) {
4801  // Line
4802  char* buf = base::utils::Str::clearBuff(buff, base::consts::kSourceLineMaxLength);
4803  buf = base::utils::Str::convertAndAddToBuff(logMessage->line(),
4804  base::consts::kSourceLineMaxLength, buf, bufLim, false);
4805  base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLineFormatSpecifier, std::string(buff));
4806  }
4807  if (logFormat->hasFlag(base::FormatFlags::Location)) {
4808  // Location
4809  char* buf = base::utils::Str::clearBuff(buff,
4810  base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength);
4811  base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff);
4812  buf = base::utils::Str::addToBuff(buff, buf, bufLim);
4813  buf = base::utils::Str::addToBuff(":", buf, bufLim);
4814  buf = base::utils::Str::convertAndAddToBuff(logMessage->line(),
4815  base::consts::kSourceLineMaxLength, buf, bufLim, false);
4816  base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLocationFormatSpecifier, std::string(buff));
4817  }
4818  if (logMessage->level() == Level::Verbose && logFormat->hasFlag(base::FormatFlags::VerboseLevel)) {
4819  // Verbose level
4820  char* buf = base::utils::Str::clearBuff(buff, 1);
4821  buf = base::utils::Str::convertAndAddToBuff(logMessage->verboseLevel(), 1, buf, bufLim, false);
4822  base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kVerboseLevelFormatSpecifier, std::string(buff));
4823  }
4824  if (logFormat->hasFlag(base::FormatFlags::LogMessage)) {
4825  // Log message
4826  base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kMessageFormatSpecifier, logMessage->message());
4827  }
4828 #if !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS)
4829  for (std::vector<CustomFormatSpecifier>::const_iterator it = ELPP->customFormatSpecifiers()->begin();
4830  it != ELPP->customFormatSpecifiers()->end(); ++it) {
4831  std::string fs(it->formatSpecifier());
4832  base::type::string_t wcsFormatSpecifier(fs.begin(), fs.end());
4833  base::utils::Str::replaceFirstWithEscape(logLine, wcsFormatSpecifier, std::string(it->resolver()()));
4834  }
4835 #endif // !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS)
4836  if (appendNewLine) logLine += ELPP_LITERAL("\n");
4837  return logLine;
4838  }
4839 };
4841 class LogDispatcher : base::NoCopy
4842 {
4843 public:
4844  LogDispatcher(bool proceed, LogMessage&& logMessage, base::DispatchAction dispatchAction) :
4845  m_proceed(proceed),
4846  m_logMessage(std::move(logMessage)),
4847  m_dispatchAction(std::move(dispatchAction))
4848  {
4849  }
4850 
4851  void dispatch(void)
4852  {
4853  if (m_proceed && m_dispatchAction == base::DispatchAction::None) {
4854  m_proceed = false;
4855  }
4856  if (!m_proceed) {
4857  return;
4858  }
4859  // We minimize the time of ELPP's lock - this lock is released after log is written
4860  base::threading::ScopedLock scopedLock(ELPP->lock());
4861  base::TypedConfigurations* tc = m_logMessage.logger()->m_typedConfigurations;
4862  if (ELPP->hasFlag(LoggingFlag::StrictLogFileSizeCheck)) {
4863  tc->validateFileRolling(m_logMessage.level(), ELPP->preRollOutCallback());
4864  }
4865  LogDispatchCallback* callback = nullptr;
4866  LogDispatchData data;
4867  for (const std::pair<std::string, base::type::LogDispatchCallbackPtr>& h
4868  : ELPP->m_logDispatchCallbacks) {
4869  callback = h.second.get();
4870  if (callback != nullptr && callback->enabled()) {
4871  data.setLogMessage(&m_logMessage);
4872  data.setDispatchAction(m_dispatchAction);
4873  callback->acquireLock();
4874  callback->handle(&data);
4875  callback->releaseLock();
4876  }
4877  }
4878  }
4879 
4880 private:
4881  bool m_proceed;
4882  LogMessage m_logMessage;
4883  base::DispatchAction m_dispatchAction;
4884 };
4885 #if defined(ELPP_STL_LOGGING)
4886 namespace workarounds {
4894 template <typename T, typename Container>
4895 class IterableContainer
4896 {
4897 public:
4898  typedef typename Container::iterator iterator;
4899  typedef typename Container::const_iterator const_iterator;
4900  IterableContainer(void) {}
4901  virtual ~IterableContainer(void) {}
4902  iterator begin(void) { return getContainer().begin(); }
4903  iterator end(void) { return getContainer().end(); }
4904 private:
4905  virtual Container& getContainer(void) = 0;
4906 };
4908 template<typename T, typename Container = std::vector<T>, typename Comparator = std::less<typename Container::value_type>>
4909 class IterablePriorityQueue : public IterableContainer<T, Container>, public std::priority_queue<T, Container, Comparator>
4910 {
4911 public:
4912  IterablePriorityQueue(std::priority_queue<T, Container, Comparator> queue_)
4913  {
4914  std::size_t count_ = 0;
4915  while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) {
4916  this->push(queue_.top());
4917  queue_.pop();
4918  }
4919  }
4920 private:
4921  inline Container& getContainer(void)
4922  {
4923  return this->c;
4924  }
4925 };
4927 template<typename T, typename Container = std::deque<T>>
4928 class IterableQueue : public IterableContainer<T, Container>, public std::queue<T, Container>
4929 {
4930 public:
4931  IterableQueue(std::queue<T, Container> queue_)
4932  {
4933  std::size_t count_ = 0;
4934  while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) {
4935  this->push(queue_.front());
4936  queue_.pop();
4937  }
4938  }
4939 private:
4940  inline Container& getContainer(void)
4941  {
4942  return this->c;
4943  }
4944 };
4946 template<typename T, typename Container = std::deque<T>>
4947 class IterableStack : public IterableContainer<T, Container>, public std::stack<T, Container>
4948 {
4949 public:
4950  IterableStack(std::stack<T, Container> stack_)
4951  {
4952  std::size_t count_ = 0;
4953  while (++count_ < base::consts::kMaxLogPerContainer && !stack_.empty()) {
4954  this->push(stack_.top());
4955  stack_.pop();
4956  }
4957  }
4958 private:
4959  inline Container& getContainer(void)
4960  {
4961  return this->c;
4962  }
4963 };
4964 } // namespace workarounds
4965 #endif // defined(ELPP_STL_LOGGING)
4966 // Log message builder
4967 class MessageBuilder
4968 {
4969 public:
4970  MessageBuilder(void) : m_logger(nullptr), m_containerLogSeperator(ELPP_LITERAL("")) {}
4971  void initialize(Logger* logger)
4972  {
4973  m_logger = logger;
4974  m_containerLogSeperator = ELPP->hasFlag(LoggingFlag::NewLineForContainer) ?
4975  ELPP_LITERAL("\n ") : ELPP_LITERAL(", ");
4976  }
4977 
4978 # define ELPP_SIMPLE_LOG(LOG_TYPE)\
4979  inline MessageBuilder& operator<<(LOG_TYPE msg) {\
4980  m_logger->stream() << msg;\
4981  if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {\
4982  m_logger->stream() << " ";\
4983  }\
4984  return *this;\
4985  }
4986 
4987  inline MessageBuilder& operator<<(const std::string& msg)
4988  {
4989  return operator<<(msg.c_str());
4990  }
4991  ELPP_SIMPLE_LOG(char)
4992  ELPP_SIMPLE_LOG(bool)
4993  ELPP_SIMPLE_LOG(signed short)
4994  ELPP_SIMPLE_LOG(unsigned short)
4995  ELPP_SIMPLE_LOG(signed int)
4996  ELPP_SIMPLE_LOG(unsigned int)
4997  ELPP_SIMPLE_LOG(signed long)
4998  ELPP_SIMPLE_LOG(unsigned long)
4999  ELPP_SIMPLE_LOG(float)
5000  ELPP_SIMPLE_LOG(double)
5001  ELPP_SIMPLE_LOG(char*)
5002  ELPP_SIMPLE_LOG(const char*)
5003  ELPP_SIMPLE_LOG(const void*)
5004  ELPP_SIMPLE_LOG(long double)
5005  inline MessageBuilder& operator<<(const std::wstring& msg)
5006  {
5007  return operator<<(msg.c_str());
5008  }
5009  inline MessageBuilder& operator<<(const wchar_t* msg)
5010  {
5011  if (msg == nullptr) {
5012  m_logger->stream() << base::consts::kNullPointer;
5013  return *this;
5014  }
5015 # if defined(ELPP_UNICODE)
5016  m_logger->stream() << msg;
5017 # else
5018  char* buff_ = base::utils::Str::wcharPtrToCharPtr(msg);
5019  m_logger->stream() << buff_;
5020  free(buff_);
5021 # endif
5022  if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {
5023  m_logger->stream() << " ";
5024  }
5025  return *this;
5026  }
5027  // ostream manipulators
5028  inline MessageBuilder& operator<<(std::ostream & (*OStreamMani)(std::ostream&))
5029  {
5030  m_logger->stream() << OStreamMani;
5031  return *this;
5032  }
5033 #define ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(temp) \
5034  template <typename T> \
5035  inline MessageBuilder& operator<<(const temp<T>& template_inst) { \
5036  return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \
5037  }
5038 #define ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(temp) \
5039  template <typename T1, typename T2> \
5040  inline MessageBuilder& operator<<(const temp<T1, T2>& template_inst) { \
5041  return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \
5042  }
5043 #define ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(temp) \
5044  template <typename T1, typename T2, typename T3> \
5045  inline MessageBuilder& operator<<(const temp<T1, T2, T3>& template_inst) { \
5046  return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \
5047  }
5048 #define ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(temp) \
5049  template <typename T1, typename T2, typename T3, typename T4> \
5050  inline MessageBuilder& operator<<(const temp<T1, T2, T3, T4>& template_inst) { \
5051  return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \
5052  }
5053 #define ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(temp) \
5054  template <typename T1, typename T2, typename T3, typename T4, typename T5> \
5055  inline MessageBuilder& operator<<(const temp<T1, T2, T3, T4, T5>& template_inst) { \
5056  return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \
5057  }
5058 
5059 #if defined(ELPP_STL_LOGGING)
5060  ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::vector)
5061  ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::list)
5062  ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::deque)
5063  ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::set)
5064  ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::multiset)
5065  ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::map)
5066  ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::multimap)
5067  template <class T, class Container>
5068  inline MessageBuilder& operator<<(const std::queue<T, Container>& queue_)
5069  {
5070  base::workarounds::IterableQueue<T, Container> iterableQueue_ =
5071  static_cast<base::workarounds::IterableQueue<T, Container> >(queue_);
5072  return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size());
5073  }
5074  template <class T, class Container>
5075  inline MessageBuilder& operator<<(const std::stack<T, Container>& stack_)
5076  {
5077  base::workarounds::IterableStack<T, Container> iterableStack_ =
5078  static_cast<base::workarounds::IterableStack<T, Container> >(stack_);
5079  return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size());
5080  }
5081  template <class T, class Container, class Comparator>
5082  inline MessageBuilder& operator<<(const std::priority_queue<T, Container, Comparator>& priorityQueue_)
5083  {
5084  base::workarounds::IterablePriorityQueue<T, Container, Comparator> iterablePriorityQueue_ =
5085  static_cast<base::workarounds::IterablePriorityQueue<T, Container, Comparator> >(priorityQueue_);
5086  return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size());
5087  }
5088  template <class First, class Second>
5089  inline MessageBuilder& operator<<(const std::pair<First, Second>& pair_)
5090  {
5091  m_logger->stream() << ELPP_LITERAL("(");
5092  operator << (static_cast<First>(pair_.first));
5093  m_logger->stream() << ELPP_LITERAL(", ");
5094  operator << (static_cast<Second>(pair_.second));
5095  m_logger->stream() << ELPP_LITERAL(")");
5096  return *this;
5097  }
5098  template <std::size_t Size>
5099  inline MessageBuilder& operator<<(const std::bitset<Size>& bitset_)
5100  {
5101  m_logger->stream() << ELPP_LITERAL("[");
5102  operator << (bitset_.to_string());
5103  m_logger->stream() << ELPP_LITERAL("]");
5104  return *this;
5105  }
5106 # if defined(ELPP_LOG_STD_ARRAY)
5107  template <class T, std::size_t Size>
5108  inline MessageBuilder& operator<<(const std::array<T, Size>& array)
5109  {
5110  return writeIterator(array.begin(), array.end(), array.size());
5111  }
5112 # endif // defined(ELPP_LOG_STD_ARRAY)
5113 # if defined(ELPP_LOG_UNORDERED_MAP)
5114  ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_map)
5115  ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_multimap)
5116 # endif // defined(ELPP_LOG_UNORDERED_MAP)
5117 # if defined(ELPP_LOG_UNORDERED_SET)
5118  ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_set)
5119  ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_multiset)
5120 # endif // defined(ELPP_LOG_UNORDERED_SET)
5121 #endif // defined(ELPP_STL_LOGGING)
5122 #if defined(ELPP_QT_LOGGING)
5123  inline MessageBuilder& operator<<(const QString& msg)
5124  {
5125 # if defined(ELPP_UNICODE)
5126  m_logger->stream() << msg.toStdWString();
5127 # else
5128  m_logger->stream() << msg.toStdString();
5129 # endif // defined(ELPP_UNICODE)
5130  return *this;
5131  }
5132  inline MessageBuilder& operator<<(const QByteArray& msg)
5133  {
5134  return operator << (QString(msg));
5135  }
5136  inline MessageBuilder& operator<<(const QStringRef& msg)
5137  {
5138  return operator<<(msg.toString());
5139  }
5140  inline MessageBuilder& operator<<(qint64 msg)
5141  {
5142 # if defined(ELPP_UNICODE)
5143  m_logger->stream() << QString::number(msg).toStdWString();
5144 # else
5145  m_logger->stream() << QString::number(msg).toStdString();
5146 # endif // defined(ELPP_UNICODE)
5147  return *this;
5148  }
5149  inline MessageBuilder& operator<<(quint64 msg)
5150  {
5151 # if defined(ELPP_UNICODE)
5152  m_logger->stream() << QString::number(msg).toStdWString();
5153 # else
5154  m_logger->stream() << QString::number(msg).toStdString();
5155 # endif // defined(ELPP_UNICODE)
5156  return *this;
5157  }
5158  inline MessageBuilder& operator<<(QChar msg)
5159  {
5160  m_logger->stream() << msg.toLatin1();
5161  return *this;
5162  }
5163  inline MessageBuilder& operator<<(const QLatin1String& msg)
5164  {
5165  m_logger->stream() << msg.latin1();
5166  return *this;
5167  }
5168  ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QList)
5169  ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QVector)
5170  ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QQueue)
5171  ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QSet)
5172  ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QLinkedList)
5173  ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QStack)
5174  template <typename First, typename Second>
5175  inline MessageBuilder& operator<<(const QPair<First, Second>& pair_)
5176  {
5177  m_logger->stream() << ELPP_LITERAL("(");
5178  operator << (static_cast<First>(pair_.first));
5179  m_logger->stream() << ELPP_LITERAL(", ");
5180  operator << (static_cast<Second>(pair_.second));
5181  m_logger->stream() << ELPP_LITERAL(")");
5182  return *this;
5183  }
5184  template <typename K, typename V>
5185  inline MessageBuilder& operator<<(const QMap<K, V>& map_)
5186  {
5187  m_logger->stream() << ELPP_LITERAL("[");
5188  QList<K> keys = map_.keys();
5189  typename QList<K>::const_iterator begin = keys.begin();
5190  typename QList<K>::const_iterator end = keys.end();
5191  int max_ = static_cast<int>(base::consts::kMaxLogPerContainer); // to prevent warning
5192  for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
5193  m_logger->stream() << ELPP_LITERAL("(");
5194  operator << (static_cast<K>(*begin));
5195  m_logger->stream() << ELPP_LITERAL(", ");
5196  operator << (static_cast<V>(map_.value(*begin)));
5197  m_logger->stream() << ELPP_LITERAL(")");
5198  m_logger->stream() << ((index_ < keys.size() - 1) ? m_containerLogSeperator : ELPP_LITERAL(""));
5199  }
5200  if (begin != end) {
5201  m_logger->stream() << ELPP_LITERAL("...");
5202  }
5203  m_logger->stream() << ELPP_LITERAL("]");
5204  return *this;
5205  }
5206  template <typename K, typename V>
5207  inline MessageBuilder& operator<<(const QMultiMap<K, V>& map_)
5208  {
5209  operator << (static_cast<QMap<K, V>>(map_));
5210  return *this;
5211  }
5212  template <typename K, typename V>
5213  inline MessageBuilder& operator<<(const QHash<K, V>& hash_)
5214  {
5215  m_logger->stream() << ELPP_LITERAL("[");
5216  QList<K> keys = hash_.keys();
5217  typename QList<K>::const_iterator begin = keys.begin();
5218  typename QList<K>::const_iterator end = keys.end();
5219  int max_ = static_cast<int>(base::consts::kMaxLogPerContainer); // prevent type warning
5220  for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
5221  m_logger->stream() << ELPP_LITERAL("(");
5222  operator << (static_cast<K>(*begin));
5223  m_logger->stream() << ELPP_LITERAL(", ");
5224  operator << (static_cast<V>(hash_.value(*begin)));
5225  m_logger->stream() << ELPP_LITERAL(")");
5226  m_logger->stream() << ((index_ < keys.size() - 1) ? m_containerLogSeperator : ELPP_LITERAL(""));
5227  }
5228  if (begin != end) {
5229  m_logger->stream() << ELPP_LITERAL("...");
5230  }
5231  m_logger->stream() << ELPP_LITERAL("]");
5232  return *this;
5233  }
5234  template <typename K, typename V>
5235  inline MessageBuilder& operator<<(const QMultiHash<K, V>& multiHash_)
5236  {
5237  operator << (static_cast<QHash<K, V>>(multiHash_));
5238  return *this;
5239  }
5240 #endif // defined(ELPP_QT_LOGGING)
5241 #if defined(ELPP_BOOST_LOGGING)
5242  ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::vector)
5243  ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::stable_vector)
5244  ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::list)
5245  ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::deque)
5246  ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::map)
5247  ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::flat_map)
5248  ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::set)
5249  ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::flat_set)
5250 #endif // defined(ELPP_BOOST_LOGGING)
5251 
5260 #define MAKE_CONTAINERELPP_FRIENDLY(ContainerType, SizeMethod, ElementInstance) \
5261  el::base::type::ostream_t& operator<<(el::base::type::ostream_t& ss, const ContainerType& container) {\
5262  const el::base::type::char_t* sep = ELPP->hasFlag(el::LoggingFlag::NewLineForContainer) ? \
5263  ELPP_LITERAL("\n ") : ELPP_LITERAL(", ");\
5264  ContainerType::const_iterator elem = container.begin();\
5265  ContainerType::const_iterator endElem = container.end();\
5266  std::size_t size_ = container.SizeMethod; \
5267  ss << ELPP_LITERAL("[");\
5268  for (std::size_t i = 0; elem != endElem && i < el::base::consts::kMaxLogPerContainer; ++i, ++elem) { \
5269  ss << ElementInstance;\
5270  ss << ((i < size_ - 1) ? sep : ELPP_LITERAL(""));\
5271  }\
5272  if (elem != endElem) {\
5273  ss << ELPP_LITERAL("...");\
5274  }\
5275  ss << ELPP_LITERAL("]");\
5276  return ss;\
5277  }
5278 #if defined(ELPP_WXWIDGETS_LOGGING)
5279  ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(wxVector)
5280 # define ELPP_WX_PTR_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), *(*elem))
5281 # define ELPP_WX_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), (*elem))
5282 # define ELPP_WX_HASH_MAP_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), \
5283  ELPP_LITERAL("(") << elem->first << ELPP_LITERAL(", ") << elem->second << ELPP_LITERAL(")")
5284 #else
5285 # define ELPP_WX_PTR_ENABLED(ContainerType)
5286 # define ELPP_WX_ENABLED(ContainerType)
5287 # define ELPP_WX_HASH_MAP_ENABLED(ContainerType)
5288 #endif // defined(ELPP_WXWIDGETS_LOGGING)
5289  // Other classes
5290  template <class Class>
5291  ELPP_SIMPLE_LOG(const Class&)
5292 #undef ELPP_SIMPLE_LOG
5293 #undef ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG
5294 #undef ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG
5295 #undef ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG
5296 #undef ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG
5297 #undef ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG
5298 private:
5299  Logger* m_logger;
5300  const base::type::char_t* m_containerLogSeperator;
5301 
5302  template<class Iterator>
5303  inline MessageBuilder& writeIterator(Iterator begin_, Iterator end_, std::size_t size_)
5304  {
5305  m_logger->stream() << ELPP_LITERAL("[");
5306  for (std::size_t i = 0; begin_ != end_ && i < base::consts::kMaxLogPerContainer; ++i, ++begin_) {
5307  operator << (*begin_);
5308  m_logger->stream() << ((i < size_ - 1) ? m_containerLogSeperator : ELPP_LITERAL(""));
5309  }
5310  if (begin_ != end_) {
5311  m_logger->stream() << ELPP_LITERAL("...");
5312  }
5313  m_logger->stream() << ELPP_LITERAL("]");
5314  if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {
5315  m_logger->stream() << " ";
5316  }
5317  return *this;
5318  }
5319 };
5321 class NullWriter : base::NoCopy
5322 {
5323 public:
5324  NullWriter(void) {}
5325 
5326  // Null manipulator
5327  inline NullWriter& operator<<(std::ostream & (*)(std::ostream&))
5328  {
5329  return *this;
5330  }
5331 
5332  template <typename T>
5333  inline NullWriter& operator<<(const T&)
5334  {
5335  return *this;
5336  }
5337 };
5339 class Writer : base::NoCopy
5340 {
5341 public:
5342  Writer(Level level, const char* file, unsigned long int line,
5343  const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
5344  base::type::VerboseLevel verboseLevel = 0) :
5345  m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel),
5346  m_proceed(false), m_dispatchAction(dispatchAction)
5347  {
5348  }
5349 
5350  virtual ~Writer(void)
5351  {
5352  processDispatch();
5353  }
5354 
5355  template <typename T>
5356  inline Writer& operator<<(const T& log)
5357  {
5358 #if ELPP_LOGGING_ENABLED
5359  if (m_proceed) {
5360  m_messageBuilder << log;
5361  }
5362 #endif // ELPP_LOGGING_ENABLED
5363  return *this;
5364  }
5365 
5366  inline Writer& operator<<(std::ostream & (*log)(std::ostream&))
5367  {
5368 #if ELPP_LOGGING_ENABLED
5369  if (m_proceed) {
5370  m_messageBuilder << log;
5371  }
5372 #endif // ELPP_LOGGING_ENABLED
5373  return *this;
5374  }
5375 
5376  Writer& construct(Logger* logger, bool needLock = true)
5377  {
5378  m_logger = logger;
5379  initializeLogger(logger->id(), false, needLock);
5380  m_messageBuilder.initialize(m_logger);
5381  return *this;
5382  }
5383 
5384  Writer& construct(int count, const char* loggerIds, ...)
5385  {
5386  if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {
5387  va_list loggersList;
5388  va_start(loggersList, loggerIds);
5389  const char* id = loggerIds;
5390  for (int i = 0; i < count; ++i) {
5391  m_loggerIds.push_back(std::string(id));
5392  id = va_arg(loggersList, const char*);
5393  }
5394  va_end(loggersList);
5395  initializeLogger(m_loggerIds.at(0));
5396  } else {
5397  initializeLogger(std::string(loggerIds));
5398  }
5399  m_messageBuilder.initialize(m_logger);
5400  return *this;
5401  }
5402 protected:
5403  Level m_level;
5404  const char* m_file;
5405  const unsigned long int m_line;
5406  const char* m_func;
5407  base::type::VerboseLevel m_verboseLevel;
5408  Logger* m_logger;
5409  bool m_proceed;
5410  base::MessageBuilder m_messageBuilder;
5411  base::DispatchAction m_dispatchAction;
5412  std::vector<std::string> m_loggerIds;
5413  friend class el::Helpers;
5414 
5415  void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true)
5416  {
5417  if (lookup) {
5418  m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically));
5419  }
5420  if (m_logger == nullptr) {
5421  ELPP->acquireLock();
5422  if (!ELPP->registeredLoggers()->has(std::string(base::consts::kDefaultLoggerId))) {
5423  // Somehow default logger has been unregistered. Not good! Register again
5424  ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId));
5425  }
5426  ELPP->releaseLock(); // Need to unlock it for next writer
5427  Writer(Level::Debug, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId)
5428  << "Logger [" << loggerId << "] is not registered yet!";
5429  m_proceed = false;
5430  } else {
5431  if (needLock) {
5432  m_logger->acquireLock(); // This should not be unlocked by checking m_proceed because
5433  // m_proceed can be changed by lines below
5434  }
5435  if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) {
5436  m_proceed = m_level == Level::Verbose ? m_logger->enabled(m_level) :
5437  LevelHelper::castToInt(m_level) >= LevelHelper::castToInt(ELPP->m_loggingLevel);
5438  } else {
5439  m_proceed = m_logger->enabled(m_level);
5440  }
5441  }
5442  }
5443 
5444  void processDispatch()
5445  {
5446 #if ELPP_LOGGING_ENABLED
5447  if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {
5448  bool firstDispatched = false;
5449  base::type::string_t logMessage;
5450  std::size_t i = 0;
5451  do {
5452  if (m_proceed) {
5453  if (firstDispatched) {
5454  m_logger->stream() << logMessage;
5455  } else {
5456  firstDispatched = true;
5457  if (m_loggerIds.size() > 1) {
5458  logMessage = m_logger->stream().str();
5459  }
5460  }
5461  triggerDispatch();
5462  } else if (m_logger != nullptr) {
5463  m_logger->stream().str(ELPP_LITERAL(""));
5464  m_logger->releaseLock();
5465  }
5466  if (i + 1 < m_loggerIds.size()) {
5467  initializeLogger(m_loggerIds.at(i + 1));
5468  }
5469  } while (++i < m_loggerIds.size());
5470  } else {
5471  if (m_proceed) {
5472  triggerDispatch();
5473  } else if (m_logger != nullptr) {
5474  m_logger->stream().str(ELPP_LITERAL(""));
5475  m_logger->releaseLock();
5476  }
5477  }
5478 #else
5479  if (m_logger != nullptr) {
5480  m_logger->stream().str(ELPP_LITERAL(""));
5481  m_logger->releaseLock();
5482  }
5483 #endif // ELPP_LOGGING_ENABLED
5484  }
5485 
5486  void triggerDispatch(void)
5487  {
5488  if (m_proceed) {
5489  base::LogDispatcher(m_proceed, LogMessage(m_level, m_file, m_line, m_func, m_verboseLevel,
5490  m_logger), m_dispatchAction).dispatch();
5491  }
5492  if (m_logger != nullptr) {
5493  m_logger->stream().str(ELPP_LITERAL(""));
5494  m_logger->releaseLock();
5495  }
5496  if (m_proceed && m_level == Level::Fatal
5497  && !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) {
5498  base::Writer(Level::Warning, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId)
5499  << "Aborting application. Reason: Fatal log at [" << m_file << ":" << m_line << "]";
5500  std::stringstream reasonStream;
5501  reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]"
5502  << " If you wish to disable 'abort on fatal log' please use "
5503  << "el::Helpers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog)";
5504  base::utils::abort(1, reasonStream.str());
5505  }
5506  m_proceed = false;
5507  }
5508 };
5509 class PErrorWriter : public base::Writer
5510 {
5511 public:
5512  PErrorWriter(Level level, const char* file, unsigned long int line,
5513  const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
5514  base::type::VerboseLevel verboseLevel = 0) :
5515  base::Writer(level, file, line, func, dispatchAction, verboseLevel)
5516  {
5517  }
5518 
5519  virtual ~PErrorWriter(void)
5520  {
5521  if (m_proceed) {
5522 #if ELPP_COMPILER_MSVC
5523  char buff[256];
5524  strerror_s(buff, 256, errno);
5525  m_logger->stream() << ": " << buff << " [" << errno << "]";
5526 #else
5527  m_logger->stream() << ": " << strerror(errno) << " [" << errno << "]";
5528 #endif
5529  }
5530  }
5531 };
5532 } // namespace base
5533 // Logging from Logger class. Why this is here? Because we have Storage and Writer class available
5534 #if ELPP_VARIADIC_TEMPLATES_SUPPORTED
5535 template <typename T, typename... Args>
5536 void Logger::log_(Level level, int vlevel, const char* s, const T& value, const Args& ... args)
5537 {
5538  base::MessageBuilder b;
5539  b.initialize(this);
5540  while (*s) {
5541  if (*s == base::consts::kFormatSpecifierChar) {
5542  if (*(s + 1) == base::consts::kFormatSpecifierChar) {
5543  ++s;
5544  } else {
5545  if (*(s + 1) == base::consts::kFormatSpecifierCharValue) {
5546  ++s;
5547  b << value;
5548  log_(level, vlevel, ++s, args...);
5549  return;
5550  }
5551  }
5552  }
5553  b << *s++;
5554  }
5555  ELPP_INTERNAL_ERROR("Too many arguments provided. Unable to handle. Please provide more format specifiers", false);
5556 }
5557 template <typename T>
5558 inline void Logger::log_(Level level, int vlevel, const T& log)
5559 {
5560  if (level == Level::Verbose) {
5561  if (ELPP->vRegistry()->allowed(vlevel, __FILE__)) {
5562  base::Writer(Level::Verbose, "FILE", 0, "FUNCTION",
5563  base::DispatchAction::NormalLog, vlevel).construct(this, false) << log;
5564  } else {
5565  stream().str(ELPP_LITERAL(""));
5566  }
5567  } else {
5568  base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log;
5569  }
5570 }
5571 template <typename T, typename... Args>
5572 void Logger::log(Level level, const char* s, const T& value, const Args& ... args)
5573 {
5574  base::threading::ScopedLock scopedLock(lock());
5575  log_(level, 0, s, value, args...);
5576 }
5577 template <typename T>
5578 inline void Logger::log(Level level, const T& log)
5579 {
5580  base::threading::ScopedLock scopedLock(lock());
5581  log_(level, 0, log);
5582 }
5583 # if ELPP_VERBOSE_LOG
5584 template <typename T, typename... Args>
5585 inline void Logger::verbose(int vlevel, const char* s, const T& value, const Args& ... args)
5586 {
5587  base::threading::ScopedLock scopedLock(lock());
5588  log_(el::Level::Verbose, vlevel, s, value, args...);
5589 }
5590 template <typename T>
5591 inline void Logger::verbose(int vlevel, const T& log)
5592 {
5593  base::threading::ScopedLock scopedLock(lock());
5594  log_(el::Level::Verbose, vlevel, log);
5595 }
5596 # else
5597 template <typename T, typename... Args>
5598 inline void Logger::verbose(int, const char*, const T&, const Args& ...)
5599 {
5600  return;
5601 }
5602 template <typename T>
5603 inline void Logger::verbose(int, const T&)
5604 {
5605  return;
5606 }
5607 # endif // ELPP_VERBOSE_LOG
5608 # define LOGGER_LEVEL_WRITERS(FUNCTION_NAME, LOG_LEVEL)\
5609  template <typename T, typename... Args>\
5610  inline void Logger::FUNCTION_NAME(const char* s, const T& value, const Args&... args) {\
5611  log(LOG_LEVEL, s, value, args...);\
5612  }\
5613  template <typename T>\
5614  inline void Logger::FUNCTION_NAME(const T& value) {\
5615  log(LOG_LEVEL, value);\
5616  }
5617 # define LOGGER_LEVEL_WRITERS_DISABLED(FUNCTION_NAME, LOG_LEVEL)\
5618  template <typename T, typename... Args>\
5619  inline void Logger::FUNCTION_NAME(const char*, const T&, const Args&...) {\
5620  return;\
5621  }\
5622  template <typename T>\
5623  inline void Logger::FUNCTION_NAME(const T&) {\
5624  return;\
5625  }
5626 
5627 # if ELPP_INFO_LOG
5628 LOGGER_LEVEL_WRITERS(info, Level::Info)
5629 # else
5630 LOGGER_LEVEL_WRITERS_DISABLED(info, Level::Info)
5631 # endif // ELPP_INFO_LOG
5632 # if ELPP_DEBUG_LOG
5633 LOGGER_LEVEL_WRITERS(debug, Level::Debug)
5634 # else
5635 LOGGER_LEVEL_WRITERS_DISABLED(debug, Level::Debug)
5636 # endif // ELPP_DEBUG_LOG
5637 # if ELPP_WARNING_LOG
5638 LOGGER_LEVEL_WRITERS(warn, Level::Warning)
5639 # else
5640 LOGGER_LEVEL_WRITERS_DISABLED(warn, Level::Warning)
5641 # endif // ELPP_WARNING_LOG
5642 # if ELPP_ERROR_LOG
5643 LOGGER_LEVEL_WRITERS(error, Level::Error)
5644 # else
5645 LOGGER_LEVEL_WRITERS_DISABLED(error, Level::Error)
5646 # endif // ELPP_ERROR_LOG
5647 # if ELPP_FATAL_LOG
5648 LOGGER_LEVEL_WRITERS(fatal, Level::Fatal)
5649 # else
5650 LOGGER_LEVEL_WRITERS_DISABLED(fatal, Level::Fatal)
5651 # endif // ELPP_FATAL_LOG
5652 # if ELPP_TRACE_LOG
5653 LOGGER_LEVEL_WRITERS(trace, Level::Trace)
5654 # else
5655 LOGGER_LEVEL_WRITERS_DISABLED(trace, Level::Trace)
5656 # endif // ELPP_TRACE_LOG
5657 # undef LOGGER_LEVEL_WRITERS
5658 # undef LOGGER_LEVEL_WRITERS_DISABLED
5659 #endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
5660 #if ELPP_COMPILER_MSVC
5661 # define ELPP_VARIADIC_FUNC_MSVC(variadicFunction, variadicArgs) variadicFunction variadicArgs
5662 # define ELPP_VARIADIC_FUNC_MSVC_RUN(variadicFunction, ...) ELPP_VARIADIC_FUNC_MSVC(variadicFunction, (__VA_ARGS__))
5663 # define el_getVALength(...) ELPP_VARIADIC_FUNC_MSVC_RUN(el_resolveVALength, 0, ## __VA_ARGS__,\
5664  10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
5665 #else
5666 # if ELPP_COMPILER_CLANG
5667 # define el_getVALength(...) el_resolveVALength(0, __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
5668 # else
5669 # define el_getVALength(...) el_resolveVALength(0, ## __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
5670 # endif // ELPP_COMPILER_CLANG
5671 #endif // ELPP_COMPILER_MSVC
5672 #define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
5673 #define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \
5674  writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
5675 #define ELPP_WRITE_LOG_IF(writer, condition, level, dispatchAction, ...) if (condition) \
5676  writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
5677 #define ELPP_WRITE_LOG_EVERY_N(writer, occasion, level, dispatchAction, ...) \
5678  if (ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion)) \
5679  writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
5680 #define ELPP_WRITE_LOG_AFTER_N(writer, n, level, dispatchAction, ...) \
5681  if (ELPP->validateAfterNCounter(__FILE__, __LINE__, n)) \
5682  writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
5683 #define ELPP_WRITE_LOG_N_TIMES(writer, n, level, dispatchAction, ...) \
5684  if (ELPP->validateNTimesCounter(__FILE__, __LINE__, n)) \
5685  writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
5686 #undef ELPP_CURR_FILE_PERFORMANCE_LOGGER
5687 #if defined(ELPP_PERFORMANCE_LOGGER)
5688 # define ELPP_CURR_FILE_PERFORMANCE_LOGGER ELPP_PERFORMANCE_LOGGER
5689 #else
5690 # define ELPP_CURR_FILE_PERFORMANCE_LOGGER el::base::consts::kPerformanceLoggerId
5691 #endif
5692 class PerformanceTrackingData
5693 {
5694 public:
5695  enum class DataType : base::type::EnumType {
5696  Checkpoint = 1, Complete = 2
5697  };
5698  // Do not use constructor, will run into multiple definition error, use init(PerformanceTracker*)
5699  explicit PerformanceTrackingData(DataType dataType) : m_performanceTracker(nullptr),
5700  m_dataType(dataType), m_file(""), m_line(0), m_func("") {}
5701  inline const std::string* blockName(void) const;
5702  inline const struct timeval* startTime(void) const;
5703  inline const struct timeval* endTime(void) const;
5704  inline const struct timeval* lastCheckpointTime(void) const;
5705  inline const base::PerformanceTracker* performanceTracker(void) const { return m_performanceTracker; }
5706  inline PerformanceTrackingData::DataType dataType(void) const { return m_dataType; }
5707  inline bool firstCheckpoint(void) const { return m_firstCheckpoint; }
5708  inline std::string checkpointId(void) const { return m_checkpointId; }
5709  inline const char* file(void) const { return m_file; }
5710  inline unsigned long int line(void) const { return m_line; }
5711  inline const char* func(void) const { return m_func; }
5712  inline const base::type::string_t* formattedTimeTaken() const { return &m_formattedTimeTaken; }
5713  inline const std::string& loggerId(void) const;
5714 private:
5715  base::PerformanceTracker* m_performanceTracker;
5716  base::type::string_t m_formattedTimeTaken;
5717  PerformanceTrackingData::DataType m_dataType;
5718  bool m_firstCheckpoint;
5719  std::string m_checkpointId;
5720  const char* m_file;
5721  unsigned long int m_line;
5722  const char* m_func;
5723  inline void init(base::PerformanceTracker* performanceTracker, bool firstCheckpoint = false)
5724  {
5725  m_performanceTracker = performanceTracker;
5726  m_firstCheckpoint = firstCheckpoint;
5727  }
5728 
5729  friend class el::base::PerformanceTracker;
5730 };
5731 namespace base {
5734 class PerformanceTracker : public base::threading::ThreadSafe, public Loggable
5735 {
5736 public:
5737  PerformanceTracker(const std::string& blockName,
5738  base::TimestampUnit timestampUnit = base::TimestampUnit::Millisecond,
5739  const std::string& loggerId = std::string(ELPP_CURR_FILE_PERFORMANCE_LOGGER),
5740  bool scopedLog = true, Level level = base::consts::kPerformanceTrackerDefaultLevel) :
5741  m_blockName(blockName), m_timestampUnit(timestampUnit), m_loggerId(loggerId), m_scopedLog(scopedLog),
5742  m_level(level), m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false)
5743  {
5744 #if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
5745  // We store it locally so that if user happen to change configuration by the end of scope
5746  // or before calling checkpoint, we still depend on state of configuraton at time of construction
5747  el::Logger* loggerPtr = ELPP->registeredLoggers()->get(loggerId, false);
5748  m_enabled = loggerPtr != nullptr && loggerPtr->m_typedConfigurations->performanceTracking(m_level);
5749  if (m_enabled) {
5750  base::utils::DateTime::gettimeofday(&m_startTime);
5751  }
5752 #endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
5753  }
5755  PerformanceTracker(const PerformanceTracker& t) :
5756  m_blockName(t.m_blockName), m_timestampUnit(t.m_timestampUnit), m_loggerId(t.m_loggerId), m_scopedLog(t.m_scopedLog),
5757  m_level(t.m_level), m_hasChecked(t.m_hasChecked), m_lastCheckpointId(t.m_lastCheckpointId), m_enabled(t.m_enabled),
5758  m_startTime(t.m_startTime), m_endTime(t.m_endTime), m_lastCheckpointTime(t.m_lastCheckpointTime)
5759  {
5760  }
5761  virtual ~PerformanceTracker(void)
5762  {
5763 #if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
5764  if (m_enabled) {
5765  base::threading::ScopedLock scopedLock(lock());
5766  if (m_scopedLog) {
5767  base::utils::DateTime::gettimeofday(&m_endTime);
5768  base::type::string_t formattedTime = getFormattedTimeTaken();
5769  PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete);
5770  data.init(this);
5771  data.m_formattedTimeTaken = formattedTime;
5772  PerformanceTrackingCallback* callback = nullptr;
5773  for (const std::pair<std::string, base::type::PerformanceTrackingCallbackPtr>& h
5774  : ELPP->m_performanceTrackingCallbacks) {
5775  callback = h.second.get();
5776  if (callback != nullptr && callback->enabled()) {
5777  callback->acquireLock();
5778  callback->handle(&data);
5779  callback->releaseLock();
5780  }
5781  }
5782  }
5783  }
5784 #endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING)
5785  }
5787  void checkpoint(const std::string& id = std::string(), const char* file = __FILE__, unsigned long int line = __LINE__, const char* func = "")
5788  {
5789 #if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
5790  if (m_enabled) {
5791  base::threading::ScopedLock scopedLock(lock());
5792  base::utils::DateTime::gettimeofday(&m_endTime);
5793  base::type::string_t formattedTime = m_hasChecked ? getFormattedTimeTaken(m_lastCheckpointTime) : ELPP_LITERAL("");
5794  PerformanceTrackingData data(PerformanceTrackingData::DataType::Checkpoint);
5795  data.init(this);
5796  data.m_checkpointId = id;
5797  data.m_file = file;
5798  data.m_line = line;
5799  data.m_func = func;
5800  data.m_formattedTimeTaken = formattedTime;
5801  PerformanceTrackingCallback* callback = nullptr;
5802  for (const std::pair<std::string, base::type::PerformanceTrackingCallbackPtr>& h
5803  : ELPP->m_performanceTrackingCallbacks) {
5804  callback = h.second.get();
5805  if (callback != nullptr && callback->enabled()) {
5806  callback->acquireLock();
5807  callback->handle(&data);
5808  callback->releaseLock();
5809  }
5810  }
5811  base::utils::DateTime::gettimeofday(&m_lastCheckpointTime);
5812  m_hasChecked = true;
5813  m_lastCheckpointId = id;
5814  }
5815 #endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
5816  ELPP_UNUSED(id);
5817  ELPP_UNUSED(file);
5818  ELPP_UNUSED(line);
5819  ELPP_UNUSED(func);
5820  }
5821  inline Level level(void) const { return m_level; }
5822 private:
5823  std::string m_blockName;
5824  base::TimestampUnit m_timestampUnit;
5825  std::string m_loggerId;
5826  bool m_scopedLog;
5827  Level m_level;
5828  bool m_hasChecked;
5829  std::string m_lastCheckpointId;
5830  bool m_enabled;
5831  struct timeval m_startTime, m_endTime, m_lastCheckpointTime;
5832 
5833  PerformanceTracker(void);
5834 
5835  friend class el::PerformanceTrackingData;
5836  friend class base::DefaultPerformanceTrackingCallback;
5837 
5838  const inline base::type::string_t getFormattedTimeTaken() const
5839  {
5840  return getFormattedTimeTaken(m_startTime);
5841  }
5842 
5843  const base::type::string_t getFormattedTimeTaken(struct timeval startTime) const
5844  {
5845  if (ELPP->hasFlag(LoggingFlag::FixedTimeFormat)) {
5846  base::type::stringstream_t ss;
5847  ss << base::utils::DateTime::getTimeDifference(m_endTime,
5848  startTime, m_timestampUnit) << " " << base::consts::kTimeFormats[static_cast<base::type::EnumType>(m_timestampUnit)].unit;
5849  return ss.str();
5850  }
5851  return base::utils::DateTime::formatTime(base::utils::DateTime::getTimeDifference(m_endTime,
5852  startTime, m_timestampUnit), m_timestampUnit);
5853  }
5854 
5855  virtual inline void log(el::base::type::ostream_t& os) const
5856  {
5857  os << getFormattedTimeTaken();
5858  }
5859 };
5860 class DefaultPerformanceTrackingCallback : public PerformanceTrackingCallback
5861 {
5862 protected:
5863  void handle(const PerformanceTrackingData* data)
5864  {
5865  m_data = data;
5866  base::type::stringstream_t ss;
5867  if (m_data->dataType() == PerformanceTrackingData::DataType::Complete) {
5868  ss << ELPP_LITERAL("Executed [") << m_data->blockName()->c_str() << ELPP_LITERAL("] in [") << *m_data->formattedTimeTaken() << ELPP_LITERAL("]");
5869  } else {
5870  ss << ELPP_LITERAL("Performance checkpoint");
5871  if (!m_data->checkpointId().empty()) {
5872  ss << ELPP_LITERAL(" [") << m_data->checkpointId().c_str() << ELPP_LITERAL("]");
5873  }
5874  ss << ELPP_LITERAL(" for block [") << m_data->blockName()->c_str() << ELPP_LITERAL("] : [") << *m_data->performanceTracker();
5875  if (!ELPP->hasFlag(LoggingFlag::DisablePerformanceTrackingCheckpointComparison) && m_data->performanceTracker()->m_hasChecked) {
5876  ss << ELPP_LITERAL(" ([") << *m_data->formattedTimeTaken() << ELPP_LITERAL("] from ");
5877  if (m_data->performanceTracker()->m_lastCheckpointId.empty()) {
5878  ss << ELPP_LITERAL("last checkpoint");
5879  } else {
5880  ss << ELPP_LITERAL("checkpoint '") << m_data->performanceTracker()->m_lastCheckpointId.c_str() << ELPP_LITERAL("'");
5881  }
5882  ss << ELPP_LITERAL(")]");
5883  } else {
5884  ss << ELPP_LITERAL("]");
5885  }
5886  }
5887  el::base::Writer(m_data->performanceTracker()->level(), m_data->file(), m_data->line(), m_data->func()).construct(1, m_data->loggerId().c_str()) << ss.str();
5888  }
5889 private:
5890  const PerformanceTrackingData* m_data;
5891 };
5892 } // namespace base
5893 inline const std::string* PerformanceTrackingData::blockName() const
5894 {
5895  return const_cast<const std::string*>(&m_performanceTracker->m_blockName);
5896 }
5897 inline const struct timeval* PerformanceTrackingData::startTime() const {
5898  return const_cast<const struct timeval*>(&m_performanceTracker->m_startTime);
5899 }
5900 inline const struct timeval* PerformanceTrackingData::endTime() const {
5901  return const_cast<const struct timeval*>(&m_performanceTracker->m_endTime);
5902 }
5903 inline const struct timeval* PerformanceTrackingData::lastCheckpointTime() const {
5904  return const_cast<const struct timeval*>(&m_performanceTracker->m_lastCheckpointTime);
5905 }
5906 inline const std::string& PerformanceTrackingData::loggerId(void) const { return m_performanceTracker->m_loggerId; }
5907 namespace base {
5909 namespace debug {
5910 class StackTrace : base::NoCopy
5911 {
5912 public:
5913  static const std::size_t kMaxStack = 64;
5914  static const std::size_t kStackStart = 2; // We want to skip c'tor and StackTrace::generateNew()
5915  class StackTraceEntry
5916  {
5917  public:
5918  StackTraceEntry(std::size_t index, const char* loc, const char* demang, const char* hex, const char* addr)
5919  {
5920  m_index = index;
5921  m_location = std::string(loc);
5922  m_demangled = std::string(demang);
5923  m_hex = std::string(hex);
5924  m_addr = std::string(addr);
5925  }
5926  StackTraceEntry(std::size_t index, char* loc)
5927  {
5928  m_index = index;
5929  m_location = std::string(loc);
5930  }
5931  std::size_t m_index;
5932  std::string m_location;
5933  std::string m_demangled;
5934  std::string m_hex;
5935  std::string m_addr;
5936  friend std::ostream& operator<<(std::ostream& ss, const StackTraceEntry& si)
5937  {
5938  ss << "[" << si.m_index << "] " << si.m_location << (si.m_demangled.empty() ? "" : ":") << si.m_demangled
5939  << (si.m_hex.empty() ? "" : "+") << si.m_hex << si.m_addr;
5940  return ss;
5941  }
5942 
5943  private:
5944  StackTraceEntry(void);
5945  };
5946 
5947  StackTrace(void)
5948  {
5949  generateNew();
5950  }
5951 
5952  virtual ~StackTrace(void)
5953  {
5954  }
5955 
5956  inline std::vector<StackTraceEntry>& getLatestStack(void)
5957  {
5958  return m_stack;
5959  }
5960 
5961  friend inline std::ostream& operator<<(std::ostream& os, const StackTrace& st)
5962  {
5963  std::vector<StackTraceEntry>::const_iterator it = st.m_stack.begin();
5964  while (it != st.m_stack.end()) {
5965  os << " " << *it++ << "\n";
5966  }
5967  return os;
5968  }
5969 
5970 private:
5971  std::vector<StackTraceEntry> m_stack;
5972 
5973  void generateNew(void)
5974  {
5975 #if ELPP_STACKTRACE
5976  m_stack.clear();
5977  void* stack[kMaxStack];
5978  std::size_t size = backtrace(stack, kMaxStack);
5979  char** strings = backtrace_symbols(stack, size);
5980  if (size > kStackStart) { // Skip StackTrace c'tor and generateNew
5981  for (std::size_t i = kStackStart; i < size; ++i) {
5982  char* mangName = nullptr;
5983  char* hex = nullptr;
5984  char* addr = nullptr;
5985  for (char* c = strings[i]; *c; ++c) {
5986  switch (*c) {
5987  case '(':
5988  mangName = c;
5989  break;
5990  case '+':
5991  hex = c;
5992  break;
5993  case ')':
5994  addr = c;
5995  break;
5996  }
5997  }
5998  // Perform demangling if parsed properly
5999  if (mangName != nullptr && hex != nullptr && addr != nullptr && mangName < hex) {
6000  *mangName++ = '\0';
6001  *hex++ = '\0';
6002  *addr++ = '\0';
6003  int status = 0;
6004  char* demangName = abi::__cxa_demangle(mangName, 0, 0, &status);
6005  // if demangling is successful, output the demangled function name
6006  if (status == 0) {
6007  // Success (see http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html)
6008  StackTraceEntry entry(i - 1, strings[i], demangName, hex, addr);
6009  m_stack.push_back(entry);
6010  } else {
6011  // Not successful - we will use mangled name
6012  StackTraceEntry entry(i - 1, strings[i], mangName, hex, addr);
6013  m_stack.push_back(entry);
6014  }
6015  free(demangName);
6016  } else {
6017  StackTraceEntry entry(i - 1, strings[i]);
6018  m_stack.push_back(entry);
6019  }
6020  }
6021  }
6022  free(strings);
6023 #else
6024  ELPP_INTERNAL_INFO(1, "Stacktrace generation not supported for selected compiler");
6025 #endif // ELPP_STACKTRACE
6026  }
6027 };
6028 static std::string crashReason(int sig)
6029 {
6030  std::stringstream ss;
6031  bool foundReason = false;
6032  for (int i = 0; i < base::consts::kCrashSignalsCount; ++i) {
6033  if (base::consts::kCrashSignals[i].numb == sig) {
6034  ss << "Application has crashed due to [" << base::consts::kCrashSignals[i].name << "] signal";
6035  if (ELPP->hasFlag(el::LoggingFlag::LogDetailedCrashReason)) {
6036  ss << std::endl <<
6037  " " << base::consts::kCrashSignals[i].brief << std::endl <<
6038  " " << base::consts::kCrashSignals[i].detail;
6039  }
6040  foundReason = true;
6041  }
6042  }
6043  if (!foundReason) {
6044  ss << "Application has crashed due to unknown signal [" << sig << "]";
6045  }
6046  return ss.str();
6047 }
6049 static void logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger)
6050 {
6051  std::stringstream ss;
6052  ss << "CRASH HANDLED; ";
6053  ss << crashReason(sig);
6054 #if ELPP_STACKTRACE
6055  if (stackTraceIfAvailable) {
6056  ss << std::endl << " ======= Backtrace: =========" << std::endl << base::debug::StackTrace();
6057  }
6058 #else
6059  ELPP_UNUSED(stackTraceIfAvailable);
6060 #endif // ELPP_STACKTRACE
6061  ELPP_WRITE_LOG(el::base::Writer, level, base::DispatchAction::NormalLog, logger) << ss.str();
6062 }
6063 static inline void crashAbort(int sig)
6064 {
6065  base::utils::abort(sig);
6066 }
6070 static inline void defaultCrashHandler(int sig)
6071 {
6072  base::debug::logCrashReason(sig, true, Level::Fatal, base::consts::kDefaultLoggerId);
6073  base::debug::crashAbort(sig);
6074 }
6076 class CrashHandler : base::NoCopy
6077 {
6078 public:
6079  typedef void (*Handler)(int);
6080 
6081  explicit CrashHandler(bool useDefault)
6082  {
6083  if (useDefault) {
6084  setHandler(defaultCrashHandler);
6085  }
6086  }
6087  explicit CrashHandler(const Handler& cHandler)
6088  {
6089  setHandler(cHandler);
6090  }
6091  void setHandler(const Handler& cHandler)
6092  {
6093  m_handler = cHandler;
6094 #if defined(ELPP_HANDLE_SIGABRT)
6095  int i = 0; // SIGABRT is at base::consts::kCrashSignals[0]
6096 #else
6097  int i = 1;
6098 #endif // defined(ELPP_HANDLE_SIGABRT)
6099  for (; i < base::consts::kCrashSignalsCount; ++i) {
6100  m_handler = signal(base::consts::kCrashSignals[i].numb, cHandler);
6101  }
6102  }
6103 
6104 private:
6105  Handler m_handler;
6106 };
6107 } // namespace debug
6108 } // namespace base
6109 extern base::debug::CrashHandler elCrashHandler;
6110 #define MAKE_LOGGABLE(ClassType, ClassInstance, OutputStreamInstance) \
6111  el::base::type::ostream_t& operator<<(el::base::type::ostream_t& OutputStreamInstance, const ClassType& ClassInstance)
6112 class SysLogInitializer
6114 {
6115 public:
6116  SysLogInitializer(const char* processIdent, int options = 0, int facility = 0)
6117  {
6118 #if defined(ELPP_SYSLOG)
6119  openlog(processIdent, options, facility);
6120 #else
6121  ELPP_UNUSED(processIdent);
6122  ELPP_UNUSED(options);
6123  ELPP_UNUSED(facility);
6124 #endif // defined(ELPP_SYSLOG)
6125  }
6126  virtual ~SysLogInitializer(void)
6127  {
6128 #if defined(ELPP_SYSLOG)
6129  closelog();
6130 #endif // defined(ELPP_SYSLOG)
6131  }
6132 };
6133 #define ELPP_INITIALIZE_SYSLOG(id, opt, fac) el::SysLogInitializer elSyslogInit(id, opt, fac)
6134 class Helpers : base::StaticClass
6136 {
6137 public:
6139  static inline void setStorage(base::type::StoragePointer storage)
6140  {
6141  ELPP = storage;
6142  }
6144  static inline base::type::StoragePointer storage()
6145  {
6146  return ELPP;
6147  }
6149  static inline void setArgs(int argc, char** argv)
6150  {
6151  ELPP->setApplicationArguments(argc, argv);
6152  }
6154  static inline void setArgs(int argc, const char** argv)
6155  {
6156  ELPP->setApplicationArguments(argc, const_cast<char**>(argv));
6157  }
6161  static inline void setCrashHandler(const el::base::debug::CrashHandler::Handler& crashHandler)
6162  {
6163  el::elCrashHandler.setHandler(crashHandler);
6164  }
6167  static inline void crashAbort(int sig, const char* sourceFile = "", unsigned int long line = 0)
6168  {
6169  std::stringstream ss;
6170  ss << base::debug::crashReason(sig).c_str();
6171  ss << " - [Called el::Helpers::crashAbort(" << sig << ")]";
6172  if (sourceFile != nullptr && strlen(sourceFile) > 0) {
6173  ss << " - Source: " << sourceFile;
6174  if (line > 0)
6175  ss << ":" << line;
6176  else
6177  ss << " (line number not specified)";
6178  }
6179  base::utils::abort(sig, ss.str());
6180  }
6186  static inline void logCrashReason(int sig, bool stackTraceIfAvailable = false,
6187  Level level = Level::Fatal, const char* logger = base::consts::kDefaultLoggerId)
6188  {
6189  el::base::debug::logCrashReason(sig, stackTraceIfAvailable, level, logger);
6190  }
6193  static inline void installPreRollOutCallback(const PreRollOutCallback& callback)
6194  {
6195  ELPP->setPreRollOutCallback(callback);
6196  }
6198  static inline void uninstallPreRollOutCallback(void)
6199  {
6200  ELPP->unsetPreRollOutCallback();
6201  }
6203  template <typename T>
6204  static inline bool installLogDispatchCallback(const std::string& id)
6205  {
6206  return ELPP->installLogDispatchCallback<T>(id);
6207  }
6209  template <typename T>
6210  static inline void uninstallLogDispatchCallback(const std::string& id)
6211  {
6212  ELPP->uninstallLogDispatchCallback<T>(id);
6213  }
6214  template <typename T>
6215  static inline T* logDispatchCallback(const std::string& id)
6216  {
6217  return ELPP->logDispatchCallback<T>(id);
6218  }
6220  template <typename T>
6221  static inline bool installPerformanceTrackingCallback(const std::string& id)
6222  {
6223  return ELPP->installPerformanceTrackingCallback<T>(id);
6224  }
6226  template <typename T>
6227  static inline void uninstallPerformanceTrackingCallback(const std::string& id)
6228  {
6229  ELPP->uninstallPerformanceTrackingCallback<T>(id);
6230  }
6231  template <typename T>
6232  static inline T* performanceTrackingCallback(const std::string& id)
6233  {
6234  return ELPP->performanceTrackingCallback<T>(id);
6235  }
6237  template <typename T>
6238  static std::string convertTemplateToStdString(const T& templ)
6239  {
6240  el::Logger* logger =
6241  ELPP->registeredLoggers()->get(el::base::consts::kDefaultLoggerId);
6242  if (logger == nullptr) {
6243  return std::string();
6244  }
6245  base::MessageBuilder b;
6246  b.initialize(logger);
6247  logger->acquireLock();
6248  b << templ;
6249 #if defined(ELPP_UNICODE)
6250  std::string s = std::string(logger->stream().str().begin(), logger->stream().str().end());
6251 #else
6252  std::string s = logger->stream().str();
6253 #endif // defined(ELPP_UNICODE)
6254  logger->stream().str(ELPP_LITERAL(""));
6255  logger->releaseLock();
6256  return s;
6257  }
6259  static inline const el::base::utils::CommandLineArgs* commandLineArgs(void)
6260  {
6261  return ELPP->commandLineArgs();
6262  }
6264  static inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier)
6265  {
6266  ELPP->installCustomFormatSpecifier(customFormatSpecifier);
6267  }
6269  static inline bool uninstallCustomFormatSpecifier(const char* formatSpecifier)
6270  {
6271  return ELPP->uninstallCustomFormatSpecifier(formatSpecifier);
6272  }
6274  static inline bool hasCustomFormatSpecifier(const char* formatSpecifier)
6275  {
6276  return ELPP->hasCustomFormatSpecifier(formatSpecifier);
6277  }
6278  static inline void validateFileRolling(Logger* logger, Level level)
6279  {
6280  if (logger == nullptr) return;
6281  logger->m_typedConfigurations->validateFileRolling(level, ELPP->preRollOutCallback());
6282  }
6283 };
6285 class Loggers : base::StaticClass
6286 {
6287 public:
6289  static inline Logger* getLogger(const std::string& identity, bool registerIfNotAvailable = true)
6290  {
6291  base::threading::ScopedLock scopedLock(ELPP->lock());
6292  return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable);
6293  }
6296  static inline bool unregisterLogger(const std::string& identity)
6297  {
6298  base::threading::ScopedLock scopedLock(ELPP->lock());
6299  return ELPP->registeredLoggers()->remove(identity);
6300  }
6302  static inline bool hasLogger(const std::string& identity)
6303  {
6304  base::threading::ScopedLock scopedLock(ELPP->lock());
6305  return ELPP->registeredLoggers()->has(identity);
6306  }
6308  static inline Logger* reconfigureLogger(Logger* logger, const Configurations& configurations)
6309  {
6310  if (!logger) return nullptr;
6311  logger->configure(configurations);
6312  return logger;
6313  }
6315  static inline Logger* reconfigureLogger(const std::string& identity, const Configurations& configurations)
6316  {
6317  return Loggers::reconfigureLogger(Loggers::getLogger(identity), configurations);
6318  }
6320  static inline Logger* reconfigureLogger(const std::string& identity, ConfigurationType configurationType,
6321  const std::string& value)
6322  {
6323  Logger* logger = Loggers::getLogger(identity);
6324  if (logger == nullptr) {
6325  return nullptr;
6326  }
6327  logger->configurations()->set(Level::Global, configurationType, value);
6328  logger->reconfigure();
6329  return logger;
6330  }
6332  static inline void reconfigureAllLoggers(const Configurations& configurations)
6333  {
6334  for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin();
6335  it != ELPP->registeredLoggers()->end(); ++it) {
6336  Loggers::reconfigureLogger(it->second, configurations);
6337  }
6338  }
6340  static inline void reconfigureAllLoggers(ConfigurationType configurationType, const std::string& value)
6341  {
6342  reconfigureAllLoggers(Level::Global, configurationType, value);
6343  }
6345  static inline void reconfigureAllLoggers(Level level, ConfigurationType configurationType,
6346  const std::string& value)
6347  {
6348  for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin();
6349  it != ELPP->registeredLoggers()->end(); ++it) {
6350  Logger* logger = it->second;
6351  logger->configurations()->set(level, configurationType, value);
6352  logger->reconfigure();
6353  }
6354  }
6356  static inline void setDefaultConfigurations(const Configurations& configurations, bool reconfigureExistingLoggers = false)
6357  {
6358  ELPP->registeredLoggers()->setDefaultConfigurations(configurations);
6359  if (reconfigureExistingLoggers) {
6360  Loggers::reconfigureAllLoggers(configurations);
6361  }
6362  }
6364  static inline const Configurations* defaultConfigurations(void)
6365  {
6366  return ELPP->registeredLoggers()->defaultConfigurations();
6367  }
6369  static inline const base::LogStreamsReferenceMap* logStreamsReference(void)
6370  {
6371  return ELPP->registeredLoggers()->logStreamsReference();
6372  }
6374  static base::TypedConfigurations defaultTypedConfigurations(void)
6375  {
6376  return base::TypedConfigurations(
6377  ELPP->registeredLoggers()->defaultConfigurations(),
6378  ELPP->registeredLoggers()->logStreamsReference());
6379  }
6382  static inline std::vector<std::string>* populateAllLoggerIds(std::vector<std::string>* targetList)
6383  {
6384  targetList->clear();
6385  for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->list().begin();
6386  it != ELPP->registeredLoggers()->list().end(); ++it) {
6387  targetList->push_back(it->first);
6388  }
6389  return targetList;
6390  }
6392  static void configureFromGlobal(const char* globalConfigurationFilePath)
6393  {
6394  std::ifstream gcfStream(globalConfigurationFilePath, std::ifstream::in);
6395  ELPP_ASSERT(gcfStream.is_open(), "Unable to open global configuration file [" << globalConfigurationFilePath
6396  << "] for parsing.");
6397  std::string line = std::string();
6398  std::stringstream ss;
6399  Logger* logger = nullptr;
6400  auto configure = [&](void) {
6401  ELPP_INTERNAL_INFO(8, "Configuring logger: '" << logger->id() << "' with configurations \n" << ss.str()
6402  << "\n--------------");
6403  Configurations c;
6404  c.parseFromText(ss.str());
6405  logger->configure(c);
6406  };
6407  while (gcfStream.good()) {
6408  std::getline(gcfStream, line);
6409  ELPP_INTERNAL_INFO(1, "Parsing line: " << line);
6410  base::utils::Str::trim(line);
6411  if (Configurations::Parser::isComment(line)) continue;
6412  Configurations::Parser::ignoreComments(&line);
6413  base::utils::Str::trim(line);
6414  if (line.size() > 2 && base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLoggerId))) {
6415  if (!ss.str().empty() && logger != nullptr) {
6416  configure();
6417  }
6418  ss.str(std::string(""));
6419  line = line.substr(2);
6420  base::utils::Str::trim(line);
6421  if (line.size() > 1) {
6422  ELPP_INTERNAL_INFO(1, "Getting logger: '" << line << "'");
6423  logger = getLogger(line);
6424  }
6425  } else {
6426  ss << line << "\n";
6427  }
6428  }
6429  if (!ss.str().empty() && logger != nullptr) {
6430  configure();
6431  }
6432  }
6437  static inline bool configureFromArg(const char* argKey)
6438  {
6439 #if defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS)
6440  ELPP_UNUSED(argKey);
6441 #else
6442  if (!Helpers::commandLineArgs()->hasParamWithValue(argKey)) {
6443  return false;
6444  }
6445  configureFromGlobal(Helpers::commandLineArgs()->getParamValue(argKey));
6446 #endif // defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS)
6447  return true;
6448  }
6450  static inline void flushAll(void)
6451  {
6452  ELPP->registeredLoggers()->flushAll();
6453  }
6455  static inline void addFlag(LoggingFlag flag)
6456  {
6457  ELPP->addFlag(flag);
6458  }
6460  static inline void removeFlag(LoggingFlag flag)
6461  {
6462  ELPP->removeFlag(flag);
6463  }
6465  static inline bool hasFlag(LoggingFlag flag)
6466  {
6467  return ELPP->hasFlag(flag);
6468  }
6470  class ScopedAddFlag
6471  {
6472  public:
6473  ScopedAddFlag(LoggingFlag flag) : m_flag(flag) { Loggers::addFlag(m_flag); }
6474  ~ScopedAddFlag(void) { Loggers::removeFlag(m_flag); }
6475  private:
6476  LoggingFlag m_flag;
6477  };
6479  class ScopedRemoveFlag
6480  {
6481  public:
6482  ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) { Loggers::removeFlag(m_flag); }
6483  ~ScopedRemoveFlag(void) { Loggers::addFlag(m_flag); }
6484  private:
6485  LoggingFlag m_flag;
6486  };
6488  static inline void setLoggingLevel(Level level)
6489  {
6490  ELPP->setLoggingLevel(level);
6491  }
6493  static inline void setVerboseLevel(base::type::VerboseLevel level)
6494  {
6495  ELPP->vRegistry()->setLevel(level);
6496  }
6498  static inline base::type::VerboseLevel verboseLevel(void)
6499  {
6500  return ELPP->vRegistry()->level();
6501  }
6503  static inline void setVModules(const char* modules)
6504  {
6505  if (ELPP->vRegistry()->vModulesEnabled()) {
6506  ELPP->vRegistry()->setModules(modules);
6507  }
6508  }
6510  static inline void clearVModules(void)
6511  {
6512  ELPP->vRegistry()->clearModules();
6513  }
6514 };
6515 class VersionInfo : base::StaticClass
6516 {
6517 public:
6519  static inline const std::string version(void) { return std::string("9.80"); }
6521  static inline const std::string releaseDate(void) { return std::string("08-01-2015 0850hrs"); }
6522 };
6523 } // namespace el
6524 #undef VLOG_IS_ON
6525 #define VLOG_IS_ON(verboseLevel) (ELPP->vRegistry()->allowed(verboseLevel, __FILE__))
6527 #undef TIMED_BLOCK
6528 #undef TIMED_SCOPE
6529 #undef TIMED_FUNC
6530 #undef ELPP_MIN_UNIT
6531 #if defined(ELPP_PERFORMANCE_MICROSECONDS)
6532 # define ELPP_MIN_UNIT el::base::TimestampUnit::Microsecond
6533 #else
6534 # define ELPP_MIN_UNIT el::base::TimestampUnit::Millisecond
6535 #endif // (defined(ELPP_PERFORMANCE_MICROSECONDS))
6536 // Note: Do not surround this definition with null macro because of obj instance
6543 #define TIMED_SCOPE(obj, blockname) el::base::PerformanceTracker obj(blockname, ELPP_MIN_UNIT)
6544 #define TIMED_BLOCK(obj, blockName) for (struct { int i; el::base::PerformanceTracker timer; } obj = { 0, \
6545  el::base::PerformanceTracker(blockName, ELPP_MIN_UNIT) }; obj.i < 1; ++obj.i)
6546 #define TIMED_FUNC(obj) TIMED_SCOPE(obj, ELPP_FUNC)
6553 #undef PERFORMANCE_CHECKPOINT
6554 #undef PERFORMANCE_CHECKPOINT_WITH_ID
6555 #define PERFORMANCE_CHECKPOINT(obj) obj.checkpoint(std::string(), __FILE__, __LINE__, ELPP_FUNC)
6556 #define PERFORMANCE_CHECKPOINT_WITH_ID(obj, id) obj.checkpoint(id, __FILE__, __LINE__, ELPP_FUNC)
6557 #undef ELPP_COUNTER
6558 #undef ELPP_COUNTER_POS
6559 #define ELPP_COUNTER (ELPP->hitCounters()->getCounter(__FILE__, __LINE__))
6561 #define ELPP_COUNTER_POS (ELPP_COUNTER == nullptr ? -1 : ELPP_COUNTER->hitCounts())
6563 // Undef levels to support LOG(LEVEL)
6564 #undef INFO
6565 #undef WARNING
6566 #undef DEBUG
6567 #undef ERROR
6568 #undef FATAL
6569 #undef TRACE
6570 #undef VERBOSE
6571 // Undef existing
6572 #undef CINFO
6573 #undef CWARNING
6574 #undef CDEBUG
6575 #undef CFATAL
6576 #undef CERROR
6577 #undef CTRACE
6578 #undef CVERBOSE
6579 #undef CINFO_IF
6580 #undef CWARNING_IF
6581 #undef CDEBUG_IF
6582 #undef CERROR_IF
6583 #undef CFATAL_IF
6584 #undef CTRACE_IF
6585 #undef CVERBOSE_IF
6586 #undef CINFO_EVERY_N
6587 #undef CWARNING_EVERY_N
6588 #undef CDEBUG_EVERY_N
6589 #undef CERROR_EVERY_N
6590 #undef CFATAL_EVERY_N
6591 #undef CTRACE_EVERY_N
6592 #undef CVERBOSE_EVERY_N
6593 #undef CINFO_AFTER_N
6594 #undef CWARNING_AFTER_N
6595 #undef CDEBUG_AFTER_N
6596 #undef CERROR_AFTER_N
6597 #undef CFATAL_AFTER_N
6598 #undef CTRACE_AFTER_N
6599 #undef CVERBOSE_AFTER_N
6600 #undef CINFO_N_TIMES
6601 #undef CWARNING_N_TIMES
6602 #undef CDEBUG_N_TIMES
6603 #undef CERROR_N_TIMES
6604 #undef CFATAL_N_TIMES
6605 #undef CTRACE_N_TIMES
6606 #undef CVERBOSE_N_TIMES
6607 // Normal logs
6608 #if ELPP_INFO_LOG
6609 # define CINFO(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Info, dispatchAction, __VA_ARGS__)
6610 #else
6611 # define CINFO(writer, dispatchAction, ...) el::base::NullWriter()
6612 #endif // ELPP_INFO_LOG
6613 #if ELPP_WARNING_LOG
6614 # define CWARNING(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Warning, dispatchAction, __VA_ARGS__)
6615 #else
6616 # define CWARNING(writer, dispatchAction, ...) el::base::NullWriter()
6617 #endif // ELPP_WARNING_LOG
6618 #if ELPP_DEBUG_LOG
6619 # define CDEBUG(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__)
6620 #else
6621 # define CDEBUG(writer, dispatchAction, ...) el::base::NullWriter()
6622 #endif // ELPP_DEBUG_LOG
6623 #if ELPP_ERROR_LOG
6624 # define CERROR(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Error, dispatchAction, __VA_ARGS__)
6625 #else
6626 # define CERROR(writer, dispatchAction, ...) el::base::NullWriter()
6627 #endif // ELPP_ERROR_LOG
6628 #if ELPP_FATAL_LOG
6629 # define CFATAL(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Fatal, dispatchAction, __VA_ARGS__)
6630 #else
6631 # define CFATAL(writer, dispatchAction, ...) el::base::NullWriter()
6632 #endif // ELPP_FATAL_LOG
6633 #if ELPP_TRACE_LOG
6634 # define CTRACE(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Trace, dispatchAction, __VA_ARGS__)
6635 #else
6636 # define CTRACE(writer, dispatchAction, ...) el::base::NullWriter()
6637 #endif // ELPP_TRACE_LOG
6638 #if ELPP_VERBOSE_LOG
6639 # define CVERBOSE(writer, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel)) writer(\
6640  el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
6641 #else
6642 # define CVERBOSE(writer, vlevel, dispatchAction, ...) el::base::NullWriter()
6643 #endif // ELPP_VERBOSE_LOG
6644 // Conditional logs
6645 #if ELPP_INFO_LOG
6646 # define CINFO_IF(writer, condition_, dispatchAction, ...) \
6647  ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Info, dispatchAction, __VA_ARGS__)
6648 #else
6649 # define CINFO_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
6650 #endif // ELPP_INFO_LOG
6651 #if ELPP_WARNING_LOG
6652 # define CWARNING_IF(writer, condition_, dispatchAction, ...)\
6653  ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Warning, dispatchAction, __VA_ARGS__)
6654 #else
6655 # define CWARNING_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
6656 #endif // ELPP_WARNING_LOG
6657 #if ELPP_DEBUG_LOG
6658 # define CDEBUG_IF(writer, condition_, dispatchAction, ...)\
6659  ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Debug, dispatchAction, __VA_ARGS__)
6660 #else
6661 # define CDEBUG_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
6662 #endif // ELPP_DEBUG_LOG
6663 #if ELPP_ERROR_LOG
6664 # define CERROR_IF(writer, condition_, dispatchAction, ...)\
6665  ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Error, dispatchAction, __VA_ARGS__)
6666 #else
6667 # define CERROR_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
6668 #endif // ELPP_ERROR_LOG
6669 #if ELPP_FATAL_LOG
6670 # define CFATAL_IF(writer, condition_, dispatchAction, ...)\
6671  ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Fatal, dispatchAction, __VA_ARGS__)
6672 #else
6673 # define CFATAL_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
6674 #endif // ELPP_FATAL_LOG
6675 #if ELPP_TRACE_LOG
6676 # define CTRACE_IF(writer, condition_, dispatchAction, ...)\
6677  ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Trace, dispatchAction, __VA_ARGS__)
6678 #else
6679 # define CTRACE_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
6680 #endif // ELPP_TRACE_LOG
6681 #if ELPP_VERBOSE_LOG
6682 # define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel) && (condition_)) writer( \
6683  el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
6684 #else
6685 # define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) el::base::NullWriter()
6686 #endif // ELPP_VERBOSE_LOG
6687 // Occasional logs
6688 #if ELPP_INFO_LOG
6689 # define CINFO_EVERY_N(writer, occasion, dispatchAction, ...)\
6690  ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Info, dispatchAction, __VA_ARGS__)
6691 #else
6692 # define CINFO_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
6693 #endif // ELPP_INFO_LOG
6694 #if ELPP_WARNING_LOG
6695 # define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...)\
6696  ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Warning, dispatchAction, __VA_ARGS__)
6697 #else
6698 # define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
6699 #endif // ELPP_WARNING_LOG
6700 #if ELPP_DEBUG_LOG
6701 # define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...)\
6702  ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Debug, dispatchAction, __VA_ARGS__)
6703 #else
6704 # define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
6705 #endif // ELPP_DEBUG_LOG
6706 #if ELPP_ERROR_LOG
6707 # define CERROR_EVERY_N(writer, occasion, dispatchAction, ...)\
6708  ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Error, dispatchAction, __VA_ARGS__)
6709 #else
6710 # define CERROR_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
6711 #endif // ELPP_ERROR_LOG
6712 #if ELPP_FATAL_LOG
6713 # define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...)\
6714  ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Fatal, dispatchAction, __VA_ARGS__)
6715 #else
6716 # define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
6717 #endif // ELPP_FATAL_LOG
6718 #if ELPP_TRACE_LOG
6719 # define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...)\
6720  ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Trace, dispatchAction, __VA_ARGS__)
6721 #else
6722 # define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
6723 #endif // ELPP_TRACE_LOG
6724 #if ELPP_VERBOSE_LOG
6725 # define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...)\
6726  CVERBOSE_IF(writer, ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion), vlevel, dispatchAction, __VA_ARGS__)
6727 #else
6728 # define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...) el::base::NullWriter()
6729 #endif // ELPP_VERBOSE_LOG
6730 // After N logs
6731 #if ELPP_INFO_LOG
6732 # define CINFO_AFTER_N(writer, n, dispatchAction, ...)\
6733  ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)
6734 #else
6735 # define CINFO_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
6736 #endif // ELPP_INFO_LOG
6737 #if ELPP_WARNING_LOG
6738 # define CWARNING_AFTER_N(writer, n, dispatchAction, ...)\
6739  ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)
6740 #else
6741 # define CWARNING_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
6742 #endif // ELPP_WARNING_LOG
6743 #if ELPP_DEBUG_LOG
6744 # define CDEBUG_AFTER_N(writer, n, dispatchAction, ...)\
6745  ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)
6746 #else
6747 # define CDEBUG_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
6748 #endif // ELPP_DEBUG_LOG
6749 #if ELPP_ERROR_LOG
6750 # define CERROR_AFTER_N(writer, n, dispatchAction, ...)\
6751  ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)
6752 #else
6753 # define CERROR_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
6754 #endif // ELPP_ERROR_LOG
6755 #if ELPP_FATAL_LOG
6756 # define CFATAL_AFTER_N(writer, n, dispatchAction, ...)\
6757  ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)
6758 #else
6759 # define CFATAL_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
6760 #endif // ELPP_FATAL_LOG
6761 #if ELPP_TRACE_LOG
6762 # define CTRACE_AFTER_N(writer, n, dispatchAction, ...)\
6763  ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)
6764 #else
6765 # define CTRACE_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
6766 #endif // ELPP_TRACE_LOG
6767 #if ELPP_VERBOSE_LOG
6768 # define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...)\
6769  CVERBOSE_IF(writer, ELPP->validateAfterNCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__)
6770 #else
6771 # define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter()
6772 #endif // ELPP_VERBOSE_LOG
6773 // N Times logs
6774 #if ELPP_INFO_LOG
6775 # define CINFO_N_TIMES(writer, n, dispatchAction, ...)\
6776  ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)
6777 #else
6778 # define CINFO_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
6779 #endif // ELPP_INFO_LOG
6780 #if ELPP_WARNING_LOG
6781 # define CWARNING_N_TIMES(writer, n, dispatchAction, ...)\
6782  ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)
6783 #else
6784 # define CWARNING_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
6785 #endif // ELPP_WARNING_LOG
6786 #if ELPP_DEBUG_LOG
6787 # define CDEBUG_N_TIMES(writer, n, dispatchAction, ...)\
6788  ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)
6789 #else
6790 # define CDEBUG_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
6791 #endif // ELPP_DEBUG_LOG
6792 #if ELPP_ERROR_LOG
6793 # define CERROR_N_TIMES(writer, n, dispatchAction, ...)\
6794  ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)
6795 #else
6796 # define CERROR_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
6797 #endif // ELPP_ERROR_LOG
6798 #if ELPP_FATAL_LOG
6799 # define CFATAL_N_TIMES(writer, n, dispatchAction, ...)\
6800  ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)
6801 #else
6802 # define CFATAL_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
6803 #endif // ELPP_FATAL_LOG
6804 #if ELPP_TRACE_LOG
6805 # define CTRACE_N_TIMES(writer, n, dispatchAction, ...)\
6806  ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)
6807 #else
6808 # define CTRACE_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
6809 #endif // ELPP_TRACE_LOG
6810 #if ELPP_VERBOSE_LOG
6811 # define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...)\
6812  CVERBOSE_IF(writer, ELPP->validateNTimesCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__)
6813 #else
6814 # define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter()
6815 #endif // ELPP_VERBOSE_LOG
6816 //
6817 // Custom Loggers - Requires (level, dispatchAction, loggerId/s)
6818 //
6819 // undef existing
6820 #undef CLOG
6821 #undef CLOG_VERBOSE
6822 #undef CVLOG
6823 #undef CLOG_IF
6824 #undef CLOG_VERBOSE_IF
6825 #undef CVLOG_IF
6826 #undef CLOG_EVERY_N
6827 #undef CVLOG_EVERY_N
6828 #undef CLOG_AFTER_N
6829 #undef CVLOG_AFTER_N
6830 #undef CLOG_N_TIMES
6831 #undef CVLOG_N_TIMES
6832 // Normal logs
6833 #define CLOG(LEVEL, ...)\
6834  C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6835 #define CVLOG(vlevel, ...) CVERBOSE(el::base::Writer, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6836 // Conditional logs
6837 #define CLOG_IF(condition, LEVEL, ...)\
6838  C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6839 #define CVLOG_IF(condition, vlevel, ...)\
6840  CVERBOSE_IF(el::base::Writer, condition, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6841 // Hit counts based logs
6842 #define CLOG_EVERY_N(n, LEVEL, ...)\
6843  C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6844 #define CVLOG_EVERY_N(n, vlevel, ...)\
6845  CVERBOSE_EVERY_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6846 #define CLOG_AFTER_N(n, LEVEL, ...)\
6847  C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6848 #define CVLOG_AFTER_N(n, vlevel, ...)\
6849  CVERBOSE_AFTER_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6850 #define CLOG_N_TIMES(n, LEVEL, ...)\
6851  C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6852 #define CVLOG_N_TIMES(n, vlevel, ...)\
6853  CVERBOSE_N_TIMES(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6854 //
6855 // Default Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros
6856 //
6857 // undef existing
6858 #undef LOG
6859 #undef VLOG
6860 #undef LOG_IF
6861 #undef VLOG_IF
6862 #undef LOG_EVERY_N
6863 #undef VLOG_EVERY_N
6864 #undef LOG_AFTER_N
6865 #undef VLOG_AFTER_N
6866 #undef LOG_N_TIMES
6867 #undef VLOG_N_TIMES
6868 #undef ELPP_CURR_FILE_LOGGER_ID
6869 #if defined(ELPP_DEFAULT_LOGGER)
6870 # define ELPP_CURR_FILE_LOGGER_ID ELPP_DEFAULT_LOGGER
6871 #else
6872 # define ELPP_CURR_FILE_LOGGER_ID el::base::consts::kDefaultLoggerId
6873 #endif
6874 #undef ELPP_TRACE
6875 #define ELPP_TRACE CLOG(TRACE, ELPP_CURR_FILE_LOGGER_ID)
6876 // Normal logs
6877 #define LOG(LEVEL) CLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
6878 #define VLOG(vlevel) CVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID)
6879 // Conditional logs
6880 #define LOG_IF(condition, LEVEL) CLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
6881 #define VLOG_IF(condition, vlevel) CVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID)
6882 // Hit counts based logs
6883 #define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
6884 #define VLOG_EVERY_N(n, vlevel) CVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
6885 #define LOG_AFTER_N(n, LEVEL) CLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
6886 #define VLOG_AFTER_N(n, vlevel) CVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
6887 #define LOG_N_TIMES(n, LEVEL) CLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
6888 #define VLOG_N_TIMES(n, vlevel) CVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
6889 // Generic PLOG()
6890 #undef CPLOG
6891 #undef CPLOG_IF
6892 #undef PLOG
6893 #undef PLOG_IF
6894 #undef DCPLOG
6895 #undef DCPLOG_IF
6896 #undef DPLOG
6897 #undef DPLOG_IF
6898 #define CPLOG(LEVEL, ...)\
6899  C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6900 #define CPLOG_IF(condition, LEVEL, ...)\
6901  C##LEVEL##_IF(el::base::PErrorWriter, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6902 #define DCPLOG(LEVEL, ...)\
6903  if (ELPP_DEBUG_LOG) C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__)
6904 #define DCPLOG_IF(condition, LEVEL, ...)\
6905  C##LEVEL##_IF(el::base::PErrorWriter, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::NormalLog, __VA_ARGS__)
6906 #define PLOG(LEVEL) CPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
6907 #define PLOG_IF(condition, LEVEL) CPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
6908 #define DPLOG(LEVEL) DCPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
6909 #define DPLOG_IF(condition, LEVEL) DCPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
6910 // Generic SYSLOG()
6911 #undef CSYSLOG
6912 #undef CSYSLOG_IF
6913 #undef CSYSLOG_EVERY_N
6914 #undef CSYSLOG_AFTER_N
6915 #undef CSYSLOG_N_TIMES
6916 #undef SYSLOG
6917 #undef SYSLOG_IF
6918 #undef SYSLOG_EVERY_N
6919 #undef SYSLOG_AFTER_N
6920 #undef SYSLOG_N_TIMES
6921 #undef DCSYSLOG
6922 #undef DCSYSLOG_IF
6923 #undef DCSYSLOG_EVERY_N
6924 #undef DCSYSLOG_AFTER_N
6925 #undef DCSYSLOG_N_TIMES
6926 #undef DSYSLOG
6927 #undef DSYSLOG_IF
6928 #undef DSYSLOG_EVERY_N
6929 #undef DSYSLOG_AFTER_N
6930 #undef DSYSLOG_N_TIMES
6931 #if defined(ELPP_SYSLOG)
6932 # define CSYSLOG(LEVEL, ...)\
6933  C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__)
6934 # define CSYSLOG_IF(condition, LEVEL, ...)\
6935  C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::SysLog, __VA_ARGS__)
6936 # define CSYSLOG_EVERY_N(n, LEVEL, ...) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
6937 # define CSYSLOG_AFTER_N(n, LEVEL, ...) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
6938 # define CSYSLOG_N_TIMES(n, LEVEL, ...) C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
6939 # define SYSLOG(LEVEL) CSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId)
6940 # define SYSLOG_IF(condition, LEVEL) CSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId)
6941 # define SYSLOG_EVERY_N(n, LEVEL) CSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
6942 # define SYSLOG_AFTER_N(n, LEVEL) CSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
6943 # define SYSLOG_N_TIMES(n, LEVEL) CSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId)
6944 # define DCSYSLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__)
6945 # define DCSYSLOG_IF(condition, LEVEL, ...)\
6946  C##LEVEL##_IF(el::base::Writer, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::SysLog, __VA_ARGS__)
6947 # define DCSYSLOG_EVERY_N(n, LEVEL, ...)\
6948  if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
6949 # define DCSYSLOG_AFTER_N(n, LEVEL, ...)\
6950  if (ELPP_DEBUG_LOG) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
6951 # define DCSYSLOG_N_TIMES(n, LEVEL, ...)\
6952  if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
6953 # define DSYSLOG(LEVEL) DCSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId)
6954 # define DSYSLOG_IF(condition, LEVEL) DCSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId)
6955 # define DSYSLOG_EVERY_N(n, LEVEL) DCSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
6956 # define DSYSLOG_AFTER_N(n, LEVEL) DCSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
6957 # define DSYSLOG_N_TIMES(n, LEVEL) DCSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId)
6958 #else
6959 # define CSYSLOG(LEVEL, ...) el::base::NullWriter()
6960 # define CSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter()
6961 # define CSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter()
6962 # define CSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter()
6963 # define CSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter()
6964 # define SYSLOG(LEVEL) el::base::NullWriter()
6965 # define SYSLOG_IF(condition, LEVEL) el::base::NullWriter()
6966 # define SYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter()
6967 # define SYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter()
6968 # define SYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter()
6969 # define DCSYSLOG(LEVEL, ...) el::base::NullWriter()
6970 # define DCSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter()
6971 # define DCSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter()
6972 # define DCSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter()
6973 # define DCSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter()
6974 # define DSYSLOG(LEVEL) el::base::NullWriter()
6975 # define DSYSLOG_IF(condition, LEVEL) el::base::NullWriter()
6976 # define DSYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter()
6977 # define DSYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter()
6978 # define DSYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter()
6979 #endif // defined(ELPP_SYSLOG)
6980 //
6981 // Custom Debug Only Loggers - Requires (level, loggerId/s)
6982 //
6983 // undef existing
6984 #undef DCLOG
6985 #undef DCVLOG
6986 #undef DCLOG_IF
6987 #undef DCVLOG_IF
6988 #undef DCLOG_EVERY_N
6989 #undef DCVLOG_EVERY_N
6990 #undef DCLOG_AFTER_N
6991 #undef DCVLOG_AFTER_N
6992 #undef DCLOG_N_TIMES
6993 #undef DCVLOG_N_TIMES
6994 // Normal logs
6995 #define DCLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG(LEVEL, __VA_ARGS__)
6996 #define DCLOG_VERBOSE(vlevel, ...) if (ELPP_DEBUG_LOG) CLOG_VERBOSE(vlevel, __VA_ARGS__)
6997 #define DCVLOG(vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG(vlevel, __VA_ARGS__)
6998 // Conditional logs
6999 #define DCLOG_IF(condition, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_IF(condition, LEVEL, __VA_ARGS__)
7000 #define DCVLOG_IF(condition, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_IF(condition, vlevel, __VA_ARGS__)
7001 // Hit counts based logs
7002 #define DCLOG_EVERY_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_EVERY_N(n, LEVEL, __VA_ARGS__)
7003 #define DCVLOG_EVERY_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_EVERY_N(n, vlevel, __VA_ARGS__)
7004 #define DCLOG_AFTER_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_AFTER_N(n, LEVEL, __VA_ARGS__)
7005 #define DCVLOG_AFTER_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_AFTER_N(n, vlevel, __VA_ARGS__)
7006 #define DCLOG_N_TIMES(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_N_TIMES(n, LEVEL, __VA_ARGS__)
7007 #define DCVLOG_N_TIMES(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_N_TIMES(n, vlevel, __VA_ARGS__)
7008 //
7009 // Default Debug Only Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros
7010 //
7011 // undef existing
7012 #undef DLOG
7013 #undef DVLOG
7014 #undef DLOG_IF
7015 #undef DVLOG_IF
7016 #undef DLOG_EVERY_N
7017 #undef DVLOG_EVERY_N
7018 #undef DLOG_AFTER_N
7019 #undef DVLOG_AFTER_N
7020 #undef DLOG_N_TIMES
7021 #undef DVLOG_N_TIMES
7022 // Normal logs
7023 #define DLOG(LEVEL) DCLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
7024 #define DVLOG(vlevel) DCVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID)
7025 // Conditional logs
7026 #define DLOG_IF(condition, LEVEL) DCLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
7027 #define DVLOG_IF(condition, vlevel) DCVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID)
7028 // Hit counts based logs
7029 #define DLOG_EVERY_N(n, LEVEL) DCLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
7030 #define DVLOG_EVERY_N(n, vlevel) DCVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
7031 #define DLOG_AFTER_N(n, LEVEL) DCLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
7032 #define DVLOG_AFTER_N(n, vlevel) DCVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
7033 #define DLOG_N_TIMES(n, LEVEL) DCLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
7034 #define DVLOG_N_TIMES(n, vlevel) DCVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
7035 // Check macros
7036 #undef CCHECK
7037 #undef CPCHECK
7038 #undef CCHECK_EQ
7039 #undef CCHECK_NE
7040 #undef CCHECK_LT
7041 #undef CCHECK_GT
7042 #undef CCHECK_LE
7043 #undef CCHECK_GE
7044 #undef CCHECK_BOUNDS
7045 #undef CCHECK_NOTNULL
7046 #undef CCHECK_STRCASEEQ
7047 #undef CCHECK_STRCASENE
7048 #undef CHECK
7049 #undef PCHECK
7050 #undef CHECK_EQ
7051 #undef CHECK_NE
7052 #undef CHECK_LT
7053 #undef CHECK_GT
7054 #undef CHECK_LE
7055 #undef CHECK_GE
7056 #undef CHECK_BOUNDS
7057 #undef CHECK_NOTNULL
7058 #undef CHECK_STRCASEEQ
7059 #undef CHECK_STRCASENE
7060 #define CCHECK(condition, ...) CLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] "
7061 #define CPCHECK(condition, ...) CPLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] "
7062 #define CHECK(condition) CCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
7063 #define PCHECK(condition) CPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
7064 #define CCHECK_EQ(a, b, ...) CCHECK(a == b, __VA_ARGS__)
7065 #define CCHECK_NE(a, b, ...) CCHECK(a != b, __VA_ARGS__)
7066 #define CCHECK_LT(a, b, ...) CCHECK(a < b, __VA_ARGS__)
7067 #define CCHECK_GT(a, b, ...) CCHECK(a > b, __VA_ARGS__)
7068 #define CCHECK_LE(a, b, ...) CCHECK(a <= b, __VA_ARGS__)
7069 #define CCHECK_GE(a, b, ...) CCHECK(a >= b, __VA_ARGS__)
7070 #define CCHECK_BOUNDS(val, min, max, ...) CCHECK(val >= min && val <= max, __VA_ARGS__)
7071 #define CHECK_EQ(a, b) CCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID)
7072 #define CHECK_NE(a, b) CCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID)
7073 #define CHECK_LT(a, b) CCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID)
7074 #define CHECK_GT(a, b) CCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID)
7075 #define CHECK_LE(a, b) CCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID)
7076 #define CHECK_GE(a, b) CCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID)
7077 #define CHECK_BOUNDS(val, min, max) CCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID)
7078 namespace el {
7079 namespace base {
7080 namespace utils {
7081 template <typename T>
7082 static T* checkNotNull(T* ptr, const char* name, const char* loggers, ...)
7083 {
7084  CLOG_IF(ptr == nullptr, FATAL, loggers) << "Check failed: [" << name << " != nullptr]";
7085  return ptr;
7086 }
7087 } // namespace utils
7088 } // namespace base
7089 } // namespace el
7090 #define CCHECK_NOTNULL(ptr, ...) el::base::utils::checkNotNull(ptr, #ptr, __VA_ARGS__)
7091 #define CCHECK_STREQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \
7092  << "Check failed: [" << #str1 << " == " << #str2 << "] "
7093 #define CCHECK_STRNE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \
7094  << "Check failed: [" << #str1 << " != " << #str2 << "] "
7095 #define CCHECK_STRCASEEQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \
7096  << "Check failed: [" << #str1 << " == " << #str2 << "] "
7097 #define CCHECK_STRCASENE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \
7098  << "Check failed: [" << #str1 << " != " << #str2 << "] "
7099 #define CHECK_NOTNULL(ptr) CCHECK_NOTNULL(ptr, ELPP_CURR_FILE_LOGGER_ID)
7100 #define CHECK_STREQ(str1, str2) CCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
7101 #define CHECK_STRNE(str1, str2) CCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
7102 #define CHECK_STRCASEEQ(str1, str2) CCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
7103 #define CHECK_STRCASENE(str1, str2) CCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
7104 #undef DCCHECK
7105 #undef DCCHECK_EQ
7106 #undef DCCHECK_NE
7107 #undef DCCHECK_LT
7108 #undef DCCHECK_GT
7109 #undef DCCHECK_LE
7110 #undef DCCHECK_GE
7111 #undef DCCHECK_BOUNDS
7112 #undef DCCHECK_NOTNULL
7113 #undef DCCHECK_STRCASEEQ
7114 #undef DCCHECK_STRCASENE
7115 #undef DCPCHECK
7116 #undef DCHECK
7117 #undef DCHECK_EQ
7118 #undef DCHECK_NE
7119 #undef DCHECK_LT
7120 #undef DCHECK_GT
7121 #undef DCHECK_LE
7122 #undef DCHECK_GE
7123 #undef DCHECK_BOUNDS_
7124 #undef DCHECK_NOTNULL
7125 #undef DCHECK_STRCASEEQ
7126 #undef DCHECK_STRCASENE
7127 #undef DPCHECK
7128 #define DCCHECK(condition, ...) if (ELPP_DEBUG_LOG) CCHECK(condition, __VA_ARGS__)
7129 #define DCCHECK_EQ(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_EQ(a, b, __VA_ARGS__)
7130 #define DCCHECK_NE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_NE(a, b, __VA_ARGS__)
7131 #define DCCHECK_LT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LT(a, b, __VA_ARGS__)
7132 #define DCCHECK_GT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GT(a, b, __VA_ARGS__)
7133 #define DCCHECK_LE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LE(a, b, __VA_ARGS__)
7134 #define DCCHECK_GE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GE(a, b, __VA_ARGS__)
7135 #define DCCHECK_BOUNDS(val, min, max, ...) if (ELPP_DEBUG_LOG) CCHECK_BOUNDS(val, min, max, __VA_ARGS__)
7136 #define DCCHECK_NOTNULL(ptr, ...) if (ELPP_DEBUG_LOG) CCHECK_NOTNULL(ptr, __VA_ARGS__)
7137 #define DCCHECK_STREQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STREQ(str1, str2, __VA_ARGS__)
7138 #define DCCHECK_STRNE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRNE(str1, str2, __VA_ARGS__)
7139 #define DCCHECK_STRCASEEQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASEEQ(str1, str2, __VA_ARGS__)
7140 #define DCCHECK_STRCASENE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASENE(str1, str2, __VA_ARGS__)
7141 #define DCPCHECK(condition, ...) if (ELPP_DEBUG_LOG) CPCHECK(condition, __VA_ARGS__)
7142 #define DCHECK(condition) DCCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
7143 #define DCHECK_EQ(a, b) DCCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID)
7144 #define DCHECK_NE(a, b) DCCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID)
7145 #define DCHECK_LT(a, b) DCCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID)
7146 #define DCHECK_GT(a, b) DCCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID)
7147 #define DCHECK_LE(a, b) DCCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID)
7148 #define DCHECK_GE(a, b) DCCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID)
7149 #define DCHECK_BOUNDS(val, min, max) DCCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID)
7150 #define DCHECK_NOTNULL(ptr) DCCHECK_NOTNULL(ptr, ELPP_CURR_FILE_LOGGER_ID)
7151 #define DCHECK_STREQ(str1, str2) DCCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
7152 #define DCHECK_STRNE(str1, str2) DCCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
7153 #define DCHECK_STRCASEEQ(str1, str2) DCCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
7154 #define DCHECK_STRCASENE(str1, str2) DCCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
7155 #define DPCHECK(condition) DCPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
7156 #if defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING)
7157 # define ELPP_USE_DEF_CRASH_HANDLER false
7158 #else
7159 # define ELPP_USE_DEF_CRASH_HANDLER true
7160 #endif // defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING)
7161 #define ELPP_CRASH_HANDLER_INIT
7162 #define ELPP_INIT_EASYLOGGINGPP(val)\
7163  ELPP_INITI_BASIC_DECLR\
7164  namespace el {\
7165  namespace base {\
7166  el::base::type::StoragePointer elStorage(val);\
7167  }\
7168  el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\
7169  }
7170 
7171 #if ELPP_ASYNC_LOGGING
7172 # define INITIALIZE_EASYLOGGINGPP\
7173  ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()),\
7174  new el::base::AsyncDispatchWorker()))\
7175 
7176 #else
7177 # define INITIALIZE_EASYLOGGINGPP\
7178  ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder())))
7179 #endif // ELPP_ASYNC_LOGGING
7180 #define INITIALIZE_NULL_EASYLOGGINGPP\
7181  ELPP_INITI_BASIC_DECLR\
7182  namespace el {\
7183  namespace base {\
7184  el::base::type::StoragePointer elStorage;\
7185  }\
7186  el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\
7187  }
7188 // NOTE: no ELPP_INITI_BASIC_DECLR when sharing - causes double free corruption on external symbols
7189 #define SHARE_EASYLOGGINGPP(initializedStorage)\
7190  namespace el {\
7191  namespace base {\
7192  el::base::type::StoragePointer elStorage(initializedStorage);\
7193  }\
7194  el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\
7195  }
7196 
7197 #if defined(ELPP_UNICODE)
7198 # define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv); std::locale::global(std::locale(""))
7199 #else
7200 # define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv)
7201 #endif // defined(ELPP_UNICODE)
7202 #endif // EASYLOGGINGPP_H
bool contains(InputIt1 first_haystack, InputIt1 last_haystack, InputIt2 first_needle, InputIt2 last_needle, BinaryPredicate p)
Definition: container_utils.h:49
bool operator==(const CachedValue::Status &S, const CalculationStatus &s)
equality operator for checking the CalculationStatus
Definition: CachedValue.h:153
bool operator!=(const CachedValue::Status &S, const CalculationStatus &s)
inequality operator for checking the CalculationStatus
Definition: CachedValue.h:157
const size_t size(const ParameterVector &V)
Definition: Parameter.h:283
std::ostream & operator<<(std::ostream &os, const DecayChannel &dc)
<< operator
Definition: DecayChannel.h:127
const CoordinateSystem< T, N > unit(const CoordinateSystem< T, N > &C)
Definition: CoordinateSystem.h:52
const T trace(const SquareMatrix< T, N > &M)
trace
Definition: Matrix.h:340