CompilerSysY/include/3rdparty/easylogging++.h
2023-05-01 23:52:06 +08:00

5038 lines
195 KiB
C++

//
// Bismillah ar-Rahmaan ar-Raheem
//
// Easylogging++ v9.96.7
// Single-header only, cross-platform logging library for C++ applications
//
// Copyright (c) 2012-2018 Amrayn Web Services
// Copyright (c) 2012-2018 @abumusamq
//
// This library is released under the MIT Licence.
// https://github.com/amrayn/easyloggingpp/blob/master/LICENSE
//
// https://amrayn.com
// http://muflihun.com
//
#ifndef EASYLOGGINGPP_H
#define EASYLOGGINGPP_H
// Compilers and C++0x/C++11 Evaluation
#if __cplusplus >= 201103L
#define ELPP_CXX11 1
#endif // __cplusplus >= 201103L
#if (defined(__GNUC__))
#define ELPP_COMPILER_GCC 1
#else
#define ELPP_COMPILER_GCC 0
#endif
#if ELPP_COMPILER_GCC
#define ELPP_GCC_VERSION \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#if defined(__GXX_EXPERIMENTAL_CXX0X__)
#define ELPP_CXX0X 1
#endif
#endif
// Visual C++
#if defined(_MSC_VER)
#define ELPP_COMPILER_MSVC 1
#else
#define ELPP_COMPILER_MSVC 0
#endif
#define ELPP_CRT_DBG_WARNINGS ELPP_COMPILER_MSVC
#if ELPP_COMPILER_MSVC
#if (_MSC_VER == 1600)
#define ELPP_CXX0X 1
#elif (_MSC_VER >= 1700)
#define ELPP_CXX11 1
#endif
#endif
// Clang++
#if (defined(__clang__) && (__clang__ == 1))
#define ELPP_COMPILER_CLANG 1
#else
#define ELPP_COMPILER_CLANG 0
#endif
#if ELPP_COMPILER_CLANG
#if __has_include(<thread>)
#include <cstddef> // Make __GLIBCXX__ defined when using libstdc++
#if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426
#define ELPP_CLANG_SUPPORTS_THREAD
#endif // !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426
#endif // __has_include(<thread>)
#endif
#if (defined(__MINGW32__) || defined(__MINGW64__))
#define ELPP_MINGW 1
#else
#define ELPP_MINGW 0
#endif
#if (defined(__CYGWIN__) && (__CYGWIN__ == 1))
#define ELPP_CYGWIN 1
#else
#define ELPP_CYGWIN 0
#endif
#if (defined(__INTEL_COMPILER))
#define ELPP_COMPILER_INTEL 1
#else
#define ELPP_COMPILER_INTEL 0
#endif
// Operating System Evaluation
// Windows
#if (defined(_WIN32) || defined(_WIN64))
#define ELPP_OS_WINDOWS 1
#else
#define ELPP_OS_WINDOWS 0
#endif
// Linux
#if (defined(__linux) || defined(__linux__))
#define ELPP_OS_LINUX 1
#else
#define ELPP_OS_LINUX 0
#endif
#if (defined(__APPLE__))
#define ELPP_OS_MAC 1
#else
#define ELPP_OS_MAC 0
#endif
#if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
#define ELPP_OS_FREEBSD 1
#else
#define ELPP_OS_FREEBSD 0
#endif
#if (defined(__sun))
#define ELPP_OS_SOLARIS 1
#else
#define ELPP_OS_SOLARIS 0
#endif
#if (defined(_AIX))
#define ELPP_OS_AIX 1
#else
#define ELPP_OS_AIX 0
#endif
#if (defined(__NetBSD__))
#define ELPP_OS_NETBSD 1
#else
#define ELPP_OS_NETBSD 0
#endif
#if defined(__EMSCRIPTEN__)
#define ELPP_OS_EMSCRIPTEN 1
#else
#define ELPP_OS_EMSCRIPTEN 0
#endif
#if (defined(__QNX__) || defined(__QNXNTO__))
#define ELPP_OS_QNX 1
#else
#define ELPP_OS_QNX 0
#endif
// Unix
#if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_NETBSD || \
ELPP_OS_SOLARIS || ELPP_OS_AIX || ELPP_OS_EMSCRIPTEN || ELPP_OS_QNX) && \
(!ELPP_OS_WINDOWS))
#define ELPP_OS_UNIX 1
#else
#define ELPP_OS_UNIX 0
#endif
#if (defined(__ANDROID__))
#define ELPP_OS_ANDROID 1
#else
#define ELPP_OS_ANDROID 0
#endif
// Evaluating Cygwin as *nix OS
#if !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN
#undef ELPP_OS_UNIX
#undef ELPP_OS_LINUX
#define ELPP_OS_UNIX 1
#define ELPP_OS_LINUX 1
#endif // !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN
#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_INFO)
#define ELPP_INTERNAL_DEBUGGING_OUT_INFO std::cout
#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_ERROR)
#define ELPP_INTERNAL_DEBUGGING_OUT_ERROR std::cerr
#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
#if !defined(ELPP_INTERNAL_DEBUGGING_ENDL)
#define ELPP_INTERNAL_DEBUGGING_ENDL std::endl
#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
#if !defined(ELPP_INTERNAL_DEBUGGING_MSG)
#define ELPP_INTERNAL_DEBUGGING_MSG(msg) msg
#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
// Internal Assertions and errors
#if !defined(ELPP_DISABLE_ASSERT)
#if (defined(ELPP_DEBUG_ASSERT_FAILURE))
#define ELPP_ASSERT(expr, msg) \
if (!(expr)) { \
std::stringstream internalInfoStream; \
internalInfoStream << msg; \
ELPP_INTERNAL_DEBUGGING_OUT_ERROR \
<< "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr \
<< "] WITH MESSAGE \"" \
<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" \
<< ELPP_INTERNAL_DEBUGGING_ENDL; \
base::utils::abort( \
1, "ELPP Assertion failure, please define ELPP_DEBUG_ASSERT_FAILURE"); \
}
#else
#define ELPP_ASSERT(expr, msg) \
if (!(expr)) { \
std::stringstream internalInfoStream; \
internalInfoStream << msg; \
ELPP_INTERNAL_DEBUGGING_OUT_ERROR \
<< "ASSERTION FAILURE FROM EASYLOGGING++ (LINE: " << __LINE__ \
<< ") [" #expr << "] WITH MESSAGE \"" \
<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" \
<< ELPP_INTERNAL_DEBUGGING_ENDL; \
}
#endif // (defined(ELPP_DEBUG_ASSERT_FAILURE))
#else
#define ELPP_ASSERT(x, y)
#endif //(!defined(ELPP_DISABLE_ASSERT)
#if ELPP_COMPILER_MSVC
#define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \
{ \
char buff[256]; \
strerror_s(buff, 256, errno); \
ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << buff << " [" << errno << "]"; \
} \
(void)0
#else
#define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \
ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << strerror(errno) << " [" \
<< errno << "]"; \
(void)0
#endif // ELPP_COMPILER_MSVC
#if defined(ELPP_DEBUG_ERRORS)
#if !defined(ELPP_INTERNAL_ERROR)
#define ELPP_INTERNAL_ERROR(msg, pe) \
{ \
std::stringstream internalInfoStream; \
internalInfoStream << "<ERROR> " << msg; \
ELPP_INTERNAL_DEBUGGING_OUT_ERROR \
<< "ERROR FROM EASYLOGGING++ (LINE: " << __LINE__ << ") " \
<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) \
<< ELPP_INTERNAL_DEBUGGING_ENDL; \
if (pe) { \
ELPP_INTERNAL_DEBUGGING_OUT_ERROR << " "; \
ELPP_INTERNAL_DEBUGGING_WRITE_PERROR; \
} \
} \
(void)0
#endif
#else
#undef ELPP_INTERNAL_INFO
#define ELPP_INTERNAL_ERROR(msg, pe)
#endif // defined(ELPP_DEBUG_ERRORS)
#if (defined(ELPP_DEBUG_INFO))
#if !(defined(ELPP_INTERNAL_INFO_LEVEL))
#define ELPP_INTERNAL_INFO_LEVEL 9
#endif // !(defined(ELPP_INTERNAL_INFO_LEVEL))
#if !defined(ELPP_INTERNAL_INFO)
#define ELPP_INTERNAL_INFO(lvl, msg) \
{ \
if (lvl <= ELPP_INTERNAL_INFO_LEVEL) { \
std::stringstream internalInfoStream; \
internalInfoStream << "<INFO> " << msg; \
ELPP_INTERNAL_DEBUGGING_OUT_INFO \
<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) \
<< ELPP_INTERNAL_DEBUGGING_ENDL; \
} \
}
#endif
#else
#undef ELPP_INTERNAL_INFO
#define ELPP_INTERNAL_INFO(lvl, msg)
#endif // (defined(ELPP_DEBUG_INFO))
#if (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG))
#if (ELPP_COMPILER_GCC && !ELPP_MINGW && !ELPP_CYGWIN && !ELPP_OS_ANDROID && \
!ELPP_OS_EMSCRIPTEN && !ELPP_OS_QNX)
#define ELPP_STACKTRACE 1
#else
#if ELPP_COMPILER_MSVC
#pragma message("Stack trace not available for this compiler")
#else
#warning "Stack trace not available for this compiler";
#endif // ELPP_COMPILER_MSVC
#define ELPP_STACKTRACE 0
#endif // ELPP_COMPILER_GCC
#else
#define ELPP_STACKTRACE 0
#endif // (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG))
// Miscellaneous macros
#define ELPP_UNUSED(x) (void)x
#if ELPP_OS_UNIX
// Log file permissions for unix-based systems
#define ELPP_LOG_PERMS \
S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH
#endif // ELPP_OS_UNIX
#if defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC
#if defined(ELPP_EXPORT_SYMBOLS)
#define ELPP_EXPORT __declspec(dllexport)
#else
#define ELPP_EXPORT __declspec(dllimport)
#endif // defined(ELPP_EXPORT_SYMBOLS)
#else
#define ELPP_EXPORT
#endif // defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC
// Some special functions that are VC++ specific
#undef STRTOK
#undef STRERROR
#undef STRCAT
#undef STRCPY
#if ELPP_CRT_DBG_WARNINGS
#define STRTOK(a, b, c) strtok_s(a, b, c)
#define STRERROR(a, b, c) strerror_s(a, b, c)
#define STRCAT(a, b, len) strcat_s(a, len, b)
#define STRCPY(a, b, len) strcpy_s(a, len, b)
#else
#define STRTOK(a, b, c) strtok(a, b)
#define STRERROR(a, b, c) strerror(c)
#define STRCAT(a, b, len) strcat(a, b)
#define STRCPY(a, b, len) strcpy(a, b)
#endif
// Compiler specific support evaluations
#if (ELPP_MINGW && !defined(ELPP_FORCE_USE_STD_THREAD))
#define ELPP_USE_STD_THREADING 0
#else
#if ((ELPP_COMPILER_CLANG && defined(ELPP_CLANG_SUPPORTS_THREAD)) || \
(!ELPP_COMPILER_CLANG && defined(ELPP_CXX11)) || \
defined(ELPP_FORCE_USE_STD_THREAD))
#define ELPP_USE_STD_THREADING 1
#else
#define ELPP_USE_STD_THREADING 0
#endif
#endif
#undef ELPP_FINAL
#if ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702)
#define ELPP_FINAL
#else
#define ELPP_FINAL final
#endif // ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702)
#if defined(ELPP_EXPERIMENTAL_ASYNC)
#define ELPP_ASYNC_LOGGING 1
#else
#define ELPP_ASYNC_LOGGING 0
#endif // defined(ELPP_EXPERIMENTAL_ASYNC)
#if defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING
#define ELPP_THREADING_ENABLED 1
#else
#define ELPP_THREADING_ENABLED 0
#endif // defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING
// Function macro ELPP_FUNC
#undef ELPP_FUNC
#if ELPP_COMPILER_MSVC // Visual C++
#define ELPP_FUNC __FUNCSIG__
#elif ELPP_COMPILER_GCC // GCC
#define ELPP_FUNC __PRETTY_FUNCTION__
#elif ELPP_COMPILER_INTEL // Intel C++
#define ELPP_FUNC __PRETTY_FUNCTION__
#elif ELPP_COMPILER_CLANG // Clang++
#define ELPP_FUNC __PRETTY_FUNCTION__
#else
#if defined(__func__)
#define ELPP_FUNC __func__
#else
#define ELPP_FUNC ""
#endif // defined(__func__)
#endif // defined(_MSC_VER)
#undef ELPP_VARIADIC_TEMPLATES_SUPPORTED
// Keep following line commented until features are fixed
#define ELPP_VARIADIC_TEMPLATES_SUPPORTED \
(ELPP_COMPILER_GCC || ELPP_COMPILER_CLANG || ELPP_COMPILER_INTEL || \
(ELPP_COMPILER_MSVC && _MSC_VER >= 1800))
// Logging Enable/Disable macros
#if defined(ELPP_DISABLE_LOGS)
#define ELPP_LOGGING_ENABLED 0
#else
#define ELPP_LOGGING_ENABLED 1
#endif
#if (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED))
#define ELPP_DEBUG_LOG 1
#else
#define ELPP_DEBUG_LOG 0
#endif // (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED))
#if (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))
#define ELPP_INFO_LOG 1
#else
#define ELPP_INFO_LOG 0
#endif // (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))
#if (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))
#define ELPP_WARNING_LOG 1
#else
#define ELPP_WARNING_LOG 0
#endif // (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))
#if (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))
#define ELPP_ERROR_LOG 1
#else
#define ELPP_ERROR_LOG 0
#endif // (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))
#if (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))
#define ELPP_FATAL_LOG 1
#else
#define ELPP_FATAL_LOG 0
#endif // (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))
#if (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))
#define ELPP_TRACE_LOG 1
#else
#define ELPP_TRACE_LOG 0
#endif // (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))
#if (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED))
#define ELPP_VERBOSE_LOG 1
#else
#define ELPP_VERBOSE_LOG 0
#endif // (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED))
#if (!(ELPP_CXX0X || ELPP_CXX11))
#error "C++0x (or higher) support not detected! (Is `-std=c++11' missing?)"
#endif // (!(ELPP_CXX0X || ELPP_CXX11))
// Headers
#if defined(ELPP_SYSLOG)
#include <syslog.h>
#endif // defined(ELPP_SYSLOG)
#include <cctype>
#include <cerrno>
#include <csignal>
#include <cstdarg>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cwchar>
#if defined(ELPP_UNICODE)
#include <locale>
#if ELPP_OS_WINDOWS
#include <codecvt>
#endif // ELPP_OS_WINDOWS
#endif // defined(ELPP_UNICODE)
#ifdef HAVE_EXECINFO
#include <cxxabi.h>
#include <execinfo.h>
#endif // ENABLE_EXECINFO
#if ELPP_OS_ANDROID
#include <sys/system_properties.h>
#endif // ELPP_OS_ANDROID
#if ELPP_OS_UNIX
#include <sys/stat.h>
#include <sys/time.h>
#elif ELPP_OS_WINDOWS
#include <direct.h>
#include <windows.h>
#if defined(WIN32_LEAN_AND_MEAN)
#if defined(ELPP_WINSOCK2)
#include <winsock2.h>
#else
#include <winsock.h>
#endif // defined(ELPP_WINSOCK2)
#endif // defined(WIN32_LEAN_AND_MEAN)
#endif // ELPP_OS_UNIX
#include <algorithm>
#include <fstream>
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
#if ELPP_THREADING_ENABLED
#if ELPP_USE_STD_THREADING
#include <mutex>
#include <thread>
#else
#if ELPP_OS_UNIX
#include <pthread.h>
#endif // ELPP_OS_UNIX
#endif // ELPP_USE_STD_THREADING
#endif // ELPP_THREADING_ENABLED
#if ELPP_ASYNC_LOGGING
#if defined(ELPP_NO_SLEEP_FOR)
#include <unistd.h>
#endif // defined(ELPP_NO_SLEEP_FOR)
#include <condition_variable>
#include <queue>
#include <thread>
#endif // ELPP_ASYNC_LOGGING
#if defined(ELPP_STL_LOGGING)
// For logging STL based templates
#include <bitset>
#include <deque>
#include <list>
#include <queue>
#include <set>
#include <stack>
#if defined(ELPP_LOG_STD_ARRAY)
#include <array>
#endif // defined(ELPP_LOG_STD_ARRAY)
#if defined(ELPP_LOG_UNORDERED_SET)
#include <unordered_set>
#endif // defined(ELPP_UNORDERED_SET)
#endif // defined(ELPP_STL_LOGGING)
#if defined(ELPP_QT_LOGGING)
// For logging Qt based classes & templates
#include <QByteArray>
#include <QHash>
#include <QLinkedList>
#include <QList>
#include <QMap>
#include <QMultiHash>
#include <QPair>
#include <QQueue>
#include <QSet>
#include <QStack>
#include <QString>
#include <QVector>
#endif // defined(ELPP_QT_LOGGING)
#if defined(ELPP_BOOST_LOGGING)
// For logging boost based classes & templates
#include <boost/container/deque.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
#include <boost/container/list.hpp>
#include <boost/container/map.hpp>
#include <boost/container/set.hpp>
#include <boost/container/stable_vector.hpp>
#include <boost/container/vector.hpp>
#endif // defined(ELPP_BOOST_LOGGING)
#if defined(ELPP_WXWIDGETS_LOGGING)
// For logging wxWidgets based classes & templates
#include <wx/vector.h>
#endif // defined(ELPP_WXWIDGETS_LOGGING)
#if defined(ELPP_UTC_DATETIME)
#define elpptime_r gmtime_r
#define elpptime_s gmtime_s
#define elpptime gmtime
#else
#define elpptime_r localtime_r
#define elpptime_s localtime_s
#define elpptime localtime
#endif // defined(ELPP_UTC_DATETIME)
// Forward declarations
namespace el {
class Logger;
class LogMessage;
class PerformanceTrackingData;
class Loggers;
class Helpers;
template <typename T> class Callback;
class LogDispatchCallback;
class PerformanceTrackingCallback;
class LoggerRegistrationCallback;
class LogDispatchData;
namespace base {
class Storage;
class RegisteredLoggers;
class PerformanceTracker;
class MessageBuilder;
class Writer;
class PErrorWriter;
class LogDispatcher;
class DefaultLogBuilder;
class DefaultLogDispatchCallback;
#if ELPP_ASYNC_LOGGING
class AsyncLogDispatchCallback;
class AsyncDispatchWorker;
#endif // ELPP_ASYNC_LOGGING
class DefaultPerformanceTrackingCallback;
} // namespace base
} // namespace el
/// @brief Easylogging++ entry namespace
namespace el {
/// @brief Namespace containing base/internal functionality used by
/// Easylogging++
namespace base {
/// @brief Data types used by Easylogging++
namespace type {
#undef ELPP_LITERAL
#undef ELPP_STRLEN
#undef ELPP_COUT
#if defined(ELPP_UNICODE)
#define ELPP_LITERAL(txt) L##txt
#define ELPP_STRLEN wcslen
#if defined ELPP_CUSTOM_COUT
#define ELPP_COUT ELPP_CUSTOM_COUT
#else
#define ELPP_COUT std::wcout
#endif // defined ELPP_CUSTOM_COUT
typedef wchar_t char_t;
typedef std::wstring string_t;
typedef std::wstringstream stringstream_t;
typedef std::wfstream fstream_t;
typedef std::wostream ostream_t;
#else
#define ELPP_LITERAL(txt) txt
#define ELPP_STRLEN strlen
#if defined ELPP_CUSTOM_COUT
#define ELPP_COUT ELPP_CUSTOM_COUT
#else
#define ELPP_COUT std::cout
#endif // defined ELPP_CUSTOM_COUT
typedef char char_t;
typedef std::string string_t;
typedef std::stringstream stringstream_t;
typedef std::fstream fstream_t;
typedef std::ostream ostream_t;
#endif // defined(ELPP_UNICODE)
#if defined(ELPP_CUSTOM_COUT_LINE)
#define ELPP_COUT_LINE(logLine) ELPP_CUSTOM_COUT_LINE(logLine)
#else
#define ELPP_COUT_LINE(logLine) logLine << std::flush
#endif // defined(ELPP_CUSTOM_COUT_LINE)
typedef unsigned int EnumType;
typedef unsigned short VerboseLevel;
typedef unsigned long int LineNumber;
typedef std::shared_ptr<base::Storage> StoragePointer;
typedef std::shared_ptr<LogDispatchCallback> LogDispatchCallbackPtr;
typedef std::shared_ptr<PerformanceTrackingCallback>
PerformanceTrackingCallbackPtr;
typedef std::shared_ptr<LoggerRegistrationCallback>
LoggerRegistrationCallbackPtr;
typedef std::unique_ptr<el::base::PerformanceTracker> PerformanceTrackerPtr;
} // namespace type
/// @brief Internal helper class that prevent copy constructor for class
///
/// @detail When using this class simply inherit it privately
class NoCopy {
protected:
NoCopy(void) {}
private:
NoCopy(const NoCopy &);
NoCopy &operator=(const NoCopy &);
};
/// @brief Internal helper class that makes all default constructors private.
///
/// @detail This prevents initializing class making it static unless an explicit
/// constructor is declared. When using this class simply inherit it privately
class StaticClass {
private:
StaticClass(void);
StaticClass(const StaticClass &);
StaticClass &operator=(const StaticClass &);
};
} // namespace base
/// @brief Represents enumeration for severity level used to determine level of
/// logging
///
/// @detail With Easylogging++, developers may disable or enable any level
/// regardless of what the severity is. Or they can choose to log using
/// hierarchical logging flag
enum class Level : base::type::EnumType {
/// @brief Generic level that represents all the levels. Useful when setting
/// global configuration for all levels
Global = 1,
/// @brief Information that can be useful to back-trace certain events -
/// mostly useful than debug logs.
Trace = 2,
/// @brief Informational events most useful for developers to debug
/// application
Debug = 4,
/// @brief Severe error information that will presumably abort application
Fatal = 8,
/// @brief Information representing errors in application but application will
/// keep running
Error = 16,
/// @brief Useful when application has potentially harmful situations
Warning = 32,
/// @brief Information that can be highly useful and vary with verbose logging
/// level.
Verbose = 64,
/// @brief Mainly useful to represent current progress of application
Info = 128,
/// @brief Represents unknown level
Unknown = 1010
};
} // namespace el
namespace std {
template <> struct hash<el::Level> {
public:
std::size_t operator()(const el::Level &l) const {
return hash<el::base::type::EnumType>{}(
static_cast<el::base::type::EnumType>(l));
}
};
} // namespace std
namespace el {
/// @brief Static class that contains helper functions for el::Level
class LevelHelper : base::StaticClass {
public:
/// @brief Represents minimum valid level. Useful when iterating through enum.
static const base::type::EnumType kMinValid =
static_cast<base::type::EnumType>(Level::Trace);
/// @brief Represents maximum valid level. This is used internally and you
/// should not need it.
static const base::type::EnumType kMaxValid =
static_cast<base::type::EnumType>(Level::Info);
/// @brief Casts level to int, useful for iterating through enum.
static base::type::EnumType castToInt(Level level) {
return static_cast<base::type::EnumType>(level);
}
/// @brief Casts int(ushort) to level, useful for iterating through enum.
static Level castFromInt(base::type::EnumType l) {
return static_cast<Level>(l);
}
/// @brief Converts level to associated const char*
/// @return Upper case string based level.
static const char *convertToString(Level level);
/// @brief Converts from levelStr to Level
/// @param levelStr Upper case string based level.
/// Lower case is also valid but providing upper case is recommended.
static Level convertFromString(const char *levelStr);
/// @brief Applies specified function to each level starting from startIndex
/// @param startIndex initial value to start the iteration from. This is
/// passed as pointer and
/// is left-shifted so this can be used inside function (fn) to
/// represent current level.
/// @param fn function to apply with each level. This bool represent whether
/// or not to stop iterating through levels.
static void forEachLevel(base::type::EnumType *startIndex,
const std::function<bool(void)> &fn);
};
/// @brief Represents enumeration of ConfigurationType used to configure or
/// access certain aspect of logging
enum class ConfigurationType : base::type::EnumType {
/// @brief Determines whether or not corresponding level and logger of logging
/// is enabled
/// You may disable all logs by using el::Level::Global
Enabled = 1,
/// @brief Whether or not to write corresponding log to log file
ToFile = 2,
/// @brief Whether or not to write corresponding level and logger log to
/// standard output.
/// By standard output meaning termnal, command prompt etc
ToStandardOutput = 4,
/// @brief Determines format of logging corresponding level and logger.
Format = 8,
/// @brief Determines log file (full path) to write logs to for corresponding
/// level and logger
Filename = 16,
/// @brief Specifies precision of the subsecond part. It should be within
/// range (1-6).
SubsecondPrecision = 32,
/// @brief Alias of SubsecondPrecision (for backward compatibility)
MillisecondsWidth = SubsecondPrecision,
/// @brief Determines whether or not performance tracking is enabled.
///
/// @detail This does not depend on logger or level. Performance tracking
/// always uses 'performance' logger
PerformanceTracking = 64,
/// @brief Specifies log file max size.
///
/// @detail If file size of corresponding log file (for corresponding level)
/// is >= specified size, log file will
/// be truncated and re-initiated.
MaxLogFileSize = 128,
/// @brief Specifies number of log entries to hold until we flush pending log
/// data
LogFlushThreshold = 256,
/// @brief Represents unknown configuration
Unknown = 1010
};
/// @brief Static class that contains helper functions for el::ConfigurationType
class ConfigurationTypeHelper : base::StaticClass {
public:
/// @brief Represents minimum valid configuration type. Useful when iterating
/// through enum.
static const base::type::EnumType kMinValid =
static_cast<base::type::EnumType>(ConfigurationType::Enabled);
/// @brief Represents maximum valid configuration type. This is used
/// internally and you should not need it.
static const base::type::EnumType kMaxValid =
static_cast<base::type::EnumType>(ConfigurationType::MaxLogFileSize);
/// @brief Casts configuration type to int, useful for iterating through enum.
static base::type::EnumType castToInt(ConfigurationType configurationType) {
return static_cast<base::type::EnumType>(configurationType);
}
/// @brief Casts int(ushort) to configuration type, useful for iterating
/// through enum.
static ConfigurationType castFromInt(base::type::EnumType c) {
return static_cast<ConfigurationType>(c);
}
/// @brief Converts configuration type to associated const char*
/// @returns Upper case string based configuration type.
static const char *convertToString(ConfigurationType configurationType);
/// @brief Converts from configStr to ConfigurationType
/// @param configStr Upper case string based configuration type.
/// Lower case is also valid but providing upper case is recommended.
static ConfigurationType convertFromString(const char *configStr);
/// @brief Applies specified function to each configuration type starting from
/// startIndex
/// @param startIndex initial value to start the iteration from. This is
/// passed by pointer and is left-shifted
/// so this can be used inside function (fn) to represent current
/// configuration type.
/// @param fn function to apply with each configuration type.
/// This bool represent whether or not to stop iterating through
/// configurations.
static inline void forEachConfigType(base::type::EnumType *startIndex,
const std::function<bool(void)> &fn);
};
/// @brief Flags used while writing logs. This flags are set by user
enum class LoggingFlag : base::type::EnumType {
/// @brief Makes sure we have new line for each container log entry
NewLineForContainer = 1,
/// @brief Makes sure if -vmodule is used and does not specifies a module,
/// then verbose
/// logging is allowed via that module.
AllowVerboseIfModuleNotSpecified = 2,
/// @brief When handling crashes by default, detailed crash reason will be
/// logged as well
LogDetailedCrashReason = 4,
/// @brief Allows to disable application abortion when logged using FATAL
/// level
DisableApplicationAbortOnFatalLog = 8,
/// @brief Flushes log with every log-entry (performance sensitive) - Disabled
/// by default
ImmediateFlush = 16,
/// @brief Enables strict file rolling
StrictLogFileSizeCheck = 32,
/// @brief Make terminal output colorful for supported terminals
ColoredTerminalOutput = 64,
/// @brief Supports use of multiple logging in same macro, e.g, CLOG(INFO,
/// "default", "network")
MultiLoggerSupport = 128,
/// @brief Disables comparing performance tracker's checkpoints
DisablePerformanceTrackingCheckpointComparison = 256,
/// @brief Disable VModules
DisableVModules = 512,
/// @brief Disable VModules extensions
DisableVModulesExtensions = 1024,
/// @brief Enables hierarchical logging
HierarchicalLogging = 2048,
/// @brief Creates logger automatically when not available
CreateLoggerAutomatically = 4096,
/// @brief Adds spaces b/w logs that separated by left-shift operator
AutoSpacing = 8192,
/// @brief Preserves time format and does not convert it to sec, hour etc
/// (performance tracking only)
FixedTimeFormat = 16384,
// @brief Ignore SIGINT or crash
IgnoreSigInt = 32768,
};
namespace base {
/// @brief Namespace containing constants used internally.
namespace consts {
static const char kFormatSpecifierCharValue = 'v';
static const char kFormatSpecifierChar = '%';
static const unsigned int kMaxLogPerCounter = 100000;
static const unsigned int kMaxLogPerContainer = 100;
static const unsigned int kDefaultSubsecondPrecision = 3;
#ifdef ELPP_DEFAULT_LOGGER
static const char *kDefaultLoggerId = ELPP_DEFAULT_LOGGER;
#else
static const char *kDefaultLoggerId = "default";
#endif
#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
#ifdef ELPP_DEFAULT_PERFORMANCE_LOGGER
static const char *kPerformanceLoggerId = ELPP_DEFAULT_PERFORMANCE_LOGGER;
#else
static const char *kPerformanceLoggerId = "performance";
#endif // ELPP_DEFAULT_PERFORMANCE_LOGGER
#endif
#if defined(ELPP_SYSLOG)
static const char *kSysLogLoggerId = "syslog";
#endif // defined(ELPP_SYSLOG)
#if ELPP_OS_WINDOWS
static const char *kFilePathSeparator = "\\";
#else
static const char *kFilePathSeparator = "/";
#endif // ELPP_OS_WINDOWS
static const std::size_t kSourceFilenameMaxLength = 100;
static const std::size_t kSourceLineMaxLength = 10;
static const Level kPerformanceTrackerDefaultLevel = Level::Info;
const struct {
double value;
const base::type::char_t *unit;
} kTimeFormats[] = {
{1000.0f, ELPP_LITERAL("us")}, {1000.0f, ELPP_LITERAL("ms")},
{60.0f, ELPP_LITERAL("seconds")}, {60.0f, ELPP_LITERAL("minutes")},
{24.0f, ELPP_LITERAL("hours")}, {7.0f, ELPP_LITERAL("days")}};
static const int kTimeFormatsCount =
sizeof(kTimeFormats) / sizeof(kTimeFormats[0]);
const struct {
int numb;
const char *name;
const char *brief;
const char *detail;
} kCrashSignals[] = {
// NOTE: Do not re-order, if you do please check CrashHandler(bool)
// constructor and CrashHandler::setHandler(..)
{SIGABRT, "SIGABRT", "Abnormal termination",
"Program was abnormally terminated."},
{SIGFPE, "SIGFPE", "Erroneous arithmetic operation",
"Arithmetic operation issue such as division by zero or operation "
"resulting in overflow."},
{SIGILL, "SIGILL", "Illegal instruction",
"Generally due to a corruption in the code or to an attempt to execute "
"data."},
{SIGSEGV, "SIGSEGV", "Invalid access to memory",
"Program is trying to read an invalid (unallocated, deleted or corrupted) "
"or inaccessible memory."},
{SIGINT, "SIGINT", "Interactive attention signal",
"Interruption generated (generally) by user or operating system."},
};
static const int kCrashSignalsCount =
sizeof(kCrashSignals) / sizeof(kCrashSignals[0]);
} // namespace consts
} // namespace base
typedef std::function<void(const char *, std::size_t)> PreRollOutCallback;
namespace base {
static inline void defaultPreRollOutCallback(const char *, std::size_t) {}
/// @brief Enum to represent timestamp unit
enum class TimestampUnit : base::type::EnumType {
Microsecond = 0,
Millisecond = 1,
Second = 2,
Minute = 3,
Hour = 4,
Day = 5
};
/// @brief Format flags used to determine specifiers that are active for
/// performance improvements.
enum class FormatFlags : base::type::EnumType {
DateTime = 1 << 1,
LoggerId = 1 << 2,
File = 1 << 3,
Line = 1 << 4,
Location = 1 << 5,
Function = 1 << 6,
User = 1 << 7,
Host = 1 << 8,
LogMessage = 1 << 9,
VerboseLevel = 1 << 10,
AppName = 1 << 11,
ThreadId = 1 << 12,
Level = 1 << 13,
FileBase = 1 << 14,
LevelShort = 1 << 15
};
/// @brief A subsecond precision class containing actual width and offset of the
/// subsecond part
class SubsecondPrecision {
public:
SubsecondPrecision(void) { init(base::consts::kDefaultSubsecondPrecision); }
explicit SubsecondPrecision(int width) { init(width); }
bool operator==(const SubsecondPrecision &ssPrec) {
return m_width == ssPrec.m_width && m_offset == ssPrec.m_offset;
}
int m_width;
unsigned int m_offset;
private:
void init(int width);
};
/// @brief Type alias of SubsecondPrecision
typedef SubsecondPrecision MillisecondsWidth;
/// @brief Namespace containing utility functions/static classes used internally
namespace utils {
/// @brief Deletes memory safely and points to null
template <typename T>
static typename std::enable_if<std::is_pointer<T *>::value, void>::type
safeDelete(T *&pointer) {
if (pointer == nullptr)
return;
delete pointer;
pointer = nullptr;
}
/// @brief Bitwise operations for C++11 strong enum class. This casts e into
/// Flag_T and returns value after bitwise operation Use these function as
/// <pre>flag = bitwise::Or<MyEnum>(MyEnum::val1, flag);</pre>
namespace bitwise {
template <typename Enum>
static inline base::type::EnumType And(Enum e, base::type::EnumType flag) {
return static_cast<base::type::EnumType>(flag) &
static_cast<base::type::EnumType>(e);
}
template <typename Enum>
static inline base::type::EnumType Not(Enum e, base::type::EnumType flag) {
return static_cast<base::type::EnumType>(flag) &
~(static_cast<base::type::EnumType>(e));
}
template <typename Enum>
static inline base::type::EnumType Or(Enum e, base::type::EnumType flag) {
return static_cast<base::type::EnumType>(flag) |
static_cast<base::type::EnumType>(e);
}
} // namespace bitwise
template <typename Enum>
static inline void addFlag(Enum e, base::type::EnumType *flag) {
*flag = base::utils::bitwise::Or<Enum>(e, *flag);
}
template <typename Enum>
static inline void removeFlag(Enum e, base::type::EnumType *flag) {
*flag = base::utils::bitwise::Not<Enum>(e, *flag);
}
template <typename Enum>
static inline bool hasFlag(Enum e, base::type::EnumType flag) {
return base::utils::bitwise::And<Enum>(e, flag) > 0x0;
}
} // namespace utils
namespace threading {
#if ELPP_THREADING_ENABLED
#if !ELPP_USE_STD_THREADING
namespace internal {
/// @brief A mutex wrapper for compiler that dont yet support
/// std::recursive_mutex
class Mutex : base::NoCopy {
public:
Mutex(void) {
#if ELPP_OS_UNIX
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&m_underlyingMutex, &attr);
pthread_mutexattr_destroy(&attr);
#elif ELPP_OS_WINDOWS
InitializeCriticalSection(&m_underlyingMutex);
#endif // ELPP_OS_UNIX
}
virtual ~Mutex(void) {
#if ELPP_OS_UNIX
pthread_mutex_destroy(&m_underlyingMutex);
#elif ELPP_OS_WINDOWS
DeleteCriticalSection(&m_underlyingMutex);
#endif // ELPP_OS_UNIX
}
inline void lock(void) {
#if ELPP_OS_UNIX
pthread_mutex_lock(&m_underlyingMutex);
#elif ELPP_OS_WINDOWS
EnterCriticalSection(&m_underlyingMutex);
#endif // ELPP_OS_UNIX
}
inline bool try_lock(void) {
#if ELPP_OS_UNIX
return (pthread_mutex_trylock(&m_underlyingMutex) == 0);
#elif ELPP_OS_WINDOWS
return TryEnterCriticalSection(&m_underlyingMutex);
#endif // ELPP_OS_UNIX
}
inline void unlock(void) {
#if ELPP_OS_UNIX
pthread_mutex_unlock(&m_underlyingMutex);
#elif ELPP_OS_WINDOWS
LeaveCriticalSection(&m_underlyingMutex);
#endif // ELPP_OS_UNIX
}
private:
#if ELPP_OS_UNIX
pthread_mutex_t m_underlyingMutex;
#elif ELPP_OS_WINDOWS
CRITICAL_SECTION m_underlyingMutex;
#endif // ELPP_OS_UNIX
};
/// @brief Scoped lock for compiler that dont yet support std::lock_guard
template <typename M> class ScopedLock : base::NoCopy {
public:
explicit ScopedLock(M &mutex) {
m_mutex = &mutex;
m_mutex->lock();
}
virtual ~ScopedLock(void) { m_mutex->unlock(); }
private:
M *m_mutex;
ScopedLock(void);
};
} // namespace internal
typedef base::threading::internal::Mutex Mutex;
typedef base::threading::internal::ScopedLock<base::threading::Mutex>
ScopedLock;
#else
typedef std::recursive_mutex Mutex;
typedef std::lock_guard<base::threading::Mutex> ScopedLock;
#endif // !ELPP_USE_STD_THREADING
#else
namespace internal {
/// @brief Mutex wrapper used when multi-threading is disabled.
class NoMutex : base::NoCopy {
public:
NoMutex(void) {}
inline void lock(void) {}
inline bool try_lock(void) { return true; }
inline void unlock(void) {}
};
/// @brief Lock guard wrapper used when multi-threading is disabled.
template <typename Mutex> class NoScopedLock : base::NoCopy {
public:
explicit NoScopedLock(Mutex &) {}
virtual ~NoScopedLock(void) {}
private:
NoScopedLock(void);
};
} // namespace internal
typedef base::threading::internal::NoMutex Mutex;
typedef base::threading::internal::NoScopedLock<base::threading::Mutex>
ScopedLock;
#endif // ELPP_THREADING_ENABLED
/// @brief Base of thread safe class, this class is inheritable-only
class ThreadSafe {
public:
virtual inline void acquireLock(void) ELPP_FINAL { m_mutex.lock(); }
virtual inline void releaseLock(void) ELPP_FINAL { m_mutex.unlock(); }
virtual inline base::threading::Mutex &lock(void) ELPP_FINAL {
return m_mutex;
}
protected:
ThreadSafe(void) {}
virtual ~ThreadSafe(void) {}
private:
base::threading::Mutex m_mutex;
};
#if ELPP_THREADING_ENABLED
#if !ELPP_USE_STD_THREADING
/// @brief Gets ID of currently running threading in windows systems. On unix,
/// nothing is returned.
static std::string getCurrentThreadId(void) {
std::stringstream ss;
#if (ELPP_OS_WINDOWS)
ss << GetCurrentThreadId();
#endif // (ELPP_OS_WINDOWS)
return ss.str();
}
#else
/// @brief Gets ID of currently running threading using
/// std::this_thread::get_id()
static std::string getCurrentThreadId(void) {
std::stringstream ss;
ss << std::this_thread::get_id();
return ss.str();
}
#endif // !ELPP_USE_STD_THREADING
#else
static inline std::string getCurrentThreadId(void) { return std::string(); }
#endif // ELPP_THREADING_ENABLED
} // namespace threading
namespace utils {
class File : base::StaticClass {
public:
/// @brief Creates new out file stream for specified filename.
/// @return Pointer to newly created fstream or nullptr
static base::type::fstream_t *newFileStream(const std::string &filename);
/// @brief Gets size of file provided in stream
static std::size_t getSizeOfFile(base::type::fstream_t *fs);
/// @brief Determines whether or not provided path exist in current file
/// system
static bool pathExists(const char *path, bool considerFile = false);
/// @brief Creates specified path on file system
/// @param path Path to create.
static bool createPath(const std::string &path);
/// @brief Extracts path of filename with leading slash
static std::string extractPathFromFilename(
const std::string &fullPath,
const char *separator = base::consts::kFilePathSeparator);
/// @brief builds stripped filename and puts it in buff
static void buildStrippedFilename(
const char *filename, char buff[],
std::size_t limit = base::consts::kSourceFilenameMaxLength);
/// @brief builds base filename and puts it in buff
static void
buildBaseFilename(const std::string &fullPath, char buff[],
std::size_t limit = base::consts::kSourceFilenameMaxLength,
const char *separator = base::consts::kFilePathSeparator);
};
/// @brief String utilities helper class used internally. You should not use it.
class Str : base::StaticClass {
public:
/// @brief Checks if character is digit. Dont use libc implementation of it to
/// prevent locale issues.
static inline bool isDigit(char c) { return c >= '0' && c <= '9'; }
/// @brief Matches wildcards, '*' and '?' only supported.
static bool wildCardMatch(const char *str, const char *pattern);
static std::string &ltrim(std::string &str);
static std::string &rtrim(std::string &str);
static std::string &trim(std::string &str);
/// @brief Determines whether or not str starts with specified string
/// @param str String to check
/// @param start String to check against
/// @return Returns true if starts with specified string, false otherwise
static bool startsWith(const std::string &str, const std::string &start);
/// @brief Determines whether or not str ends with specified string
/// @param str String to check
/// @param end String to check against
/// @return Returns true if ends with specified string, false otherwise
static bool endsWith(const std::string &str, const std::string &end);
/// @brief Replaces all instances of replaceWhat with 'replaceWith'. Original
/// variable is changed for performance.
/// @param [in,out] str String to replace from
/// @param replaceWhat Character to replace
/// @param replaceWith Character to replace with
/// @return Modified version of str
static std::string &replaceAll(std::string &str, char replaceWhat,
char replaceWith);
/// @brief Replaces all instances of 'replaceWhat' with 'replaceWith'. (String
/// version) Replaces in place
/// @param str String to replace from
/// @param replaceWhat Character to replace
/// @param replaceWith Character to replace with
/// @return Modified (original) str
static std::string &replaceAll(std::string &str,
const std::string &replaceWhat,
const std::string &replaceWith);
static void replaceFirstWithEscape(base::type::string_t &str,
const base::type::string_t &replaceWhat,
const base::type::string_t &replaceWith);
#if defined(ELPP_UNICODE)
static void replaceFirstWithEscape(base::type::string_t &str,
const base::type::string_t &replaceWhat,
const std::string &replaceWith);
#endif // defined(ELPP_UNICODE)
/// @brief Converts string to uppercase
/// @param str String to convert
/// @return Uppercase string
static std::string &toUpper(std::string &str);
/// @brief Compares cstring equality - uses strcmp
static bool cStringEq(const char *s1, const char *s2);
/// @brief Compares cstring equality (case-insensitive) - uses toupper(char)
/// Dont use strcasecmp because of CRT (VC++)
static bool cStringCaseEq(const char *s1, const char *s2);
/// @brief Returns true if c exist in str
static bool contains(const char *str, char c);
static char *convertAndAddToBuff(std::size_t n, int len, char *buf,
const char *bufLim, bool zeroPadded = true);
static char *addToBuff(const char *str, char *buf, const char *bufLim);
static char *clearBuff(char buff[], std::size_t lim);
/// @brief Converts wchar* to char*
/// NOTE: Need to free return value after use!
static char *wcharPtrToCharPtr(const wchar_t *line);
};
/// @brief Operating System helper static class used internally. You should not
/// use it.
class OS : base::StaticClass {
public:
#if ELPP_OS_WINDOWS
/// @brief Gets environment variables for Windows based OS.
/// We are not using <code>getenv(const char*)</code> because of CRT
/// deprecation
/// @param varname Variable name to get environment variable value for
/// @return If variable exist the value of it otherwise nullptr
static const char *getWindowsEnvironmentVariable(const char *varname);
#endif // ELPP_OS_WINDOWS
#if ELPP_OS_ANDROID
/// @brief Reads android property value
static std::string getProperty(const char *prop);
/// @brief Reads android device name
static std::string getDeviceName(void);
#endif // ELPP_OS_ANDROID
/// @brief Runs command on terminal and returns the output.
///
/// @detail This is applicable only on unix based systems, for all other OS,
/// an empty string is returned.
/// @param command Bash command
/// @return Result of bash output or empty string if no result found.
static const std::string getBashOutput(const char *command);
/// @brief Gets environment variable. This is cross-platform and CRT safe (for
/// VC++)
/// @param variableName Environment variable name
/// @param defaultVal If no environment variable or value found the value to
/// return by default
/// @param alternativeBashCommand If environment variable not found what would
/// be alternative bash command
/// in order to look for value user is looking for. E.g, for 'user'
/// alternative command will 'whoami'
static std::string
getEnvironmentVariable(const char *variableName, const char *defaultVal,
const char *alternativeBashCommand = nullptr);
/// @brief Gets current username.
static std::string currentUser(void);
/// @brief Gets current host name or computer name.
///
/// @detail For android systems this is device name with its manufacturer and
/// model separated by hyphen
static std::string currentHost(void);
/// @brief Whether or not terminal supports colors
static bool termSupportsColor(void);
};
/// @brief Contains utilities for cross-platform date/time. This class make use
/// of el::base::utils::Str
class DateTime : base::StaticClass {
public:
/// @brief Cross platform gettimeofday for Windows and unix platform. This can
/// be used to determine current microsecond.
///
/// @detail For unix system it uses gettimeofday(timeval*, timezone*) and for
/// Windows, a separate implementation is provided
/// @param [in,out] tv Pointer that gets updated
static void gettimeofday(struct timeval *tv);
/// @brief Gets current date and time with a subsecond part.
/// @param format User provided date/time format
/// @param ssPrec A pointer to base::SubsecondPrecision from configuration
/// (non-null)
/// @returns string based date time in specified format.
static std::string getDateTime(const char *format,
const base::SubsecondPrecision *ssPrec);
/// @brief Converts timeval (struct from ctime) to string using specified
/// format and subsecond precision
static std::string
timevalToString(struct timeval tval, const char *format,
const el::base::SubsecondPrecision *ssPrec);
/// @brief Formats time to get unit accordingly, units like second if > 1000
/// or minutes if > 60000 etc
static base::type::string_t formatTime(unsigned long long time,
base::TimestampUnit timestampUnit);
/// @brief Gets time difference in milli/micro second depending on
/// timestampUnit
static unsigned long long
getTimeDifference(const struct timeval &endTime,
const struct timeval &startTime,
base::TimestampUnit timestampUnit);
static struct ::tm *buildTimeInfo(struct timeval *currTime,
struct ::tm *timeInfo);
private:
static char *parseFormat(char *buf, std::size_t bufSz, const char *format,
const struct tm *tInfo, std::size_t msec,
const base::SubsecondPrecision *ssPrec);
};
/// @brief Command line arguments for application if specified using
/// el::Helpers::setArgs(..) or START_EASYLOGGINGPP(..)
class CommandLineArgs {
public:
CommandLineArgs(void) { setArgs(0, static_cast<char **>(nullptr)); }
CommandLineArgs(int argc, const char **argv) { setArgs(argc, argv); }
CommandLineArgs(int argc, char **argv) { setArgs(argc, argv); }
virtual ~CommandLineArgs(void) {}
/// @brief Sets arguments and parses them
inline void setArgs(int argc, const char **argv) {
setArgs(argc, const_cast<char **>(argv));
}
/// @brief Sets arguments and parses them
void setArgs(int argc, char **argv);
/// @brief Returns true if arguments contain paramKey with a value (separated
/// by '=')
bool hasParamWithValue(const char *paramKey) const;
/// @brief Returns value of arguments
/// @see hasParamWithValue(const char*)
const char *getParamValue(const char *paramKey) const;
/// @brief Return true if arguments has a param (not having a value) i,e
/// without '='
bool hasParam(const char *paramKey) const;
/// @brief Returns true if no params available. This exclude argv[0]
bool empty(void) const;
/// @brief Returns total number of arguments. This exclude argv[0]
std::size_t size(void) const;
friend base::type::ostream_t &operator<<(base::type::ostream_t &os,
const CommandLineArgs &c);
private:
int m_argc;
char **m_argv;
std::unordered_map<std::string, std::string> m_paramsWithValue;
std::vector<std::string> m_params;
};
/// @brief Abstract registry (aka repository) that provides basic interface for
/// pointer repository specified by T_Ptr type.
///
/// @detail Most of the functions are virtual final methods but anything
/// implementing this abstract class should implement unregisterAll() and
/// deepCopy(const AbstractRegistry<T_Ptr, Container>&) and write registerNew()
/// method according to container and few more methods; get() to find element,
/// unregister() to unregister single entry. Please note that this is
/// thread-unsafe and should also implement thread-safety mechanisms in
/// implementation.
template <typename T_Ptr, typename Container>
class AbstractRegistry : public base::threading::ThreadSafe {
public:
typedef typename Container::iterator iterator;
typedef typename Container::const_iterator const_iterator;
/// @brief Default constructor
AbstractRegistry(void) {}
/// @brief Move constructor that is useful for base classes
AbstractRegistry(AbstractRegistry &&sr) {
if (this == &sr) {
return;
}
unregisterAll();
m_list = std::move(sr.m_list);
}
bool operator==(const AbstractRegistry<T_Ptr, Container> &other) {
if (size() != other.size()) {
return false;
}
for (std::size_t i = 0; i < m_list.size(); ++i) {
if (m_list.at(i) != other.m_list.at(i)) {
return false;
}
}
return true;
}
bool operator!=(const AbstractRegistry<T_Ptr, Container> &other) {
if (size() != other.size()) {
return true;
}
for (std::size_t i = 0; i < m_list.size(); ++i) {
if (m_list.at(i) != other.m_list.at(i)) {
return true;
}
}
return false;
}
/// @brief Assignment move operator
AbstractRegistry &operator=(AbstractRegistry &&sr) {
if (this == &sr) {
return *this;
}
unregisterAll();
m_list = std::move(sr.m_list);
return *this;
}
virtual ~AbstractRegistry(void) {}
/// @return Iterator pointer from start of repository
virtual inline iterator begin(void) ELPP_FINAL { return m_list.begin(); }
/// @return Iterator pointer from end of repository
virtual inline iterator end(void) ELPP_FINAL { return m_list.end(); }
/// @return Constant iterator pointer from start of repository
virtual inline const_iterator cbegin(void) const ELPP_FINAL {
return m_list.cbegin();
}
/// @return End of repository
virtual inline const_iterator cend(void) const ELPP_FINAL {
return m_list.cend();
}
/// @return Whether or not repository is empty
virtual inline bool empty(void) const ELPP_FINAL { return m_list.empty(); }
/// @return Size of repository
virtual inline std::size_t size(void) const ELPP_FINAL {
return m_list.size();
}
/// @brief Returns underlying container by reference
virtual inline Container &list(void) ELPP_FINAL { return m_list; }
/// @brief Returns underlying container by constant reference.
virtual inline const Container &list(void) const ELPP_FINAL { return m_list; }
/// @brief Unregisters all the pointers from current repository.
virtual void unregisterAll(void) = 0;
protected:
virtual void deepCopy(const AbstractRegistry<T_Ptr, Container> &) = 0;
void reinitDeepCopy(const AbstractRegistry<T_Ptr, Container> &sr) {
unregisterAll();
deepCopy(sr);
}
private:
Container m_list;
};
/// @brief A pointer registry mechanism to manage memory and provide search
/// functionalities. (non-predicate version)
///
/// @detail NOTE: This is thread-unsafe implementation (although it contains
/// lock function, it does not use these functions)
/// of AbstractRegistry<T_Ptr, Container>. Any implementation of this
/// class should be explicitly (by using lock functions)
template <typename T_Ptr, typename T_Key = const char *>
class Registry
: public AbstractRegistry<T_Ptr, std::unordered_map<T_Key, T_Ptr *>> {
public:
typedef typename Registry<T_Ptr, T_Key>::iterator iterator;
typedef typename Registry<T_Ptr, T_Key>::const_iterator const_iterator;
Registry(void) {}
/// @brief Copy constructor that is useful for base classes. Try to avoid this
/// constructor, use move constructor.
Registry(const Registry &sr)
: AbstractRegistry<T_Ptr, std::vector<T_Ptr *>>() {
if (this == &sr) {
return;
}
this->reinitDeepCopy(sr);
}
/// @brief Assignment operator that unregisters all the existing registries
/// and deeply copies each of repo element
/// @see unregisterAll()
/// @see deepCopy(const AbstractRegistry&)
Registry &operator=(const Registry &sr) {
if (this == &sr) {
return *this;
}
this->reinitDeepCopy(sr);
return *this;
}
virtual ~Registry(void) { unregisterAll(); }
protected:
virtual void unregisterAll(void) ELPP_FINAL {
if (!this->empty()) {
for (auto &&curr : this->list()) {
base::utils::safeDelete(curr.second);
}
this->list().clear();
}
}
/// @brief Registers new registry to repository.
virtual void registerNew(const T_Key &uniqKey, T_Ptr *ptr) ELPP_FINAL {
unregister(uniqKey);
this->list().insert(std::make_pair(uniqKey, ptr));
}
/// @brief Unregisters single entry mapped to specified unique key
void unregister(const T_Key &uniqKey) {
T_Ptr *existing = get(uniqKey);
if (existing != nullptr) {
this->list().erase(uniqKey);
base::utils::safeDelete(existing);
}
}
/// @brief Gets pointer from repository. If none found, nullptr is returned.
T_Ptr *get(const T_Key &uniqKey) {
iterator it = this->list().find(uniqKey);
return it == this->list().end() ? nullptr : it->second;
}
private:
virtual void deepCopy(
const AbstractRegistry<T_Ptr, std::unordered_map<T_Key, T_Ptr *>> &sr)
ELPP_FINAL {
for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it) {
registerNew(it->first, new T_Ptr(*it->second));
}
}
};
/// @brief A pointer registry mechanism to manage memory and provide search
/// functionalities. (predicate version)
///
/// @detail NOTE: This is thread-unsafe implementation of
/// AbstractRegistry<T_Ptr, Container>. Any implementation of this class should
/// be made thread-safe explicitly
template <typename T_Ptr, typename Pred>
class RegistryWithPred : public AbstractRegistry<T_Ptr, std::vector<T_Ptr *>> {
public:
typedef typename RegistryWithPred<T_Ptr, Pred>::iterator iterator;
typedef typename RegistryWithPred<T_Ptr, Pred>::const_iterator const_iterator;
RegistryWithPred(void) {}
virtual ~RegistryWithPred(void) { unregisterAll(); }
/// @brief Copy constructor that is useful for base classes. Try to avoid this
/// constructor, use move constructor.
RegistryWithPred(const RegistryWithPred &sr)
: AbstractRegistry<T_Ptr, std::vector<T_Ptr *>>() {
if (this == &sr) {
return;
}
this->reinitDeepCopy(sr);
}
/// @brief Assignment operator that unregisters all the existing registries
/// and deeply copies each of repo element
/// @see unregisterAll()
/// @see deepCopy(const AbstractRegistry&)
RegistryWithPred &operator=(const RegistryWithPred &sr) {
if (this == &sr) {
return *this;
}
this->reinitDeepCopy(sr);
return *this;
}
friend base::type::ostream_t &operator<<(base::type::ostream_t &os,
const RegistryWithPred &sr) {
for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
os << ELPP_LITERAL(" ") << **it << ELPP_LITERAL("\n");
}
return os;
}
protected:
virtual void unregisterAll(void) ELPP_FINAL {
if (!this->empty()) {
for (auto &&curr : this->list()) {
base::utils::safeDelete(curr);
}
this->list().clear();
}
}
virtual void unregister(T_Ptr *&ptr) ELPP_FINAL {
if (ptr) {
iterator iter = this->begin();
for (; iter != this->end(); ++iter) {
if (ptr == *iter) {
break;
}
}
if (iter != this->end() && *iter != nullptr) {
this->list().erase(iter);
base::utils::safeDelete(*iter);
}
}
}
virtual inline void registerNew(T_Ptr *ptr) ELPP_FINAL {
this->list().push_back(ptr);
}
/// @brief Gets pointer from repository with specified arguments. Arguments
/// are passed to predicate in order to validate pointer.
template <typename T, typename T2> T_Ptr *get(const T &arg1, const T2 arg2) {
iterator iter = std::find_if(this->list().begin(), this->list().end(),
Pred(arg1, arg2));
if (iter != this->list().end() && *iter != nullptr) {
return *iter;
}
return nullptr;
}
private:
virtual void
deepCopy(const AbstractRegistry<T_Ptr, std::vector<T_Ptr *>> &sr) {
for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
registerNew(new T_Ptr(**it));
}
}
};
class Utils {
public:
template <typename T, typename TPtr>
static bool installCallback(const std::string &id,
std::unordered_map<std::string, TPtr> *mapT) {
if (mapT->find(id) == mapT->end()) {
mapT->insert(std::make_pair(id, TPtr(new T())));
return true;
}
return false;
}
template <typename T, typename TPtr>
static void uninstallCallback(const std::string &id,
std::unordered_map<std::string, TPtr> *mapT) {
if (mapT->find(id) != mapT->end()) {
mapT->erase(id);
}
}
template <typename T, typename TPtr>
static T *callback(const std::string &id,
std::unordered_map<std::string, TPtr> *mapT) {
typename std::unordered_map<std::string, TPtr>::iterator iter =
mapT->find(id);
if (iter != mapT->end()) {
return static_cast<T *>(iter->second.get());
}
return nullptr;
}
};
} // namespace utils
} // namespace base
/// @brief Base of Easylogging++ friendly class
///
/// @detail After inheriting this class publicly, implement pure-virtual
/// function `void log(std::ostream&) const`
class Loggable {
public:
virtual ~Loggable(void) {}
virtual void log(el::base::type::ostream_t &) const = 0;
private:
friend inline el::base::type::ostream_t &
operator<<(el::base::type::ostream_t &os, const Loggable &loggable) {
loggable.log(os);
return os;
}
};
namespace base {
/// @brief Represents log format containing flags and date format. This is used
/// internally to start initial log
class LogFormat : public Loggable {
public:
LogFormat(void);
LogFormat(Level level, const base::type::string_t &format);
LogFormat(const LogFormat &logFormat);
LogFormat(LogFormat &&logFormat);
LogFormat &operator=(const LogFormat &logFormat);
virtual ~LogFormat(void) {}
bool operator==(const LogFormat &other);
/// @brief Updates format to be used while logging.
/// @param userFormat User provided format
void parseFromFormat(const base::type::string_t &userFormat);
inline Level level(void) const { return m_level; }
inline const base::type::string_t &userFormat(void) const {
return m_userFormat;
}
inline const base::type::string_t &format(void) const { return m_format; }
inline const std::string &dateTimeFormat(void) const {
return m_dateTimeFormat;
}
inline base::type::EnumType flags(void) const { return m_flags; }
inline bool hasFlag(base::FormatFlags flag) const {
return base::utils::hasFlag(flag, m_flags);
}
virtual void log(el::base::type::ostream_t &os) const { os << m_format; }
protected:
/// @brief Updates date time format if available in currFormat.
/// @param index Index where %datetime, %date or %time was found
/// @param [in,out] currFormat current format that is being used to format
virtual void updateDateFormat(std::size_t index,
base::type::string_t &currFormat) ELPP_FINAL;
/// @brief Updates %level from format. This is so that we dont have to do it
/// at log-writing-time. It uses m_format and m_level
virtual void updateFormatSpec(void) ELPP_FINAL;
inline void addFlag(base::FormatFlags flag) {
base::utils::addFlag(flag, &m_flags);
}
private:
Level m_level;
base::type::string_t m_userFormat;
base::type::string_t m_format;
std::string m_dateTimeFormat;
base::type::EnumType m_flags;
std::string m_currentUser;
std::string m_currentHost;
friend class el::Logger; // To resolve loggerId format specifier easily
};
} // namespace base
/// @brief Resolving function for format specifier
typedef std::function<std::string(const LogMessage *)>
FormatSpecifierValueResolver;
/// @brief User-provided custom format specifier
/// @see el::Helpers::installCustomFormatSpecifier
/// @see FormatSpecifierValueResolver
class CustomFormatSpecifier {
public:
CustomFormatSpecifier(const char *formatSpecifier,
const FormatSpecifierValueResolver &resolver)
: m_formatSpecifier(formatSpecifier), m_resolver(resolver) {}
inline const char *formatSpecifier(void) const { return m_formatSpecifier; }
inline const FormatSpecifierValueResolver &resolver(void) const {
return m_resolver;
}
inline bool operator==(const char *formatSpecifier) {
return strcmp(m_formatSpecifier, formatSpecifier) == 0;
}
private:
const char *m_formatSpecifier;
FormatSpecifierValueResolver m_resolver;
};
/// @brief Represents single configuration that has representing level,
/// configuration type and a string based value.
///
/// @detail String based value means any value either its boolean, integer or
/// string itself, it will be embedded inside quotes and will be parsed later.
///
/// Consider some examples below:
/// * el::Configuration confEnabledInfo(el::Level::Info,
/// el::ConfigurationType::Enabled, "true");
/// * el::Configuration confMaxLogFileSizeInfo(el::Level::Info,
/// el::ConfigurationType::MaxLogFileSize, "2048");
/// * el::Configuration confFilenameInfo(el::Level::Info,
/// el::ConfigurationType::Filename, "/var/log/my.log");
class Configuration : public Loggable {
public:
Configuration(const Configuration &c);
Configuration &operator=(const Configuration &c);
virtual ~Configuration(void) {}
/// @brief Full constructor used to sets value of configuration
Configuration(Level level, ConfigurationType configurationType,
const std::string &value);
/// @brief Gets level of current configuration
inline Level level(void) const { return m_level; }
/// @brief Gets configuration type of current configuration
inline ConfigurationType configurationType(void) const {
return m_configurationType;
}
/// @brief Gets string based configuration value
inline const std::string &value(void) const { return m_value; }
/// @brief Set string based configuration value
/// @param value Value to set. Values have to be std::string; For boolean
/// values use "true", "false", for any integral values
/// use them in quotes. They will be parsed when configuring
inline void setValue(const std::string &value) { m_value = value; }
virtual void log(el::base::type::ostream_t &os) const;
/// @brief Used to find configuration from configuration (pointers)
/// repository. Avoid using it.
class Predicate {
public:
Predicate(Level level, ConfigurationType configurationType);
bool operator()(const Configuration *conf) const;
private:
Level m_level;
ConfigurationType m_configurationType;
};
private:
Level m_level;
ConfigurationType m_configurationType;
std::string m_value;
};
/// @brief Thread-safe Configuration repository
///
/// @detail This repository represents configurations for all the levels and
/// configuration type mapped to a value.
class Configurations
: public base::utils::RegistryWithPred<Configuration,
Configuration::Predicate> {
public:
/// @brief Default constructor with empty repository
Configurations(void);
/// @brief Constructor used to set configurations using configuration file.
/// @param configurationFile Full path to configuration file
/// @param useDefaultsForRemaining Lets you set the remaining configurations
/// to default.
/// @param base If provided, this configuration will be based off existing
/// repository that this argument is pointing to.
/// @see parseFromFile(const std::string&, Configurations* base)
/// @see setRemainingToDefault()
Configurations(const std::string &configurationFile,
bool useDefaultsForRemaining = true,
Configurations *base = nullptr);
virtual ~Configurations(void) {}
/// @brief Parses configuration from file.
/// @param configurationFile Full path to configuration file
/// @param base Configurations to base new configuration repository off. This
/// value is used when you want to use
/// existing Configurations to base all the values and then set rest of
/// configuration via configuration file.
/// @return True if successfully parsed, false otherwise. You may define
/// 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
/// do not proceed without successful parse.
bool parseFromFile(const std::string &configurationFile,
Configurations *base = nullptr);
/// @brief Parse configurations from configuration string.
///
/// @detail This configuration string has same syntax as configuration file
/// contents. Make sure all the necessary new line characters are provided.
/// @param base Configurations to base new configuration repository off. This
/// value is used when you want to use
/// existing Configurations to base all the values and then set rest of
/// configuration via configuration text.
/// @return True if successfully parsed, false otherwise. You may define
/// 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
/// do not proceed without successful parse.
bool parseFromText(const std::string &configurationsString,
Configurations *base = nullptr);
/// @brief Sets configuration based-off an existing configurations.
/// @param base Pointer to existing configurations.
void setFromBase(Configurations *base);
/// @brief Determines whether or not specified configuration type exists in
/// the repository.
///
/// @detail Returns as soon as first level is found.
/// @param configurationType Type of configuration to check existence for.
bool hasConfiguration(ConfigurationType configurationType);
/// @brief Determines whether or not specified configuration type exists for
/// specified level
/// @param level Level to check
/// @param configurationType Type of configuration to check existence for.
bool hasConfiguration(Level level, ConfigurationType configurationType);
/// @brief Sets value of configuration for specified level.
///
/// @detail Any existing configuration for specified level will be replaced.
/// Also note that configuration types ConfigurationType::SubsecondPrecision
/// and ConfigurationType::PerformanceTracking will be ignored if not set for
/// Level::Global because these configurations are not dependant on level.
/// @param level Level to set configuration for (el::Level).
/// @param configurationType Type of configuration (el::ConfigurationType)
/// @param value A string based value. Regardless of what the data type of
/// configuration is, it will always be string from users' point of view. This
/// is then parsed later to be used internally.
/// @see Configuration::setValue(const std::string& value)
/// @see el::Level
/// @see el::ConfigurationType
void set(Level level, ConfigurationType configurationType,
const std::string &value);
/// @brief Sets single configuration based on other single configuration.
/// @see set(Level level, ConfigurationType configurationType, const
/// std::string& value)
void set(Configuration *conf);
inline Configuration *get(Level level, ConfigurationType configurationType) {
base::threading::ScopedLock scopedLock(lock());
return RegistryWithPred<Configuration, Configuration::Predicate>::get(
level, configurationType);
}
/// @brief Sets configuration for all levels.
/// @param configurationType Type of configuration
/// @param value String based value
/// @see Configurations::set(Level level, ConfigurationType configurationType,
/// const std::string& value)
inline void setGlobally(ConfigurationType configurationType,
const std::string &value) {
setGlobally(configurationType, value, false);
}
/// @brief Clears repository so that all the configurations are unset
inline void clear(void) {
base::threading::ScopedLock scopedLock(lock());
unregisterAll();
}
/// @brief Gets configuration file used in parsing this configurations.
///
/// @detail If this repository was set manually or by text this returns empty
/// string.
inline const std::string &configurationFile(void) const {
return m_configurationFile;
}
/// @brief Sets configurations to "factory based" configurations.
void setToDefault(void);
/// @brief Lets you set the remaining configurations to default.
///
/// @detail By remaining, it means that the level/type a configuration does
/// not exist for. This function is useful when you want to minimize chances
/// of failures, e.g, if you have a configuration file that sets configuration
/// for all the configurations except for Enabled or not, we use this so that
/// ENABLED is set to default i.e, true. If you dont do this explicitly
/// (either by calling this function or by using second param in Constructor
/// and try to access a value, an error is thrown
void setRemainingToDefault(void);
/// @brief Parser used internally to parse configurations from file or text.
///
/// @detail This class makes use of base::utils::Str.
/// You should not need this unless you are working on some tool for
/// Easylogging++
class Parser : base::StaticClass {
public:
/// @brief Parses configuration from file.
/// @param configurationFile Full path to configuration file
/// @param sender Sender configurations pointer. Usually 'this' is used from
/// calling class
/// @param base Configurations to base new configuration repository off.
/// This value is used when you want to use
/// existing Configurations to base all the values and then set rest
/// of configuration via configuration file.
/// @return True if successfully parsed, false otherwise. You may define
/// '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you
/// do not proceed without successful parse.
static bool parseFromFile(const std::string &configurationFile,
Configurations *sender,
Configurations *base = nullptr);
/// @brief Parse configurations from configuration string.
///
/// @detail This configuration string has same syntax as configuration file
/// contents. Make sure all the necessary new line characters are provided.
/// You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you do not
/// proceed without successful parse (This is recommended)
/// @param configurationsString the configuration in plain text format
/// @param sender Sender configurations pointer. Usually 'this' is used from
/// calling class
/// @param base Configurations to base new configuration repository off.
/// This value is used when you want to use
/// existing Configurations to base all the values and then set rest
/// of configuration via configuration text.
/// @return True if successfully parsed, false otherwise.
static bool parseFromText(const std::string &configurationsString,
Configurations *sender,
Configurations *base = nullptr);
private:
friend class el::Loggers;
static void ignoreComments(std::string *line);
static bool isLevel(const std::string &line);
static bool isComment(const std::string &line);
static inline bool isConfig(const std::string &line);
static bool parseLine(std::string *line, std::string *currConfigStr,
std::string *currLevelStr, Level *currLevel,
Configurations *conf);
};
private:
std::string m_configurationFile;
bool m_isFromFile;
friend class el::Loggers;
/// @brief Unsafely sets configuration if does not already exist
void unsafeSetIfNotExist(Level level, ConfigurationType configurationType,
const std::string &value);
/// @brief Thread unsafe set
void unsafeSet(Level level, ConfigurationType configurationType,
const std::string &value);
/// @brief Sets configurations for all levels including Level::Global if
/// includeGlobalLevel is true
/// @see Configurations::setGlobally(ConfigurationType configurationType,
/// const std::string& value)
void setGlobally(ConfigurationType configurationType,
const std::string &value, bool includeGlobalLevel);
/// @brief Sets configurations (Unsafely) for all levels including
/// Level::Global if includeGlobalLevel is true
/// @see Configurations::setGlobally(ConfigurationType configurationType,
/// const std::string& value)
void unsafeSetGlobally(ConfigurationType configurationType,
const std::string &value, bool includeGlobalLevel);
};
namespace base {
typedef std::shared_ptr<base::type::fstream_t> FileStreamPtr;
typedef std::unordered_map<std::string, FileStreamPtr> LogStreamsReferenceMap;
typedef std::shared_ptr<base::LogStreamsReferenceMap> LogStreamsReferenceMapPtr;
/// @brief Configurations with data types.
///
/// @detail el::Configurations have string based values. This is whats used
/// internally in order to read correct configurations. This is to perform
/// faster while writing logs using correct configurations.
///
/// This is thread safe and final class containing non-virtual destructor (means
/// nothing should inherit this class)
class TypedConfigurations : public base::threading::ThreadSafe {
public:
/// @brief Constructor to initialize (construct) the object off
/// el::Configurations
/// @param configurations Configurations pointer/reference to base this typed
/// configurations off.
/// @param logStreamsReference Use
/// ELPP->registeredLoggers()->logStreamsReference()
TypedConfigurations(Configurations *configurations,
LogStreamsReferenceMapPtr logStreamsReference);
TypedConfigurations(const TypedConfigurations &other);
virtual ~TypedConfigurations(void) {}
const Configurations *configurations(void) const { return m_configurations; }
bool enabled(Level level);
bool toFile(Level level);
const std::string &filename(Level level);
bool toStandardOutput(Level level);
const base::LogFormat &logFormat(Level level);
const base::SubsecondPrecision &
subsecondPrecision(Level level = Level::Global);
const base::MillisecondsWidth &millisecondsWidth(Level level = Level::Global);
bool performanceTracking(Level level = Level::Global);
base::type::fstream_t *fileStream(Level level);
std::size_t maxLogFileSize(Level level);
std::size_t logFlushThreshold(Level level);
private:
Configurations *m_configurations;
std::unordered_map<Level, bool> m_enabledMap;
std::unordered_map<Level, bool> m_toFileMap;
std::unordered_map<Level, std::string> m_filenameMap;
std::unordered_map<Level, bool> m_toStandardOutputMap;
std::unordered_map<Level, base::LogFormat> m_logFormatMap;
std::unordered_map<Level, base::SubsecondPrecision> m_subsecondPrecisionMap;
std::unordered_map<Level, bool> m_performanceTrackingMap;
std::unordered_map<Level, base::FileStreamPtr> m_fileStreamMap;
std::unordered_map<Level, std::size_t> m_maxLogFileSizeMap;
std::unordered_map<Level, std::size_t> m_logFlushThresholdMap;
LogStreamsReferenceMapPtr m_logStreamsReference = nullptr;
friend class el::Helpers;
friend class el::base::MessageBuilder;
friend class el::base::Writer;
friend class el::base::DefaultLogDispatchCallback;
friend class el::base::LogDispatcher;
template <typename Conf_T>
inline Conf_T getConfigByVal(Level level,
const std::unordered_map<Level, Conf_T> *confMap,
const char *confName) {
base::threading::ScopedLock scopedLock(lock());
return unsafeGetConfigByVal(
level, confMap,
confName); // This is not unsafe anymore - mutex locked in scope
}
template <typename Conf_T>
inline Conf_T &getConfigByRef(Level level,
std::unordered_map<Level, Conf_T> *confMap,
const char *confName) {
base::threading::ScopedLock scopedLock(lock());
return unsafeGetConfigByRef(
level, confMap,
confName); // This is not unsafe anymore - mutex locked in scope
}
template <typename Conf_T>
Conf_T unsafeGetConfigByVal(Level level,
const std::unordered_map<Level, Conf_T> *confMap,
const char *confName) {
ELPP_UNUSED(confName);
typename std::unordered_map<Level, Conf_T>::const_iterator it =
confMap->find(level);
if (it == confMap->end()) {
try {
return confMap->at(Level::Global);
} catch (...) {
ELPP_INTERNAL_ERROR(
"Unable to get configuration ["
<< confName << "] for level ["
<< LevelHelper::convertToString(level) << "]" << std::endl
<< "Please ensure you have properly configured logger.",
false);
return Conf_T();
}
}
return it->second;
}
template <typename Conf_T>
Conf_T &unsafeGetConfigByRef(Level level,
std::unordered_map<Level, Conf_T> *confMap,
const char *confName) {
ELPP_UNUSED(confName);
typename std::unordered_map<Level, Conf_T>::iterator it =
confMap->find(level);
if (it == confMap->end()) {
try {
return confMap->at(Level::Global);
} catch (...) {
ELPP_INTERNAL_ERROR(
"Unable to get configuration ["
<< confName << "] for level ["
<< LevelHelper::convertToString(level) << "]" << std::endl
<< "Please ensure you have properly configured logger.",
false);
}
}
return it->second;
}
template <typename Conf_T>
void setValue(Level level, const Conf_T &value,
std::unordered_map<Level, Conf_T> *confMap,
bool includeGlobalLevel = true) {
// If map is empty and we are allowed to add into generic level
// (Level::Global), do it!
if (confMap->empty() && includeGlobalLevel) {
confMap->insert(std::make_pair(Level::Global, value));
return;
}
// If same value exist in generic level already, dont add it to explicit
// level
typename std::unordered_map<Level, Conf_T>::iterator it =
confMap->find(Level::Global);
if (it != confMap->end() && it->second == value) {
return;
}
// Now make sure we dont double up values if we really need to add it to
// explicit level
it = confMap->find(level);
if (it == confMap->end()) {
// Value not found for level, add new
confMap->insert(std::make_pair(level, value));
} else {
// Value found, just update value
confMap->at(level) = value;
}
}
void build(Configurations *configurations);
unsigned long getULong(std::string confVal);
std::string resolveFilename(const std::string &filename);
void insertFile(Level level, const std::string &fullFilename);
bool unsafeValidateFileRolling(Level level,
const PreRollOutCallback &preRollOutCallback);
inline bool
validateFileRolling(Level level,
const PreRollOutCallback &preRollOutCallback) {
base::threading::ScopedLock scopedLock(lock());
return unsafeValidateFileRolling(level, preRollOutCallback);
}
};
/// @brief Class that keeps record of current line hit for occasional logging
class HitCounter {
public:
HitCounter(void) : m_filename(""), m_lineNumber(0), m_hitCounts(0) {}
HitCounter(const char *filename, base::type::LineNumber lineNumber)
: m_filename(filename), m_lineNumber(lineNumber), m_hitCounts(0) {}
HitCounter(const HitCounter &hitCounter)
: m_filename(hitCounter.m_filename),
m_lineNumber(hitCounter.m_lineNumber),
m_hitCounts(hitCounter.m_hitCounts) {}
HitCounter &operator=(const HitCounter &hitCounter) {
if (&hitCounter != this) {
m_filename = hitCounter.m_filename;
m_lineNumber = hitCounter.m_lineNumber;
m_hitCounts = hitCounter.m_hitCounts;
}
return *this;
}
virtual ~HitCounter(void) {}
/// @brief Resets location of current hit counter
inline void resetLocation(const char *filename,
base::type::LineNumber lineNumber) {
m_filename = filename;
m_lineNumber = lineNumber;
}
/// @brief Validates hit counts and resets it if necessary
inline void validateHitCounts(std::size_t n) {
if (m_hitCounts >= base::consts::kMaxLogPerCounter) {
m_hitCounts = (n >= 1 ? base::consts::kMaxLogPerCounter % n : 0);
}
++m_hitCounts;
}
inline const char *filename(void) const { return m_filename; }
inline base::type::LineNumber lineNumber(void) const { return m_lineNumber; }
inline std::size_t hitCounts(void) const { return m_hitCounts; }
inline void increment(void) { ++m_hitCounts; }
class Predicate {
public:
Predicate(const char *filename, base::type::LineNumber lineNumber)
: m_filename(filename), m_lineNumber(lineNumber) {}
inline bool operator()(const HitCounter *counter) {
return ((counter != nullptr) &&
(strcmp(counter->m_filename, m_filename) == 0) &&
(counter->m_lineNumber == m_lineNumber));
}
private:
const char *m_filename;
base::type::LineNumber m_lineNumber;
};
private:
const char *m_filename;
base::type::LineNumber m_lineNumber;
std::size_t m_hitCounts;
};
/// @brief Repository for hit counters used across the application
class RegisteredHitCounters
: public base::utils::RegistryWithPred<base::HitCounter,
base::HitCounter::Predicate> {
public:
/// @brief Validates counter for every N, i.e, registers new if does not exist
/// otherwise updates original one
/// @return True if validation resulted in triggering hit. Meaning logs should
/// be written everytime true is returned
bool validateEveryN(const char *filename, base::type::LineNumber lineNumber,
std::size_t n);
/// @brief Validates counter for hits >= N, i.e, registers new if does not
/// exist otherwise updates original one
/// @return True if validation resulted in triggering hit. Meaning logs should
/// be written everytime true is returned
bool validateAfterN(const char *filename, base::type::LineNumber lineNumber,
std::size_t n);
/// @brief Validates counter for hits are <= n, i.e, registers new if does not
/// exist otherwise updates original one
/// @return True if validation resulted in triggering hit. Meaning logs should
/// be written everytime true is returned
bool validateNTimes(const char *filename, base::type::LineNumber lineNumber,
std::size_t n);
/// @brief Gets hit counter registered at specified position
inline const base::HitCounter *getCounter(const char *filename,
base::type::LineNumber lineNumber) {
base::threading::ScopedLock scopedLock(lock());
return get(filename, lineNumber);
}
};
/// @brief Action to be taken for dispatching
enum class DispatchAction : base::type::EnumType {
None = 1,
NormalLog = 2,
SysLog = 4
};
} // namespace base
template <typename T> class Callback : protected base::threading::ThreadSafe {
public:
Callback(void) : m_enabled(true) {}
inline bool enabled(void) const { return m_enabled; }
inline void setEnabled(bool enabled) {
base::threading::ScopedLock scopedLock(lock());
m_enabled = enabled;
}
protected:
virtual void handle(const T *handlePtr) = 0;
private:
bool m_enabled;
};
class LogDispatchData {
public:
LogDispatchData()
: m_logMessage(nullptr), m_dispatchAction(base::DispatchAction::None) {}
inline const LogMessage *logMessage(void) const { return m_logMessage; }
inline base::DispatchAction dispatchAction(void) const {
return m_dispatchAction;
}
inline void setLogMessage(LogMessage *logMessage) {
m_logMessage = logMessage;
}
inline void setDispatchAction(base::DispatchAction dispatchAction) {
m_dispatchAction = dispatchAction;
}
private:
LogMessage *m_logMessage;
base::DispatchAction m_dispatchAction;
friend class base::LogDispatcher;
};
class LogDispatchCallback : public Callback<LogDispatchData> {
protected:
virtual void handle(const LogDispatchData *data);
base::threading::Mutex &fileHandle(const LogDispatchData *data);
private:
friend class base::LogDispatcher;
std::unordered_map<std::string, std::unique_ptr<base::threading::Mutex>>
m_fileLocks;
base::threading::Mutex m_fileLocksMapLock;
};
class PerformanceTrackingCallback : public Callback<PerformanceTrackingData> {
private:
friend class base::PerformanceTracker;
};
class LoggerRegistrationCallback : public Callback<Logger> {
private:
friend class base::RegisteredLoggers;
};
class LogBuilder : base::NoCopy {
public:
LogBuilder() : m_termSupportsColor(base::utils::OS::termSupportsColor()) {}
virtual ~LogBuilder(void) {
ELPP_INTERNAL_INFO(3, "Destroying log builder...")
}
virtual base::type::string_t build(const LogMessage *logMessage,
bool appendNewLine) const = 0;
void convertToColoredOutput(base::type::string_t *logLine, Level level);
private:
bool m_termSupportsColor;
friend class el::base::DefaultLogDispatchCallback;
};
typedef std::shared_ptr<LogBuilder> LogBuilderPtr;
/// @brief Represents a logger holding ID and configurations we need to write
/// logs
///
/// @detail This class does not write logs itself instead its used by writer to
/// read configurations from.
class Logger : public base::threading::ThreadSafe, public Loggable {
public:
Logger(const std::string &id,
base::LogStreamsReferenceMapPtr logStreamsReference);
Logger(const std::string &id, const Configurations &configurations,
base::LogStreamsReferenceMapPtr logStreamsReference);
Logger(const Logger &logger);
Logger &operator=(const Logger &logger);
virtual ~Logger(void) { base::utils::safeDelete(m_typedConfigurations); }
virtual inline void log(el::base::type::ostream_t &os) const {
os << m_id.c_str();
}
/// @brief Configures the logger using specified configurations.
void configure(const Configurations &configurations);
/// @brief Reconfigures logger using existing configurations
void reconfigure(void);
inline const std::string &id(void) const { return m_id; }
inline const std::string &parentApplicationName(void) const {
return m_parentApplicationName;
}
inline void
setParentApplicationName(const std::string &parentApplicationName) {
m_parentApplicationName = parentApplicationName;
}
inline Configurations *configurations(void) { return &m_configurations; }
inline base::TypedConfigurations *typedConfigurations(void) {
return m_typedConfigurations;
}
static bool isValidId(const std::string &id);
/// @brief Flushes logger to sync all log files for all levels
void flush(void);
void flush(Level level, base::type::fstream_t *fs);
inline bool isFlushNeeded(Level level) {
return ++m_unflushedCount.find(level)->second >=
m_typedConfigurations->logFlushThreshold(level);
}
inline LogBuilder *logBuilder(void) const { return m_logBuilder.get(); }
inline void setLogBuilder(const LogBuilderPtr &logBuilder) {
m_logBuilder = logBuilder;
}
inline bool enabled(Level level) const {
return m_typedConfigurations->enabled(level);
}
#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
#define LOGGER_LEVEL_WRITERS_SIGNATURES(FUNCTION_NAME) \
template <typename T, typename... Args> \
inline void FUNCTION_NAME(const char *, const T &, const Args &...); \
template <typename T> inline void FUNCTION_NAME(const T &);
template <typename T, typename... Args>
inline void verbose(int, const char *, const T &, const Args &...);
template <typename T> inline void verbose(int, const T &);
LOGGER_LEVEL_WRITERS_SIGNATURES(info)
LOGGER_LEVEL_WRITERS_SIGNATURES(debug)
LOGGER_LEVEL_WRITERS_SIGNATURES(warn)
LOGGER_LEVEL_WRITERS_SIGNATURES(error)
LOGGER_LEVEL_WRITERS_SIGNATURES(fatal)
LOGGER_LEVEL_WRITERS_SIGNATURES(trace)
#undef LOGGER_LEVEL_WRITERS_SIGNATURES
#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
private:
std::string m_id;
base::TypedConfigurations *m_typedConfigurations;
base::type::stringstream_t m_stream;
std::string m_parentApplicationName;
bool m_isConfigured;
Configurations m_configurations;
std::unordered_map<Level, unsigned int> m_unflushedCount;
base::LogStreamsReferenceMapPtr m_logStreamsReference = nullptr;
LogBuilderPtr m_logBuilder;
friend class el::LogMessage;
friend class el::Loggers;
friend class el::Helpers;
friend class el::base::RegisteredLoggers;
friend class el::base::DefaultLogDispatchCallback;
friend class el::base::MessageBuilder;
friend class el::base::Writer;
friend class el::base::PErrorWriter;
friend class el::base::Storage;
friend class el::base::PerformanceTracker;
friend class el::base::LogDispatcher;
Logger(void);
#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
template <typename T, typename... Args>
void log_(Level, int, const char *, const T &, const Args &...);
template <typename T> inline void log_(Level, int, const T &);
template <typename T, typename... Args>
void log(Level, const char *, const T &, const Args &...);
template <typename T> inline void log(Level, const T &);
#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
void initUnflushedCount(void);
inline base::type::stringstream_t &stream(void) { return m_stream; }
void resolveLoggerFormatSpec(void) const;
};
namespace base {
/// @brief Loggers repository
class RegisteredLoggers : public base::utils::Registry<Logger, std::string> {
public:
explicit RegisteredLoggers(const LogBuilderPtr &defaultLogBuilder);
virtual ~RegisteredLoggers(void) { unsafeFlushAll(); }
inline void setDefaultConfigurations(const Configurations &configurations) {
base::threading::ScopedLock scopedLock(lock());
m_defaultConfigurations.setFromBase(
const_cast<Configurations *>(&configurations));
}
inline Configurations *defaultConfigurations(void) {
return &m_defaultConfigurations;
}
Logger *get(const std::string &id, bool forceCreation = true);
template <typename T>
inline bool installLoggerRegistrationCallback(const std::string &id) {
return base::utils::Utils::installCallback<
T, base::type::LoggerRegistrationCallbackPtr>(
id, &m_loggerRegistrationCallbacks);
}
template <typename T>
inline void uninstallLoggerRegistrationCallback(const std::string &id) {
base::utils::Utils::uninstallCallback<
T, base::type::LoggerRegistrationCallbackPtr>(
id, &m_loggerRegistrationCallbacks);
}
template <typename T>
inline T *loggerRegistrationCallback(const std::string &id) {
return base::utils::Utils::callback<
T, base::type::LoggerRegistrationCallbackPtr>(
id, &m_loggerRegistrationCallbacks);
}
bool remove(const std::string &id);
inline bool has(const std::string &id) { return get(id, false) != nullptr; }
inline void unregister(Logger *&logger) {
base::threading::ScopedLock scopedLock(lock());
base::utils::Registry<Logger, std::string>::unregister(logger->id());
}
inline LogStreamsReferenceMapPtr logStreamsReference(void) {
return m_logStreamsReference;
}
inline void flushAll(void) {
base::threading::ScopedLock scopedLock(lock());
unsafeFlushAll();
}
inline void setDefaultLogBuilder(LogBuilderPtr &logBuilderPtr) {
base::threading::ScopedLock scopedLock(lock());
m_defaultLogBuilder = logBuilderPtr;
}
private:
LogBuilderPtr m_defaultLogBuilder;
Configurations m_defaultConfigurations;
base::LogStreamsReferenceMapPtr m_logStreamsReference = nullptr;
std::unordered_map<std::string, base::type::LoggerRegistrationCallbackPtr>
m_loggerRegistrationCallbacks;
friend class el::base::Storage;
void unsafeFlushAll(void);
};
/// @brief Represents registries for verbose logging
class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
public:
explicit VRegistry(base::type::VerboseLevel level,
base::type::EnumType *pFlags);
/// @brief Sets verbose level. Accepted range is 0-9
void setLevel(base::type::VerboseLevel level);
inline base::type::VerboseLevel level(void) const { return m_level; }
inline void clearModules(void) {
base::threading::ScopedLock scopedLock(lock());
m_modules.clear();
}
void setModules(const char *modules);
bool allowed(base::type::VerboseLevel vlevel, const char *file);
inline const std::unordered_map<std::string, base::type::VerboseLevel> &
modules(void) const {
return m_modules;
}
void setFromArgs(const base::utils::CommandLineArgs *commandLineArgs);
/// @brief Whether or not vModules enabled
inline bool vModulesEnabled(void) {
return !base::utils::hasFlag(LoggingFlag::DisableVModules, *m_pFlags);
}
private:
base::type::VerboseLevel m_level;
base::type::EnumType *m_pFlags;
std::unordered_map<std::string, base::type::VerboseLevel> m_modules;
};
} // namespace base
class LogMessage {
public:
LogMessage(Level level, const std::string &file, base::type::LineNumber line,
const std::string &func, base::type::VerboseLevel verboseLevel,
Logger *logger)
: m_level(level), m_file(file), m_line(line), m_func(func),
m_verboseLevel(verboseLevel), m_logger(logger),
m_message(logger->stream().str()) {}
inline Level level(void) const { return m_level; }
inline const std::string &file(void) const { return m_file; }
inline base::type::LineNumber line(void) const { return m_line; }
inline const std::string &func(void) const { return m_func; }
inline base::type::VerboseLevel verboseLevel(void) const {
return m_verboseLevel;
}
inline Logger *logger(void) const { return m_logger; }
inline const base::type::string_t &message(void) const { return m_message; }
private:
Level m_level;
std::string m_file;
base::type::LineNumber m_line;
std::string m_func;
base::type::VerboseLevel m_verboseLevel;
Logger *m_logger;
base::type::string_t m_message;
};
namespace base {
#if ELPP_ASYNC_LOGGING
class AsyncLogItem {
public:
explicit AsyncLogItem(const LogMessage &logMessage,
const LogDispatchData &data,
const base::type::string_t &logLine)
: m_logMessage(logMessage), m_dispatchData(data), m_logLine(logLine) {}
virtual ~AsyncLogItem() {}
inline LogMessage *logMessage(void) { return &m_logMessage; }
inline LogDispatchData *data(void) { return &m_dispatchData; }
inline base::type::string_t logLine(void) { return m_logLine; }
private:
LogMessage m_logMessage;
LogDispatchData m_dispatchData;
base::type::string_t m_logLine;
};
class AsyncLogQueue : public base::threading::ThreadSafe {
public:
virtual ~AsyncLogQueue() { ELPP_INTERNAL_INFO(6, "~AsyncLogQueue"); }
inline AsyncLogItem next(void) {
base::threading::ScopedLock scopedLock(lock());
AsyncLogItem result = m_queue.front();
m_queue.pop();
return result;
}
inline void push(const AsyncLogItem &item) {
base::threading::ScopedLock scopedLock(lock());
m_queue.push(item);
}
inline void pop(void) {
base::threading::ScopedLock scopedLock(lock());
m_queue.pop();
}
inline AsyncLogItem front(void) {
base::threading::ScopedLock scopedLock(lock());
return m_queue.front();
}
inline bool empty(void) {
base::threading::ScopedLock scopedLock(lock());
return m_queue.empty();
}
private:
std::queue<AsyncLogItem> m_queue;
};
class IWorker {
public:
virtual ~IWorker() {}
virtual void start() = 0;
};
#endif // ELPP_ASYNC_LOGGING
/// @brief Easylogging++ management storage
class Storage : base::NoCopy, public base::threading::ThreadSafe {
public:
#if ELPP_ASYNC_LOGGING
Storage(const LogBuilderPtr &defaultLogBuilder,
base::IWorker *asyncDispatchWorker);
#else
explicit Storage(const LogBuilderPtr &defaultLogBuilder);
#endif // ELPP_ASYNC_LOGGING
virtual ~Storage(void);
inline bool validateEveryNCounter(const char *filename,
base::type::LineNumber lineNumber,
std::size_t occasion) {
return hitCounters()->validateEveryN(filename, lineNumber, occasion);
}
inline bool validateAfterNCounter(const char *filename,
base::type::LineNumber lineNumber,
std::size_t n) {
return hitCounters()->validateAfterN(filename, lineNumber, n);
}
inline bool validateNTimesCounter(const char *filename,
base::type::LineNumber lineNumber,
std::size_t n) {
return hitCounters()->validateNTimes(filename, lineNumber, n);
}
inline base::RegisteredHitCounters *hitCounters(void) const {
return m_registeredHitCounters;
}
inline base::RegisteredLoggers *registeredLoggers(void) const {
return m_registeredLoggers;
}
inline base::VRegistry *vRegistry(void) const { return m_vRegistry; }
#if ELPP_ASYNC_LOGGING
inline base::AsyncLogQueue *asyncLogQueue(void) const {
return m_asyncLogQueue;
}
#endif // ELPP_ASYNC_LOGGING
inline const base::utils::CommandLineArgs *commandLineArgs(void) const {
return &m_commandLineArgs;
}
inline void addFlag(LoggingFlag flag) {
base::utils::addFlag(flag, &m_flags);
}
inline void removeFlag(LoggingFlag flag) {
base::utils::removeFlag(flag, &m_flags);
}
inline bool hasFlag(LoggingFlag flag) const {
return base::utils::hasFlag(flag, m_flags);
}
inline base::type::EnumType flags(void) const { return m_flags; }
inline void setFlags(base::type::EnumType flags) { m_flags = flags; }
inline void setPreRollOutCallback(const PreRollOutCallback &callback) {
m_preRollOutCallback = callback;
}
inline void unsetPreRollOutCallback(void) {
m_preRollOutCallback = base::defaultPreRollOutCallback;
}
inline PreRollOutCallback &preRollOutCallback(void) {
return m_preRollOutCallback;
}
bool hasCustomFormatSpecifier(const char *formatSpecifier);
void installCustomFormatSpecifier(
const CustomFormatSpecifier &customFormatSpecifier);
bool uninstallCustomFormatSpecifier(const char *formatSpecifier);
const std::vector<CustomFormatSpecifier> *customFormatSpecifiers(void) const {
return &m_customFormatSpecifiers;
}
base::threading::Mutex &customFormatSpecifiersLock() {
return m_customFormatSpecifiersLock;
}
inline void setLoggingLevel(Level level) { m_loggingLevel = level; }
template <typename T>
inline bool installLogDispatchCallback(const std::string &id) {
return base::utils::Utils::installCallback<
T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
}
template <typename T>
inline void uninstallLogDispatchCallback(const std::string &id) {
base::utils::Utils::uninstallCallback<T,
base::type::LogDispatchCallbackPtr>(
id, &m_logDispatchCallbacks);
}
template <typename T> inline T *logDispatchCallback(const std::string &id) {
return base::utils::Utils::callback<T, base::type::LogDispatchCallbackPtr>(
id, &m_logDispatchCallbacks);
}
#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
template <typename T>
inline bool installPerformanceTrackingCallback(const std::string &id) {
return base::utils::Utils::installCallback<
T, base::type::PerformanceTrackingCallbackPtr>(
id, &m_performanceTrackingCallbacks);
}
template <typename T>
inline void uninstallPerformanceTrackingCallback(const std::string &id) {
base::utils::Utils::uninstallCallback<
T, base::type::PerformanceTrackingCallbackPtr>(
id, &m_performanceTrackingCallbacks);
}
template <typename T>
inline T *performanceTrackingCallback(const std::string &id) {
return base::utils::Utils::callback<
T, base::type::PerformanceTrackingCallbackPtr>(
id, &m_performanceTrackingCallbacks);
}
#endif // defined(ELPP_FEATURE_ALL) ||
// defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
/// @brief Sets thread name for current thread. Requires std::thread
inline void setThreadName(const std::string &name) {
if (name.empty())
return;
base::threading::ScopedLock scopedLock(m_threadNamesLock);
m_threadNames[base::threading::getCurrentThreadId()] = name;
}
inline std::string getThreadName(const std::string &threadId) {
base::threading::ScopedLock scopedLock(m_threadNamesLock);
std::unordered_map<std::string, std::string>::const_iterator it =
m_threadNames.find(threadId);
if (it == m_threadNames.end()) {
return threadId;
}
return it->second;
}
private:
base::RegisteredHitCounters *m_registeredHitCounters;
base::RegisteredLoggers *m_registeredLoggers;
base::type::EnumType m_flags;
base::VRegistry *m_vRegistry;
#if ELPP_ASYNC_LOGGING
base::AsyncLogQueue *m_asyncLogQueue;
base::IWorker *m_asyncDispatchWorker;
#endif // ELPP_ASYNC_LOGGING
base::utils::CommandLineArgs m_commandLineArgs;
PreRollOutCallback m_preRollOutCallback;
std::unordered_map<std::string, base::type::LogDispatchCallbackPtr>
m_logDispatchCallbacks;
std::unordered_map<std::string, base::type::PerformanceTrackingCallbackPtr>
m_performanceTrackingCallbacks;
std::unordered_map<std::string, std::string> m_threadNames;
std::vector<CustomFormatSpecifier> m_customFormatSpecifiers;
base::threading::Mutex m_customFormatSpecifiersLock;
base::threading::Mutex m_threadNamesLock;
Level m_loggingLevel;
friend class el::Helpers;
friend class el::base::DefaultLogDispatchCallback;
friend class el::LogBuilder;
friend class el::base::MessageBuilder;
friend class el::base::Writer;
friend class el::base::PerformanceTracker;
friend class el::base::LogDispatcher;
void setApplicationArguments(int argc, char **argv);
inline void setApplicationArguments(int argc, const char **argv) {
setApplicationArguments(argc, const_cast<char **>(argv));
}
};
extern ELPP_EXPORT base::type::StoragePointer elStorage;
#define ELPP el::base::elStorage
class DefaultLogDispatchCallback : public LogDispatchCallback {
protected:
void handle(const LogDispatchData *data);
private:
const LogDispatchData *m_data;
void dispatch(base::type::string_t &&logLine);
};
#if ELPP_ASYNC_LOGGING
class AsyncLogDispatchCallback : public LogDispatchCallback {
protected:
void handle(const LogDispatchData *data);
};
class AsyncDispatchWorker : public base::IWorker,
public base::threading::ThreadSafe {
public:
AsyncDispatchWorker();
virtual ~AsyncDispatchWorker();
bool clean(void);
void emptyQueue(void);
virtual void start(void);
void handle(AsyncLogItem *logItem);
void run(void);
void setContinueRunning(bool value) {
base::threading::ScopedLock scopedLock(m_continueRunningLock);
m_continueRunning = value;
}
bool continueRunning(void) const { return m_continueRunning; }
private:
std::condition_variable cv;
bool m_continueRunning;
base::threading::Mutex m_continueRunningLock;
};
#endif // ELPP_ASYNC_LOGGING
} // namespace base
namespace base {
class DefaultLogBuilder : public LogBuilder {
public:
base::type::string_t build(const LogMessage *logMessage,
bool appendNewLine) const;
};
/// @brief Dispatches log messages
class LogDispatcher : base::NoCopy {
public:
LogDispatcher(bool proceed, LogMessage *logMessage,
base::DispatchAction dispatchAction)
: m_proceed(proceed), m_logMessage(logMessage),
m_dispatchAction(std::move(dispatchAction)) {}
void dispatch(void);
private:
bool m_proceed;
LogMessage *m_logMessage;
base::DispatchAction m_dispatchAction;
};
#if defined(ELPP_STL_LOGGING)
/// @brief Workarounds to write some STL logs
///
/// @detail There is workaround needed to loop through some stl containers. In
/// order to do that, we need iterable containers of same type and provide
/// iterator interface and pass it on to writeIterator(). Remember, this is
/// passed by value in constructor so that we dont change original containers.
/// This operation is as expensive as Big-O(std::min(class_.size(),
/// base::consts::kMaxLogPerContainer))
namespace workarounds {
/// @brief Abstract IterableContainer template that provides interface for
/// iterable classes of type T
template <typename T, typename Container> class IterableContainer {
public:
typedef typename Container::iterator iterator;
typedef typename Container::const_iterator const_iterator;
IterableContainer(void) {}
virtual ~IterableContainer(void) {}
iterator begin(void) { return getContainer().begin(); }
iterator end(void) { return getContainer().end(); }
private:
virtual Container &getContainer(void) = 0;
};
/// @brief Implements IterableContainer and provides iterable
/// std::priority_queue class
template <typename T, typename Container = std::vector<T>,
typename Comparator = std::less<typename Container::value_type>>
class IterablePriorityQueue
: public IterableContainer<T, Container>,
public std::priority_queue<T, Container, Comparator> {
public:
IterablePriorityQueue(std::priority_queue<T, Container, Comparator> queue_) {
std::size_t count_ = 0;
while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) {
this->push(queue_.top());
queue_.pop();
}
}
private:
inline Container &getContainer(void) { return this->c; }
};
/// @brief Implements IterableContainer and provides iterable std::queue class
template <typename T, typename Container = std::deque<T>>
class IterableQueue : public IterableContainer<T, Container>,
public std::queue<T, Container> {
public:
IterableQueue(std::queue<T, Container> queue_) {
std::size_t count_ = 0;
while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) {
this->push(queue_.front());
queue_.pop();
}
}
private:
inline Container &getContainer(void) { return this->c; }
};
/// @brief Implements IterableContainer and provides iterable std::stack class
template <typename T, typename Container = std::deque<T>>
class IterableStack : public IterableContainer<T, Container>,
public std::stack<T, Container> {
public:
IterableStack(std::stack<T, Container> stack_) {
std::size_t count_ = 0;
while (++count_ < base::consts::kMaxLogPerContainer && !stack_.empty()) {
this->push(stack_.top());
stack_.pop();
}
}
private:
inline Container &getContainer(void) { return this->c; }
};
} // namespace workarounds
#endif // defined(ELPP_STL_LOGGING)
// Log message builder
class MessageBuilder {
public:
MessageBuilder(void)
: m_logger(nullptr), m_containerLogSeparator(ELPP_LITERAL("")) {}
void initialize(Logger *logger);
#define ELPP_SIMPLE_LOG(LOG_TYPE) \
MessageBuilder &operator<<(LOG_TYPE msg) { \
m_logger->stream() << msg; \
if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) { \
m_logger->stream() << " "; \
} \
return *this; \
}
inline MessageBuilder &operator<<(const std::string &msg) {
return operator<<(msg.c_str());
}
ELPP_SIMPLE_LOG(char)
ELPP_SIMPLE_LOG(bool)
ELPP_SIMPLE_LOG(signed short)
ELPP_SIMPLE_LOG(unsigned short)
ELPP_SIMPLE_LOG(signed int)
ELPP_SIMPLE_LOG(unsigned int)
ELPP_SIMPLE_LOG(signed long)
ELPP_SIMPLE_LOG(unsigned long)
ELPP_SIMPLE_LOG(float)
ELPP_SIMPLE_LOG(double)
ELPP_SIMPLE_LOG(char *)
ELPP_SIMPLE_LOG(const char *)
ELPP_SIMPLE_LOG(const void *)
ELPP_SIMPLE_LOG(long double)
inline MessageBuilder &operator<<(const std::wstring &msg) {
return operator<<(msg.c_str());
}
MessageBuilder &operator<<(const wchar_t *msg);
// ostream manipulators
inline MessageBuilder &
operator<<(std::ostream &(*OStreamMani)(std::ostream &)) {
m_logger->stream() << OStreamMani;
return *this;
}
#define ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(temp) \
template <typename T> \
inline MessageBuilder &operator<<(const temp<T> &template_inst) { \
return writeIterator(template_inst.begin(), template_inst.end(), \
template_inst.size()); \
}
#define ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(temp) \
template <typename T1, typename T2> \
inline MessageBuilder &operator<<(const temp<T1, T2> &template_inst) { \
return writeIterator(template_inst.begin(), template_inst.end(), \
template_inst.size()); \
}
#define ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(temp) \
template <typename T1, typename T2, typename T3> \
inline MessageBuilder &operator<<(const temp<T1, T2, T3> &template_inst) { \
return writeIterator(template_inst.begin(), template_inst.end(), \
template_inst.size()); \
}
#define ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(temp) \
template <typename T1, typename T2, typename T3, typename T4> \
inline MessageBuilder &operator<<( \
const temp<T1, T2, T3, T4> &template_inst) { \
return writeIterator(template_inst.begin(), template_inst.end(), \
template_inst.size()); \
}
#define ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(temp) \
template <typename T1, typename T2, typename T3, typename T4, typename T5> \
inline MessageBuilder &operator<<( \
const temp<T1, T2, T3, T4, T5> &template_inst) { \
return writeIterator(template_inst.begin(), template_inst.end(), \
template_inst.size()); \
}
#if defined(ELPP_STL_LOGGING)
ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::vector)
ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::list)
ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::deque)
ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::set)
ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::multiset)
ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::map)
ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::multimap)
template <class T, class Container>
inline MessageBuilder &operator<<(const std::queue<T, Container> &queue_) {
base::workarounds::IterableQueue<T, Container> iterableQueue_ =
static_cast<base::workarounds::IterableQueue<T, Container>>(queue_);
return writeIterator(iterableQueue_.begin(), iterableQueue_.end(),
iterableQueue_.size());
}
template <class T, class Container>
inline MessageBuilder &operator<<(const std::stack<T, Container> &stack_) {
base::workarounds::IterableStack<T, Container> iterableStack_ =
static_cast<base::workarounds::IterableStack<T, Container>>(stack_);
return writeIterator(iterableStack_.begin(), iterableStack_.end(),
iterableStack_.size());
}
template <class T, class Container, class Comparator>
inline MessageBuilder &operator<<(
const std::priority_queue<T, Container, Comparator> &priorityQueue_) {
base::workarounds::IterablePriorityQueue<T, Container, Comparator>
iterablePriorityQueue_ = static_cast<
base::workarounds::IterablePriorityQueue<T, Container, Comparator>>(
priorityQueue_);
return writeIterator(iterablePriorityQueue_.begin(),
iterablePriorityQueue_.end(),
iterablePriorityQueue_.size());
}
template <class First, class Second>
MessageBuilder &operator<<(const std::pair<First, Second> &pair_) {
m_logger->stream() << ELPP_LITERAL("(");
operator<<(static_cast<First>(pair_.first));
m_logger->stream() << ELPP_LITERAL(", ");
operator<<(static_cast<Second>(pair_.second));
m_logger->stream() << ELPP_LITERAL(")");
return *this;
}
template <std::size_t Size>
MessageBuilder &operator<<(const std::bitset<Size> &bitset_) {
m_logger->stream() << ELPP_LITERAL("[");
operator<<(bitset_.to_string());
m_logger->stream() << ELPP_LITERAL("]");
return *this;
}
#if defined(ELPP_LOG_STD_ARRAY)
template <class T, std::size_t Size>
inline MessageBuilder &operator<<(const std::array<T, Size> &array) {
return writeIterator(array.begin(), array.end(), array.size());
}
#endif // defined(ELPP_LOG_STD_ARRAY)
#if defined(ELPP_LOG_UNORDERED_MAP)
ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_map)
ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_multimap)
#endif // defined(ELPP_LOG_UNORDERED_MAP)
#if defined(ELPP_LOG_UNORDERED_SET)
ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_set)
ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_multiset)
#endif // defined(ELPP_LOG_UNORDERED_SET)
#endif // defined(ELPP_STL_LOGGING)
#if defined(ELPP_QT_LOGGING)
inline MessageBuilder &operator<<(const QString &msg) {
#if defined(ELPP_UNICODE)
m_logger->stream() << msg.toStdWString();
#else
m_logger->stream() << msg.toStdString();
#endif // defined(ELPP_UNICODE)
return *this;
}
inline MessageBuilder &operator<<(const QByteArray &msg) {
return operator<<(QString(msg));
}
inline MessageBuilder &operator<<(const QStringRef &msg) {
return operator<<(msg.toString());
}
inline MessageBuilder &operator<<(qint64 msg) {
#if defined(ELPP_UNICODE)
m_logger->stream() << QString::number(msg).toStdWString();
#else
m_logger->stream() << QString::number(msg).toStdString();
#endif // defined(ELPP_UNICODE)
return *this;
}
inline MessageBuilder &operator<<(quint64 msg) {
#if defined(ELPP_UNICODE)
m_logger->stream() << QString::number(msg).toStdWString();
#else
m_logger->stream() << QString::number(msg).toStdString();
#endif // defined(ELPP_UNICODE)
return *this;
}
inline MessageBuilder &operator<<(QChar msg) {
m_logger->stream() << msg.toLatin1();
return *this;
}
inline MessageBuilder &operator<<(const QLatin1String &msg) {
m_logger->stream() << msg.latin1();
return *this;
}
ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QList)
ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QVector)
ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QQueue)
ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QSet)
ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QLinkedList)
ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QStack)
template <typename First, typename Second>
MessageBuilder &operator<<(const QPair<First, Second> &pair_) {
m_logger->stream() << ELPP_LITERAL("(");
operator<<(static_cast<First>(pair_.first));
m_logger->stream() << ELPP_LITERAL(", ");
operator<<(static_cast<Second>(pair_.second));
m_logger->stream() << ELPP_LITERAL(")");
return *this;
}
template <typename K, typename V>
MessageBuilder &operator<<(const QMap<K, V> &map_) {
m_logger->stream() << ELPP_LITERAL("[");
QList<K> keys = map_.keys();
typename QList<K>::const_iterator begin = keys.begin();
typename QList<K>::const_iterator end = keys.end();
int max_ = static_cast<int>(
base::consts::kMaxLogPerContainer); // to prevent warning
for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
m_logger->stream() << ELPP_LITERAL("(");
operator<<(static_cast<K>(*begin));
m_logger->stream() << ELPP_LITERAL(", ");
operator<<(static_cast<V>(map_.value(*begin)));
m_logger->stream() << ELPP_LITERAL(")");
m_logger->stream() << ((index_ < keys.size() - 1)
? m_containerLogSeparator
: ELPP_LITERAL(""));
}
if (begin != end) {
m_logger->stream() << ELPP_LITERAL("...");
}
m_logger->stream() << ELPP_LITERAL("]");
return *this;
}
template <typename K, typename V>
inline MessageBuilder &operator<<(const QMultiMap<K, V> &map_) {
operator<<(static_cast<QMap<K, V>>(map_));
return *this;
}
template <typename K, typename V>
MessageBuilder &operator<<(const QHash<K, V> &hash_) {
m_logger->stream() << ELPP_LITERAL("[");
QList<K> keys = hash_.keys();
typename QList<K>::const_iterator begin = keys.begin();
typename QList<K>::const_iterator end = keys.end();
int max_ = static_cast<int>(
base::consts::kMaxLogPerContainer); // prevent type warning
for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
m_logger->stream() << ELPP_LITERAL("(");
operator<<(static_cast<K>(*begin));
m_logger->stream() << ELPP_LITERAL(", ");
operator<<(static_cast<V>(hash_.value(*begin)));
m_logger->stream() << ELPP_LITERAL(")");
m_logger->stream() << ((index_ < keys.size() - 1)
? m_containerLogSeparator
: ELPP_LITERAL(""));
}
if (begin != end) {
m_logger->stream() << ELPP_LITERAL("...");
}
m_logger->stream() << ELPP_LITERAL("]");
return *this;
}
template <typename K, typename V>
inline MessageBuilder &operator<<(const QMultiHash<K, V> &multiHash_) {
operator<<(static_cast<QHash<K, V>>(multiHash_));
return *this;
}
#endif // defined(ELPP_QT_LOGGING)
#if defined(ELPP_BOOST_LOGGING)
ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::vector)
ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::stable_vector)
ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::list)
ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::deque)
ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::map)
ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::flat_map)
ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::set)
ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::flat_set)
#endif // defined(ELPP_BOOST_LOGGING)
/// @brief Macro used internally that can be used externally to make
/// containers easylogging++ friendly
///
/// @detail This macro expands to write an ostream& operator<< for container.
/// This container is expected to
/// have begin() and end() methods that return respective iterators
/// @param ContainerType Type of container e.g, MyList from
/// WX_DECLARE_LIST(int, MyList); in wxwidgets
/// @param SizeMethod Method used to get size of container.
/// @param ElementInstance Instance of element to be fed out. Instance name is
/// "elem". See WXELPP_ENABLED macro
/// for an example usage
#define MAKE_CONTAINERELPP_FRIENDLY(ContainerType, SizeMethod, \
ElementInstance) \
el::base::type::ostream_t &operator<<(el::base::type::ostream_t &ss, \
const ContainerType &container) { \
const el::base::type::char_t *sep = \
ELPP->hasFlag(el::LoggingFlag::NewLineForContainer) \
? ELPP_LITERAL("\n ") \
: ELPP_LITERAL(", "); \
ContainerType::const_iterator elem = container.begin(); \
ContainerType::const_iterator endElem = container.end(); \
std::size_t size_ = container.SizeMethod; \
ss << ELPP_LITERAL("["); \
for (std::size_t i = 0; \
elem != endElem && i < el::base::consts::kMaxLogPerContainer; \
++i, ++elem) { \
ss << ElementInstance; \
ss << ((i < size_ - 1) ? sep : ELPP_LITERAL("")); \
} \
if (elem != endElem) { \
ss << ELPP_LITERAL("..."); \
} \
ss << ELPP_LITERAL("]"); \
return ss; \
}
#if defined(ELPP_WXWIDGETS_LOGGING)
ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(wxVector)
#define ELPP_WX_PTR_ENABLED(ContainerType) \
MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), *(*elem))
#define ELPP_WX_ENABLED(ContainerType) \
MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), (*elem))
#define ELPP_WX_HASH_MAP_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), \
ELPP_LITERAL("(") << elem->first << ELPP_LITERAL(", ") << elem->second << ELPP_LITERAL(")")
#else
#define ELPP_WX_PTR_ENABLED(ContainerType)
#define ELPP_WX_ENABLED(ContainerType)
#define ELPP_WX_HASH_MAP_ENABLED(ContainerType)
#endif // defined(ELPP_WXWIDGETS_LOGGING)
// Other classes
template <class Class>
ELPP_SIMPLE_LOG(const Class &)
#undef ELPP_SIMPLE_LOG
#undef ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG
#undef ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG
#undef ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG
#undef ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG
#undef ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG
private : Logger *m_logger;
const base::type::char_t *m_containerLogSeparator;
template <class Iterator>
MessageBuilder &writeIterator(Iterator begin_, Iterator end_,
std::size_t size_) {
m_logger->stream() << ELPP_LITERAL("[");
for (std::size_t i = 0;
begin_ != end_ && i < base::consts::kMaxLogPerContainer;
++i, ++begin_) {
operator<<(*begin_);
m_logger->stream() << ((i < size_ - 1) ? m_containerLogSeparator
: ELPP_LITERAL(""));
}
if (begin_ != end_) {
m_logger->stream() << ELPP_LITERAL("...");
}
m_logger->stream() << ELPP_LITERAL("]");
if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {
m_logger->stream() << " ";
}
return *this;
}
};
/// @brief Writes nothing - Used when certain log is disabled
class NullWriter : base::NoCopy {
public:
NullWriter(void) {}
// Null manipulator
inline NullWriter &operator<<(std::ostream &(*)(std::ostream &)) {
return *this;
}
template <typename T> inline NullWriter &operator<<(const T &) {
return *this;
}
inline operator bool() { return true; }
};
/// @brief Main entry point of each logging
class Writer : base::NoCopy {
public:
Writer(Level level, const char *file, base::type::LineNumber line,
const char *func,
base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
base::type::VerboseLevel verboseLevel = 0)
: m_msg(nullptr), m_level(level), m_file(file), m_line(line),
m_func(func), m_verboseLevel(verboseLevel), m_logger(nullptr),
m_proceed(false), m_dispatchAction(dispatchAction) {}
Writer(LogMessage *msg,
base::DispatchAction dispatchAction = base::DispatchAction::NormalLog)
: m_msg(msg), m_level(msg != nullptr ? msg->level() : Level::Unknown),
m_line(0), m_logger(nullptr), m_proceed(false),
m_dispatchAction(dispatchAction) {}
virtual ~Writer(void) { processDispatch(); }
template <typename T> inline Writer &operator<<(const T &log) {
#if ELPP_LOGGING_ENABLED
if (m_proceed) {
m_messageBuilder << log;
}
#endif // ELPP_LOGGING_ENABLED
return *this;
}
inline Writer &operator<<(std::ostream &(*log)(std::ostream &)) {
#if ELPP_LOGGING_ENABLED
if (m_proceed) {
m_messageBuilder << log;
}
#endif // ELPP_LOGGING_ENABLED
return *this;
}
inline operator bool() { return true; }
Writer &construct(Logger *logger, bool needLock = true);
Writer &construct(int count, const char *loggerIds, ...);
protected:
LogMessage *m_msg;
Level m_level;
const char *m_file;
const base::type::LineNumber m_line;
const char *m_func;
base::type::VerboseLevel m_verboseLevel;
Logger *m_logger;
bool m_proceed;
base::MessageBuilder m_messageBuilder;
base::DispatchAction m_dispatchAction;
std::vector<std::string> m_loggerIds;
friend class el::Helpers;
void initializeLogger(const std::string &loggerId, bool lookup = true,
bool needLock = true);
void processDispatch();
void triggerDispatch(void);
};
class PErrorWriter : public base::Writer {
public:
PErrorWriter(
Level level, const char *file, base::type::LineNumber line,
const char *func,
base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
base::type::VerboseLevel verboseLevel = 0)
: base::Writer(level, file, line, func, dispatchAction, verboseLevel) {}
virtual ~PErrorWriter(void);
};
} // namespace base
// Logging from Logger class. Why this is here? Because we have Storage and
// Writer class available
#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
template <typename T, typename... Args>
void Logger::log_(Level level, int vlevel, const char *s, const T &value,
const Args &...args) {
base::MessageBuilder b;
b.initialize(this);
while (*s) {
if (*s == base::consts::kFormatSpecifierChar) {
if (*(s + 1) == base::consts::kFormatSpecifierChar) {
++s;
} else {
if (*(s + 1) == base::consts::kFormatSpecifierCharValue) {
++s;
b << value;
log_(level, vlevel, ++s, args...);
return;
}
}
}
b << *s++;
}
ELPP_INTERNAL_ERROR("Too many arguments provided. Unable to handle. Please "
"provide more format specifiers",
false);
}
template <typename T> void Logger::log_(Level level, int vlevel, const T &log) {
if (level == Level::Verbose) {
if (ELPP->vRegistry()->allowed(vlevel, __FILE__)) {
base::Writer(Level::Verbose, "FILE", 0, "FUNCTION",
base::DispatchAction::NormalLog, vlevel)
.construct(this, false)
<< log;
} else {
stream().str(ELPP_LITERAL(""));
releaseLock();
}
} else {
base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log;
}
}
template <typename T, typename... Args>
inline void Logger::log(Level level, const char *s, const T &value,
const Args &...args) {
acquireLock(); // released in Writer!
log_(level, 0, s, value, args...);
}
template <typename T> inline void Logger::log(Level level, const T &log) {
acquireLock(); // released in Writer!
log_(level, 0, log);
}
#if ELPP_VERBOSE_LOG
template <typename T, typename... Args>
inline void Logger::verbose(int vlevel, const char *s, const T &value,
const Args &...args) {
acquireLock(); // released in Writer!
log_(el::Level::Verbose, vlevel, s, value, args...);
}
template <typename T> inline void Logger::verbose(int vlevel, const T &log) {
acquireLock(); // released in Writer!
log_(el::Level::Verbose, vlevel, log);
}
#else
template <typename T, typename... Args>
inline void Logger::verbose(int, const char *, const T &, const Args &...) {
return;
}
template <typename T> inline void Logger::verbose(int, const T &) { return; }
#endif // ELPP_VERBOSE_LOG
#define LOGGER_LEVEL_WRITERS(FUNCTION_NAME, LOG_LEVEL) \
template <typename T, typename... Args> \
inline void Logger::FUNCTION_NAME(const char *s, const T &value, \
const Args &...args) { \
log(LOG_LEVEL, s, value, args...); \
} \
template <typename T> inline void Logger::FUNCTION_NAME(const T &value) { \
log(LOG_LEVEL, value); \
}
#define LOGGER_LEVEL_WRITERS_DISABLED(FUNCTION_NAME, LOG_LEVEL) \
template <typename T, typename... Args> \
inline void Logger::FUNCTION_NAME(const char *, const T &, \
const Args &...) { \
return; \
} \
template <typename T> inline void Logger::FUNCTION_NAME(const T &) { return; }
#if ELPP_INFO_LOG
LOGGER_LEVEL_WRITERS(info, Level::Info)
#else
LOGGER_LEVEL_WRITERS_DISABLED(info, Level::Info)
#endif // ELPP_INFO_LOG
#if ELPP_DEBUG_LOG
LOGGER_LEVEL_WRITERS(debug, Level::Debug)
#else
LOGGER_LEVEL_WRITERS_DISABLED(debug, Level::Debug)
#endif // ELPP_DEBUG_LOG
#if ELPP_WARNING_LOG
LOGGER_LEVEL_WRITERS(warn, Level::Warning)
#else
LOGGER_LEVEL_WRITERS_DISABLED(warn, Level::Warning)
#endif // ELPP_WARNING_LOG
#if ELPP_ERROR_LOG
LOGGER_LEVEL_WRITERS(error, Level::Error)
#else
LOGGER_LEVEL_WRITERS_DISABLED(error, Level::Error)
#endif // ELPP_ERROR_LOG
#if ELPP_FATAL_LOG
LOGGER_LEVEL_WRITERS(fatal, Level::Fatal)
#else
LOGGER_LEVEL_WRITERS_DISABLED(fatal, Level::Fatal)
#endif // ELPP_FATAL_LOG
#if ELPP_TRACE_LOG
LOGGER_LEVEL_WRITERS(trace, Level::Trace)
#else
LOGGER_LEVEL_WRITERS_DISABLED(trace, Level::Trace)
#endif // ELPP_TRACE_LOG
#undef LOGGER_LEVEL_WRITERS
#undef LOGGER_LEVEL_WRITERS_DISABLED
#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
#if ELPP_COMPILER_MSVC
#define ELPP_VARIADIC_FUNC_MSVC(variadicFunction, variadicArgs) \
variadicFunction variadicArgs
#define ELPP_VARIADIC_FUNC_MSVC_RUN(variadicFunction, ...) \
ELPP_VARIADIC_FUNC_MSVC(variadicFunction, (__VA_ARGS__))
#define el_getVALength(...) \
ELPP_VARIADIC_FUNC_MSVC_RUN(el_resolveVALength, 0, ##__VA_ARGS__, 10, 9, 8, \
7, 6, 5, 4, 3, 2, 1, 0)
#else
#if ELPP_COMPILER_CLANG
#define el_getVALength(...) \
el_resolveVALength(0, __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#else
#define el_getVALength(...) \
el_resolveVALength(0, ##__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#endif // ELPP_COMPILER_CLANG
#endif // ELPP_COMPILER_MSVC
#define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, \
...) \
N
#define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \
writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction) \
.construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
#define ELPP_WRITE_LOG_IF(writer, condition, level, dispatchAction, ...) \
if (condition) \
writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction) \
.construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
#define ELPP_WRITE_LOG_EVERY_N(writer, occasion, level, dispatchAction, ...) \
ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion) && \
writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction) \
.construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
#define ELPP_WRITE_LOG_AFTER_N(writer, n, level, dispatchAction, ...) \
ELPP->validateAfterNCounter(__FILE__, __LINE__, n) && \
writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction) \
.construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
#define ELPP_WRITE_LOG_N_TIMES(writer, n, level, dispatchAction, ...) \
ELPP->validateNTimesCounter(__FILE__, __LINE__, n) && \
writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction) \
.construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
class PerformanceTrackingData {
public:
enum class DataType : base::type::EnumType { Checkpoint = 1, Complete = 2 };
// Do not use constructor, will run into multiple definition error, use
// init(PerformanceTracker*)
explicit PerformanceTrackingData(DataType dataType)
: m_performanceTracker(nullptr), m_dataType(dataType),
m_firstCheckpoint(false), m_file(""), m_line(0), m_func("") {}
inline const std::string *blockName(void) const;
inline const struct timeval *startTime(void) const;
inline const struct timeval *endTime(void) const;
inline const struct timeval *lastCheckpointTime(void) const;
inline const base::PerformanceTracker *performanceTracker(void) const {
return m_performanceTracker;
}
inline PerformanceTrackingData::DataType dataType(void) const {
return m_dataType;
}
inline bool firstCheckpoint(void) const { return m_firstCheckpoint; }
inline std::string checkpointId(void) const { return m_checkpointId; }
inline const char *file(void) const { return m_file; }
inline base::type::LineNumber line(void) const { return m_line; }
inline const char *func(void) const { return m_func; }
inline const base::type::string_t *formattedTimeTaken() const {
return &m_formattedTimeTaken;
}
inline const std::string &loggerId(void) const;
private:
base::PerformanceTracker *m_performanceTracker;
base::type::string_t m_formattedTimeTaken;
PerformanceTrackingData::DataType m_dataType;
bool m_firstCheckpoint;
std::string m_checkpointId;
const char *m_file;
base::type::LineNumber m_line;
const char *m_func;
inline void init(base::PerformanceTracker *performanceTracker,
bool firstCheckpoint = false) {
m_performanceTracker = performanceTracker;
m_firstCheckpoint = firstCheckpoint;
}
friend class el::base::PerformanceTracker;
};
namespace base {
/// @brief Represents performanceTracker block of code that conditionally adds
/// performance status to log
/// either when goes outside the scope of when checkpoint() is called
class PerformanceTracker : public base::threading::ThreadSafe, public Loggable {
public:
PerformanceTracker(
const std::string &blockName,
base::TimestampUnit timestampUnit = base::TimestampUnit::Millisecond,
const std::string &loggerId =
std::string(el::base::consts::kPerformanceLoggerId),
bool scopedLog = true,
Level level = base::consts::kPerformanceTrackerDefaultLevel);
/// @brief Copy constructor
PerformanceTracker(const PerformanceTracker &t)
: m_blockName(t.m_blockName), m_timestampUnit(t.m_timestampUnit),
m_loggerId(t.m_loggerId), m_scopedLog(t.m_scopedLog),
m_level(t.m_level), m_hasChecked(t.m_hasChecked),
m_lastCheckpointId(t.m_lastCheckpointId), m_enabled(t.m_enabled),
m_startTime(t.m_startTime), m_endTime(t.m_endTime),
m_lastCheckpointTime(t.m_lastCheckpointTime) {}
virtual ~PerformanceTracker(void);
/// @brief A checkpoint for current performanceTracker block.
void checkpoint(const std::string &id = std::string(),
const char *file = __FILE__,
base::type::LineNumber line = __LINE__,
const char *func = "");
inline Level level(void) const { return m_level; }
private:
std::string m_blockName;
base::TimestampUnit m_timestampUnit;
std::string m_loggerId;
bool m_scopedLog;
Level m_level;
bool m_hasChecked;
std::string m_lastCheckpointId;
bool m_enabled;
struct timeval m_startTime, m_endTime, m_lastCheckpointTime;
PerformanceTracker(void);
friend class el::PerformanceTrackingData;
friend class base::DefaultPerformanceTrackingCallback;
const inline base::type::string_t getFormattedTimeTaken() const {
return getFormattedTimeTaken(m_startTime);
}
const base::type::string_t
getFormattedTimeTaken(struct timeval startTime) const;
virtual inline void log(el::base::type::ostream_t &os) const {
os << getFormattedTimeTaken();
}
};
class DefaultPerformanceTrackingCallback : public PerformanceTrackingCallback {
protected:
void handle(const PerformanceTrackingData *data) {
m_data = data;
base::type::stringstream_t ss;
if (m_data->dataType() == PerformanceTrackingData::DataType::Complete) {
ss << ELPP_LITERAL("Executed [") << m_data->blockName()->c_str()
<< ELPP_LITERAL("] in [") << *m_data->formattedTimeTaken()
<< ELPP_LITERAL("]");
} else {
ss << ELPP_LITERAL("Performance checkpoint");
if (!m_data->checkpointId().empty()) {
ss << ELPP_LITERAL(" [") << m_data->checkpointId().c_str()
<< ELPP_LITERAL("]");
}
ss << ELPP_LITERAL(" for block [") << m_data->blockName()->c_str()
<< ELPP_LITERAL("] : [") << *m_data->performanceTracker();
if (!ELPP->hasFlag(
LoggingFlag::DisablePerformanceTrackingCheckpointComparison) &&
m_data->performanceTracker()->m_hasChecked) {
ss << ELPP_LITERAL(" ([") << *m_data->formattedTimeTaken()
<< ELPP_LITERAL("] from ");
if (m_data->performanceTracker()->m_lastCheckpointId.empty()) {
ss << ELPP_LITERAL("last checkpoint");
} else {
ss << ELPP_LITERAL("checkpoint '")
<< m_data->performanceTracker()->m_lastCheckpointId.c_str()
<< ELPP_LITERAL("'");
}
ss << ELPP_LITERAL(")]");
} else {
ss << ELPP_LITERAL("]");
}
}
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();
}
private:
const PerformanceTrackingData *m_data;
};
} // namespace base
inline const std::string *PerformanceTrackingData::blockName() const {
return const_cast<const std::string *>(&m_performanceTracker->m_blockName);
}
inline const struct timeval *PerformanceTrackingData::startTime() const {
return const_cast<const struct timeval *>(&m_performanceTracker->m_startTime);
}
inline const struct timeval *PerformanceTrackingData::endTime() const {
return const_cast<const struct timeval *>(&m_performanceTracker->m_endTime);
}
inline const struct timeval *
PerformanceTrackingData::lastCheckpointTime() const {
return const_cast<const struct timeval *>(
&m_performanceTracker->m_lastCheckpointTime);
}
inline const std::string &PerformanceTrackingData::loggerId(void) const {
return m_performanceTracker->m_loggerId;
}
#endif // defined(ELPP_FEATURE_ALL) ||
// defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
namespace base {
/// @brief Contains some internal debugging tools like crash handler and stack
/// tracer
namespace debug {
#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
class StackTrace : base::NoCopy {
public:
static const unsigned int kMaxStack = 64;
static const unsigned int kStackStart =
2; // We want to skip c'tor and StackTrace::generateNew()
class StackTraceEntry {
public:
StackTraceEntry(std::size_t index, const std::string &loc,
const std::string &demang, const std::string &hex,
const std::string &addr);
StackTraceEntry(std::size_t index, const std::string &loc)
: m_index(index), m_location(loc) {}
std::size_t m_index;
std::string m_location;
std::string m_demangled;
std::string m_hex;
std::string m_addr;
friend std::ostream &operator<<(std::ostream &ss,
const StackTraceEntry &si);
private:
StackTraceEntry(void);
};
StackTrace(void) { generateNew(); }
virtual ~StackTrace(void) {}
inline std::vector<StackTraceEntry> &getLatestStack(void) { return m_stack; }
friend std::ostream &operator<<(std::ostream &os, const StackTrace &st);
private:
std::vector<StackTraceEntry> m_stack;
void generateNew(void);
};
/// @brief Handles unexpected crashes
class CrashHandler : base::NoCopy {
public:
typedef void (*Handler)(int);
explicit CrashHandler(bool useDefault);
explicit CrashHandler(const Handler &cHandler) { setHandler(cHandler); }
void setHandler(const Handler &cHandler);
private:
Handler m_handler;
};
#else
class CrashHandler {
public:
explicit CrashHandler(bool) {}
};
#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
} // namespace debug
} // namespace base
extern base::debug::CrashHandler elCrashHandler;
#define MAKE_LOGGABLE(ClassType, ClassInstance, OutputStreamInstance) \
el::base::type::ostream_t &operator<<( \
el::base::type::ostream_t &OutputStreamInstance, \
const ClassType &ClassInstance)
/// @brief Initializes syslog with process ID, options and facility. calls
/// closelog() on d'tor
class SysLogInitializer {
public:
SysLogInitializer(const char *processIdent, int options = 0,
int facility = 0) {
#if defined(ELPP_SYSLOG)
(void)base::consts::kSysLogLoggerId;
openlog(processIdent, options, facility);
#else
ELPP_UNUSED(processIdent);
ELPP_UNUSED(options);
ELPP_UNUSED(facility);
#endif // defined(ELPP_SYSLOG)
}
virtual ~SysLogInitializer(void) {
#if defined(ELPP_SYSLOG)
closelog();
#endif // defined(ELPP_SYSLOG)
}
};
#define ELPP_INITIALIZE_SYSLOG(id, opt, fac) \
el::SysLogInitializer elSyslogInit(id, opt, fac)
/// @brief Static helpers for developers
class Helpers : base::StaticClass {
public:
/// @brief Shares logging repository (base::Storage)
static inline void setStorage(base::type::StoragePointer storage) {
ELPP = storage;
}
/// @return Main storage repository
static inline base::type::StoragePointer storage() { return ELPP; }
/// @brief Sets application arguments and figures out whats active for logging
/// and whats not.
static inline void setArgs(int argc, char **argv) {
ELPP->setApplicationArguments(argc, argv);
}
/// @copydoc setArgs(int argc, char** argv)
static inline void setArgs(int argc, const char **argv) {
ELPP->setApplicationArguments(argc, const_cast<char **>(argv));
}
/// @brief Sets thread name for current thread. Requires std::thread
static inline void setThreadName(const std::string &name) {
ELPP->setThreadName(name);
}
static inline std::string getThreadName() {
return ELPP->getThreadName(base::threading::getCurrentThreadId());
}
#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
/// @brief Overrides default crash handler and installs custom handler.
/// @param crashHandler A functor with no return type that takes single int
/// argument.
/// Handler is a typedef with specification: void (*Handler)(int)
static inline void
setCrashHandler(const el::base::debug::CrashHandler::Handler &crashHandler) {
el::elCrashHandler.setHandler(crashHandler);
}
/// @brief Abort due to crash with signal in parameter
/// @param sig Crash signal
static void crashAbort(int sig, const char *sourceFile = "",
unsigned int long line = 0);
/// @brief Logs reason of crash as per sig
/// @param sig Crash signal
/// @param stackTraceIfAvailable Includes stack trace if available
/// @param level Logging level
/// @param logger Logger to use for logging
static void
logCrashReason(int sig, bool stackTraceIfAvailable = false,
Level level = Level::Fatal,
const char *logger = base::consts::kDefaultLoggerId);
#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
/// @brief Installs pre rollout callback, this callback is triggered when log
/// file is about to be rolled out
/// (can be useful for backing up)
static inline void
installPreRollOutCallback(const PreRollOutCallback &callback) {
ELPP->setPreRollOutCallback(callback);
}
/// @brief Uninstalls pre rollout callback
static inline void uninstallPreRollOutCallback(void) {
ELPP->unsetPreRollOutCallback();
}
/// @brief Installs post log dispatch callback, this callback is triggered
/// when log is dispatched
template <typename T>
static inline bool installLogDispatchCallback(const std::string &id) {
return ELPP->installLogDispatchCallback<T>(id);
}
/// @brief Uninstalls log dispatch callback
template <typename T>
static inline void uninstallLogDispatchCallback(const std::string &id) {
ELPP->uninstallLogDispatchCallback<T>(id);
}
template <typename T>
static inline T *logDispatchCallback(const std::string &id) {
return ELPP->logDispatchCallback<T>(id);
}
#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
/// @brief Installs post performance tracking callback, this callback is
/// triggered when performance tracking is finished
template <typename T>
static inline bool installPerformanceTrackingCallback(const std::string &id) {
return ELPP->installPerformanceTrackingCallback<T>(id);
}
/// @brief Uninstalls post performance tracking handler
template <typename T>
static inline void
uninstallPerformanceTrackingCallback(const std::string &id) {
ELPP->uninstallPerformanceTrackingCallback<T>(id);
}
template <typename T>
static inline T *performanceTrackingCallback(const std::string &id) {
return ELPP->performanceTrackingCallback<T>(id);
}
#endif // defined(ELPP_FEATURE_ALL) ||
// defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
/// @brief Converts template to std::string - useful for loggable classes to
/// log containers within log(std::ostream&) const
template <typename T>
static std::string convertTemplateToStdString(const T &templ) {
el::Logger *logger =
ELPP->registeredLoggers()->get(el::base::consts::kDefaultLoggerId);
if (logger == nullptr) {
return std::string();
}
base::MessageBuilder b;
b.initialize(logger);
logger->acquireLock();
b << templ;
#if defined(ELPP_UNICODE)
std::string s = std::string(logger->stream().str().begin(),
logger->stream().str().end());
#else
std::string s = logger->stream().str();
#endif // defined(ELPP_UNICODE)
logger->stream().str(ELPP_LITERAL(""));
logger->releaseLock();
return s;
}
/// @brief Returns command line arguments (pointer) provided to easylogging++
static inline const el::base::utils::CommandLineArgs *commandLineArgs(void) {
return ELPP->commandLineArgs();
}
/// @brief Reserve space for custom format specifiers for performance
/// @see std::vector::reserve
static inline void reserveCustomFormatSpecifiers(std::size_t size) {
ELPP->m_customFormatSpecifiers.reserve(size);
}
/// @brief Installs user defined format specifier and handler
static inline void installCustomFormatSpecifier(
const CustomFormatSpecifier &customFormatSpecifier) {
ELPP->installCustomFormatSpecifier(customFormatSpecifier);
}
/// @brief Uninstalls user defined format specifier and handler
static inline bool
uninstallCustomFormatSpecifier(const char *formatSpecifier) {
return ELPP->uninstallCustomFormatSpecifier(formatSpecifier);
}
/// @brief Returns true if custom format specifier is installed
static inline bool hasCustomFormatSpecifier(const char *formatSpecifier) {
return ELPP->hasCustomFormatSpecifier(formatSpecifier);
}
static inline void validateFileRolling(Logger *logger, Level level) {
if (ELPP == nullptr || logger == nullptr)
return;
logger->m_typedConfigurations->validateFileRolling(
level, ELPP->preRollOutCallback());
}
};
/// @brief Static helpers to deal with loggers and their configurations
class Loggers : base::StaticClass {
public:
/// @brief Gets existing or registers new logger
static Logger *getLogger(const std::string &identity,
bool registerIfNotAvailable = true);
/// @brief Changes default log builder for future loggers
static void setDefaultLogBuilder(el::LogBuilderPtr &logBuilderPtr);
/// @brief Installs logger registration callback, this callback is triggered
/// when new logger is registered
template <typename T>
static inline bool installLoggerRegistrationCallback(const std::string &id) {
return ELPP->registeredLoggers()->installLoggerRegistrationCallback<T>(id);
}
/// @brief Uninstalls log dispatch callback
template <typename T>
static inline void
uninstallLoggerRegistrationCallback(const std::string &id) {
ELPP->registeredLoggers()->uninstallLoggerRegistrationCallback<T>(id);
}
template <typename T>
static inline T *loggerRegistrationCallback(const std::string &id) {
return ELPP->registeredLoggers()->loggerRegistrationCallback<T>(id);
}
/// @brief Unregisters logger - use it only when you know what you are doing,
/// you may unregister
/// loggers initialized / used by third-party libs.
static bool unregisterLogger(const std::string &identity);
/// @brief Whether or not logger with id is registered
static bool hasLogger(const std::string &identity);
/// @brief Reconfigures specified logger with new configurations
static Logger *reconfigureLogger(Logger *logger,
const Configurations &configurations);
/// @brief Reconfigures logger with new configurations after looking it up
/// using identity
static Logger *reconfigureLogger(const std::string &identity,
const Configurations &configurations);
/// @brief Reconfigures logger's single configuration
static Logger *reconfigureLogger(const std::string &identity,
ConfigurationType configurationType,
const std::string &value);
/// @brief Reconfigures all the existing loggers with new configurations
static void reconfigureAllLoggers(const Configurations &configurations);
/// @brief Reconfigures single configuration for all the loggers
static inline void reconfigureAllLoggers(ConfigurationType configurationType,
const std::string &value) {
reconfigureAllLoggers(Level::Global, configurationType, value);
}
/// @brief Reconfigures single configuration for all the loggers for specified
/// level
static void reconfigureAllLoggers(Level level,
ConfigurationType configurationType,
const std::string &value);
/// @brief Sets default configurations. This configuration is used for future
/// (and conditionally for existing) loggers
static void setDefaultConfigurations(const Configurations &configurations,
bool reconfigureExistingLoggers = false);
/// @brief Returns current default
static const Configurations *defaultConfigurations(void);
/// @brief Returns log stream reference pointer if needed by user
static const base::LogStreamsReferenceMapPtr logStreamsReference(void);
/// @brief Default typed configuration based on existing defaultConf
static base::TypedConfigurations defaultTypedConfigurations(void);
/// @brief Populates all logger IDs in current repository.
/// @param [out] targetList List of fill up.
static std::vector<std::string> *
populateAllLoggerIds(std::vector<std::string> *targetList);
/// @brief Sets configurations from global configuration file.
static void configureFromGlobal(const char *globalConfigurationFilePath);
/// @brief Configures loggers using command line arg. Ensure you have already
/// set command line args,
/// @return False if invalid argument or argument with no value provided, true
/// if attempted to configure logger.
/// If true is returned that does not mean it has been configured
/// successfully, it only means that it has attempted to configure
/// logger using configuration file provided in argument
static bool configureFromArg(const char *argKey);
/// @brief Flushes all loggers for all levels - Be careful if you dont know
/// how many loggers are registered
static void flushAll(void);
/// @brief Adds logging flag used internally.
static inline void addFlag(LoggingFlag flag) { ELPP->addFlag(flag); }
/// @brief Removes logging flag used internally.
static inline void removeFlag(LoggingFlag flag) { ELPP->removeFlag(flag); }
/// @brief Determines whether or not certain flag is active
static inline bool hasFlag(LoggingFlag flag) { return ELPP->hasFlag(flag); }
/// @brief Adds flag and removes it when scope goes out
class ScopedAddFlag {
public:
ScopedAddFlag(LoggingFlag flag) : m_flag(flag) { Loggers::addFlag(m_flag); }
~ScopedAddFlag(void) { Loggers::removeFlag(m_flag); }
private:
LoggingFlag m_flag;
};
/// @brief Removes flag and add it when scope goes out
class ScopedRemoveFlag {
public:
ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) {
Loggers::removeFlag(m_flag);
}
~ScopedRemoveFlag(void) { Loggers::addFlag(m_flag); }
private:
LoggingFlag m_flag;
};
/// @brief Sets hierarchy for logging. Needs to enable logging flag
/// (HierarchicalLogging)
static void setLoggingLevel(Level level) { ELPP->setLoggingLevel(level); }
/// @brief Sets verbose level on the fly
static void setVerboseLevel(base::type::VerboseLevel level);
/// @brief Gets current verbose level
static base::type::VerboseLevel verboseLevel(void);
/// @brief Sets vmodules as specified (on the fly)
static void setVModules(const char *modules);
/// @brief Clears vmodules
static void clearVModules(void);
};
class VersionInfo : base::StaticClass {
public:
/// @brief Current version number
static const std::string version(void);
/// @brief Release date of current version
static const std::string releaseDate(void);
};
} // namespace el
#undef VLOG_IS_ON
/// @brief Determines whether verbose logging is on for specified level current
/// file.
#define VLOG_IS_ON(verboseLevel) \
(ELPP->vRegistry()->allowed(verboseLevel, __FILE__))
#undef TIMED_BLOCK
#undef TIMED_SCOPE
#undef TIMED_SCOPE_IF
#undef TIMED_FUNC
#undef TIMED_FUNC_IF
#undef ELPP_MIN_UNIT
#if defined(ELPP_PERFORMANCE_MICROSECONDS)
#define ELPP_MIN_UNIT el::base::TimestampUnit::Microsecond
#else
#define ELPP_MIN_UNIT el::base::TimestampUnit::Millisecond
#endif // (defined(ELPP_PERFORMANCE_MICROSECONDS))
/// @brief Performance tracked scope. Performance gets written when goes out of
/// scope using
/// 'performance' logger.
///
/// @detail Please note in order to check the performance at a certain time you
/// can use obj->checkpoint();
/// @see el::base::PerformanceTracker
/// @see el::base::PerformanceTracker::checkpoint
// Note: Do not surround this definition with null macro because of obj instance
#define TIMED_SCOPE_IF(obj, blockname, condition) \
el::base::type::PerformanceTrackerPtr obj( \
condition ? new el::base::PerformanceTracker(blockname, ELPP_MIN_UNIT) \
: nullptr)
#define TIMED_SCOPE(obj, blockname) TIMED_SCOPE_IF(obj, blockname, true)
#define TIMED_BLOCK(obj, blockName) \
for (struct { \
int i; \
el::base::type::PerformanceTrackerPtr timer; \
} obj = {0, \
el::base::type::PerformanceTrackerPtr( \
new el::base::PerformanceTracker(blockName, \
ELPP_MIN_UNIT))}; \
obj.i < 1; ++obj.i)
/// @brief Performance tracked function. Performance gets written when goes out
/// of scope using
/// 'performance' logger.
///
/// @detail Please note in order to check the performance at a certain time you
/// can use obj->checkpoint();
/// @see el::base::PerformanceTracker
/// @see el::base::PerformanceTracker::checkpoint
#define TIMED_FUNC_IF(obj, condition) TIMED_SCOPE_IF(obj, ELPP_FUNC, condition)
#define TIMED_FUNC(obj) TIMED_SCOPE(obj, ELPP_FUNC)
#undef PERFORMANCE_CHECKPOINT
#undef PERFORMANCE_CHECKPOINT_WITH_ID
#define PERFORMANCE_CHECKPOINT(obj) \
obj->checkpoint(std::string(), __FILE__, __LINE__, ELPP_FUNC)
#define PERFORMANCE_CHECKPOINT_WITH_ID(obj, id) \
obj->checkpoint(id, __FILE__, __LINE__, ELPP_FUNC)
#undef ELPP_COUNTER
#undef ELPP_COUNTER_POS
/// @brief Gets hit counter for file/line
#define ELPP_COUNTER (ELPP->hitCounters()->getCounter(__FILE__, __LINE__))
/// @brief Gets hit counter position for file/line, -1 if not registered yet
#define ELPP_COUNTER_POS \
(ELPP_COUNTER == nullptr ? -1 : ELPP_COUNTER->hitCounts())
// Undef levels to support LOG(LEVEL)
#undef INFO
#undef WARNING
#undef DEBUG
#undef ERROR
#undef FATAL
#undef TRACE
#undef VERBOSE
// Undef existing
#undef CINFO
#undef CWARNING
#undef CDEBUG
#undef CFATAL
#undef CERROR
#undef CTRACE
#undef CVERBOSE
#undef CINFO_IF
#undef CWARNING_IF
#undef CDEBUG_IF
#undef CERROR_IF
#undef CFATAL_IF
#undef CTRACE_IF
#undef CVERBOSE_IF
#undef CINFO_EVERY_N
#undef CWARNING_EVERY_N
#undef CDEBUG_EVERY_N
#undef CERROR_EVERY_N
#undef CFATAL_EVERY_N
#undef CTRACE_EVERY_N
#undef CVERBOSE_EVERY_N
#undef CINFO_AFTER_N
#undef CWARNING_AFTER_N
#undef CDEBUG_AFTER_N
#undef CERROR_AFTER_N
#undef CFATAL_AFTER_N
#undef CTRACE_AFTER_N
#undef CVERBOSE_AFTER_N
#undef CINFO_N_TIMES
#undef CWARNING_N_TIMES
#undef CDEBUG_N_TIMES
#undef CERROR_N_TIMES
#undef CFATAL_N_TIMES
#undef CTRACE_N_TIMES
#undef CVERBOSE_N_TIMES
// Normal logs
#if ELPP_INFO_LOG
#define CINFO(writer, dispatchAction, ...) \
ELPP_WRITE_LOG(writer, el::Level::Info, dispatchAction, __VA_ARGS__)
#else
#define CINFO(writer, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_INFO_LOG
#if ELPP_WARNING_LOG
#define CWARNING(writer, dispatchAction, ...) \
ELPP_WRITE_LOG(writer, el::Level::Warning, dispatchAction, __VA_ARGS__)
#else
#define CWARNING(writer, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_WARNING_LOG
#if ELPP_DEBUG_LOG
#define CDEBUG(writer, dispatchAction, ...) \
ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__)
#else
#define CDEBUG(writer, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_DEBUG_LOG
#if ELPP_ERROR_LOG
#define CERROR(writer, dispatchAction, ...) \
ELPP_WRITE_LOG(writer, el::Level::Error, dispatchAction, __VA_ARGS__)
#else
#define CERROR(writer, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_ERROR_LOG
#if ELPP_FATAL_LOG
#define CFATAL(writer, dispatchAction, ...) \
ELPP_WRITE_LOG(writer, el::Level::Fatal, dispatchAction, __VA_ARGS__)
#else
#define CFATAL(writer, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_FATAL_LOG
#if ELPP_TRACE_LOG
#define CTRACE(writer, dispatchAction, ...) \
ELPP_WRITE_LOG(writer, el::Level::Trace, dispatchAction, __VA_ARGS__)
#else
#define CTRACE(writer, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_TRACE_LOG
#if ELPP_VERBOSE_LOG
#define CVERBOSE(writer, vlevel, dispatchAction, ...) \
if (VLOG_IS_ON(vlevel)) \
writer(el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, \
vlevel) \
.construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
#else
#define CVERBOSE(writer, vlevel, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_VERBOSE_LOG
// Conditional logs
#if ELPP_INFO_LOG
#define CINFO_IF(writer, condition_, dispatchAction, ...) \
ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Info, dispatchAction, \
__VA_ARGS__)
#else
#define CINFO_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_INFO_LOG
#if ELPP_WARNING_LOG
#define CWARNING_IF(writer, condition_, dispatchAction, ...) \
ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Warning, dispatchAction, \
__VA_ARGS__)
#else
#define CWARNING_IF(writer, condition_, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_WARNING_LOG
#if ELPP_DEBUG_LOG
#define CDEBUG_IF(writer, condition_, dispatchAction, ...) \
ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Debug, dispatchAction, \
__VA_ARGS__)
#else
#define CDEBUG_IF(writer, condition_, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_DEBUG_LOG
#if ELPP_ERROR_LOG
#define CERROR_IF(writer, condition_, dispatchAction, ...) \
ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Error, dispatchAction, \
__VA_ARGS__)
#else
#define CERROR_IF(writer, condition_, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_ERROR_LOG
#if ELPP_FATAL_LOG
#define CFATAL_IF(writer, condition_, dispatchAction, ...) \
ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Fatal, dispatchAction, \
__VA_ARGS__)
#else
#define CFATAL_IF(writer, condition_, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_FATAL_LOG
#if ELPP_TRACE_LOG
#define CTRACE_IF(writer, condition_, dispatchAction, ...) \
ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Trace, dispatchAction, \
__VA_ARGS__)
#else
#define CTRACE_IF(writer, condition_, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_TRACE_LOG
#if ELPP_VERBOSE_LOG
#define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) \
if (VLOG_IS_ON(vlevel) && (condition_)) \
writer(el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, \
vlevel) \
.construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
#else
#define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_VERBOSE_LOG
// Occasional logs
#if ELPP_INFO_LOG
#define CINFO_EVERY_N(writer, occasion, dispatchAction, ...) \
ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Info, dispatchAction, \
__VA_ARGS__)
#else
#define CINFO_EVERY_N(writer, occasion, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_INFO_LOG
#if ELPP_WARNING_LOG
#define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...) \
ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Warning, dispatchAction, \
__VA_ARGS__)
#else
#define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_WARNING_LOG
#if ELPP_DEBUG_LOG
#define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...) \
ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Debug, dispatchAction, \
__VA_ARGS__)
#else
#define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_DEBUG_LOG
#if ELPP_ERROR_LOG
#define CERROR_EVERY_N(writer, occasion, dispatchAction, ...) \
ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Error, dispatchAction, \
__VA_ARGS__)
#else
#define CERROR_EVERY_N(writer, occasion, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_ERROR_LOG
#if ELPP_FATAL_LOG
#define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...) \
ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Fatal, dispatchAction, \
__VA_ARGS__)
#else
#define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_FATAL_LOG
#if ELPP_TRACE_LOG
#define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...) \
ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Trace, dispatchAction, \
__VA_ARGS__)
#else
#define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_TRACE_LOG
#if ELPP_VERBOSE_LOG
#define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...) \
CVERBOSE_IF(writer, \
ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion), \
vlevel, dispatchAction, __VA_ARGS__)
#else
#define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_VERBOSE_LOG
// After N logs
#if ELPP_INFO_LOG
#define CINFO_AFTER_N(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Info, dispatchAction, \
__VA_ARGS__)
#else
#define CINFO_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_INFO_LOG
#if ELPP_WARNING_LOG
#define CWARNING_AFTER_N(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Warning, dispatchAction, \
__VA_ARGS__)
#else
#define CWARNING_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_WARNING_LOG
#if ELPP_DEBUG_LOG
#define CDEBUG_AFTER_N(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Debug, dispatchAction, \
__VA_ARGS__)
#else
#define CDEBUG_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_DEBUG_LOG
#if ELPP_ERROR_LOG
#define CERROR_AFTER_N(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Error, dispatchAction, \
__VA_ARGS__)
#else
#define CERROR_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_ERROR_LOG
#if ELPP_FATAL_LOG
#define CFATAL_AFTER_N(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Fatal, dispatchAction, \
__VA_ARGS__)
#else
#define CFATAL_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_FATAL_LOG
#if ELPP_TRACE_LOG
#define CTRACE_AFTER_N(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Trace, dispatchAction, \
__VA_ARGS__)
#else
#define CTRACE_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_TRACE_LOG
#if ELPP_VERBOSE_LOG
#define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...) \
CVERBOSE_IF(writer, ELPP->validateAfterNCounter(__FILE__, __LINE__, n), \
vlevel, dispatchAction, __VA_ARGS__)
#else
#define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_VERBOSE_LOG
// N Times logs
#if ELPP_INFO_LOG
#define CINFO_N_TIMES(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Info, dispatchAction, \
__VA_ARGS__)
#else
#define CINFO_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_INFO_LOG
#if ELPP_WARNING_LOG
#define CWARNING_N_TIMES(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Warning, dispatchAction, \
__VA_ARGS__)
#else
#define CWARNING_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_WARNING_LOG
#if ELPP_DEBUG_LOG
#define CDEBUG_N_TIMES(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Debug, dispatchAction, \
__VA_ARGS__)
#else
#define CDEBUG_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_DEBUG_LOG
#if ELPP_ERROR_LOG
#define CERROR_N_TIMES(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Error, dispatchAction, \
__VA_ARGS__)
#else
#define CERROR_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_ERROR_LOG
#if ELPP_FATAL_LOG
#define CFATAL_N_TIMES(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Fatal, dispatchAction, \
__VA_ARGS__)
#else
#define CFATAL_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_FATAL_LOG
#if ELPP_TRACE_LOG
#define CTRACE_N_TIMES(writer, n, dispatchAction, ...) \
ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Trace, dispatchAction, \
__VA_ARGS__)
#else
#define CTRACE_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif // ELPP_TRACE_LOG
#if ELPP_VERBOSE_LOG
#define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...) \
CVERBOSE_IF(writer, ELPP->validateNTimesCounter(__FILE__, __LINE__, n), \
vlevel, dispatchAction, __VA_ARGS__)
#else
#define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...) \
el::base::NullWriter()
#endif // ELPP_VERBOSE_LOG
//
// Custom Loggers - Requires (level, dispatchAction, loggerId/s)
//
// undef existing
#undef CLOG
#undef CLOG_VERBOSE
#undef CVLOG
#undef CLOG_IF
#undef CLOG_VERBOSE_IF
#undef CVLOG_IF
#undef CLOG_EVERY_N
#undef CVLOG_EVERY_N
#undef CLOG_AFTER_N
#undef CVLOG_AFTER_N
#undef CLOG_N_TIMES
#undef CVLOG_N_TIMES
// Normal logs
#define CLOG(LEVEL, ...) \
C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__)
#define CVLOG(vlevel, ...) \
CVERBOSE(el::base::Writer, vlevel, el::base::DispatchAction::NormalLog, \
__VA_ARGS__)
// Conditional logs
#define CLOG_IF(condition, LEVEL, ...) \
C##LEVEL##_IF(el::base::Writer, condition, \
el::base::DispatchAction::NormalLog, __VA_ARGS__)
#define CVLOG_IF(condition, vlevel, ...) \
CVERBOSE_IF(el::base::Writer, condition, vlevel, \
el::base::DispatchAction::NormalLog, __VA_ARGS__)
// Hit counts based logs
#define CLOG_EVERY_N(n, LEVEL, ...) \
C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, \
__VA_ARGS__)
#define CVLOG_EVERY_N(n, vlevel, ...) \
CVERBOSE_EVERY_N(el::base::Writer, n, vlevel, \
el::base::DispatchAction::NormalLog, __VA_ARGS__)
#define CLOG_AFTER_N(n, LEVEL, ...) \
C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, \
__VA_ARGS__)
#define CVLOG_AFTER_N(n, vlevel, ...) \
CVERBOSE_AFTER_N(el::base::Writer, n, vlevel, \
el::base::DispatchAction::NormalLog, __VA_ARGS__)
#define CLOG_N_TIMES(n, LEVEL, ...) \
C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::NormalLog, \
__VA_ARGS__)
#define CVLOG_N_TIMES(n, vlevel, ...) \
CVERBOSE_N_TIMES(el::base::Writer, n, vlevel, \
el::base::DispatchAction::NormalLog, __VA_ARGS__)
//
// Default Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros
//
// undef existing
#undef LOG
#undef VLOG
#undef LOG_IF
#undef VLOG_IF
#undef LOG_EVERY_N
#undef VLOG_EVERY_N
#undef LOG_AFTER_N
#undef VLOG_AFTER_N
#undef LOG_N_TIMES
#undef VLOG_N_TIMES
#undef ELPP_CURR_FILE_LOGGER_ID
#if defined(ELPP_DEFAULT_LOGGER)
#define ELPP_CURR_FILE_LOGGER_ID ELPP_DEFAULT_LOGGER
#else
#define ELPP_CURR_FILE_LOGGER_ID el::base::consts::kDefaultLoggerId
#endif
#undef ELPP_TRACE
#define ELPP_TRACE CLOG(TRACE, ELPP_CURR_FILE_LOGGER_ID)
// Normal logs
#define LOG(LEVEL) CLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define VLOG(vlevel) CVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID)
// Conditional logs
#define LOG_IF(condition, LEVEL) \
CLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define VLOG_IF(condition, vlevel) \
CVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID)
// Hit counts based logs
#define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define VLOG_EVERY_N(n, vlevel) \
CVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
#define LOG_AFTER_N(n, LEVEL) CLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define VLOG_AFTER_N(n, vlevel) \
CVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
#define LOG_N_TIMES(n, LEVEL) CLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define VLOG_N_TIMES(n, vlevel) \
CVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
// Generic PLOG()
#undef CPLOG
#undef CPLOG_IF
#undef PLOG
#undef PLOG_IF
#undef DCPLOG
#undef DCPLOG_IF
#undef DPLOG
#undef DPLOG_IF
#define CPLOG(LEVEL, ...) \
C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, \
__VA_ARGS__)
#define CPLOG_IF(condition, LEVEL, ...) \
C##LEVEL##_IF(el::base::PErrorWriter, condition, \
el::base::DispatchAction::NormalLog, __VA_ARGS__)
#define DCPLOG(LEVEL, ...) \
if (ELPP_DEBUG_LOG) \
C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, \
__VA_ARGS__)
#define DCPLOG_IF(condition, LEVEL, ...) \
C##LEVEL##_IF(el::base::PErrorWriter, (ELPP_DEBUG_LOG) && (condition), \
el::base::DispatchAction::NormalLog, __VA_ARGS__)
#define PLOG(LEVEL) CPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define PLOG_IF(condition, LEVEL) \
CPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define DPLOG(LEVEL) DCPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define DPLOG_IF(condition, LEVEL) \
DCPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
// Generic SYSLOG()
#undef CSYSLOG
#undef CSYSLOG_IF
#undef CSYSLOG_EVERY_N
#undef CSYSLOG_AFTER_N
#undef CSYSLOG_N_TIMES
#undef SYSLOG
#undef SYSLOG_IF
#undef SYSLOG_EVERY_N
#undef SYSLOG_AFTER_N
#undef SYSLOG_N_TIMES
#undef DCSYSLOG
#undef DCSYSLOG_IF
#undef DCSYSLOG_EVERY_N
#undef DCSYSLOG_AFTER_N
#undef DCSYSLOG_N_TIMES
#undef DSYSLOG
#undef DSYSLOG_IF
#undef DSYSLOG_EVERY_N
#undef DSYSLOG_AFTER_N
#undef DSYSLOG_N_TIMES
#if defined(ELPP_SYSLOG)
#define CSYSLOG(LEVEL, ...) \
C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__)
#define CSYSLOG_IF(condition, LEVEL, ...) \
C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::SysLog, \
__VA_ARGS__)
#define CSYSLOG_EVERY_N(n, LEVEL, ...) \
C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, \
__VA_ARGS__)
#define CSYSLOG_AFTER_N(n, LEVEL, ...) \
C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, \
__VA_ARGS__)
#define CSYSLOG_N_TIMES(n, LEVEL, ...) \
C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::SysLog, \
__VA_ARGS__)
#define SYSLOG(LEVEL) CSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId)
#define SYSLOG_IF(condition, LEVEL) \
CSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId)
#define SYSLOG_EVERY_N(n, LEVEL) \
CSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
#define SYSLOG_AFTER_N(n, LEVEL) \
CSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
#define SYSLOG_N_TIMES(n, LEVEL) \
CSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId)
#define DCSYSLOG(LEVEL, ...) \
if (ELPP_DEBUG_LOG) \
C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__)
#define DCSYSLOG_IF(condition, LEVEL, ...) \
C##LEVEL##_IF(el::base::Writer, (ELPP_DEBUG_LOG) && (condition), \
el::base::DispatchAction::SysLog, __VA_ARGS__)
#define DCSYSLOG_EVERY_N(n, LEVEL, ...) \
if (ELPP_DEBUG_LOG) \
C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, \
__VA_ARGS__)
#define DCSYSLOG_AFTER_N(n, LEVEL, ...) \
if (ELPP_DEBUG_LOG) \
C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, \
__VA_ARGS__)
#define DCSYSLOG_N_TIMES(n, LEVEL, ...) \
if (ELPP_DEBUG_LOG) \
C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, \
__VA_ARGS__)
#define DSYSLOG(LEVEL) DCSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId)
#define DSYSLOG_IF(condition, LEVEL) \
DCSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId)
#define DSYSLOG_EVERY_N(n, LEVEL) \
DCSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
#define DSYSLOG_AFTER_N(n, LEVEL) \
DCSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
#define DSYSLOG_N_TIMES(n, LEVEL) \
DCSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId)
#else
#define CSYSLOG(LEVEL, ...) el::base::NullWriter()
#define CSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter()
#define CSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter()
#define CSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter()
#define CSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter()
#define SYSLOG(LEVEL) el::base::NullWriter()
#define SYSLOG_IF(condition, LEVEL) el::base::NullWriter()
#define SYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter()
#define SYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter()
#define SYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter()
#define DCSYSLOG(LEVEL, ...) el::base::NullWriter()
#define DCSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter()
#define DCSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter()
#define DCSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter()
#define DCSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter()
#define DSYSLOG(LEVEL) el::base::NullWriter()
#define DSYSLOG_IF(condition, LEVEL) el::base::NullWriter()
#define DSYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter()
#define DSYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter()
#define DSYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter()
#endif // defined(ELPP_SYSLOG)
//
// Custom Debug Only Loggers - Requires (level, loggerId/s)
//
// undef existing
#undef DCLOG
#undef DCVLOG
#undef DCLOG_IF
#undef DCVLOG_IF
#undef DCLOG_EVERY_N
#undef DCVLOG_EVERY_N
#undef DCLOG_AFTER_N
#undef DCVLOG_AFTER_N
#undef DCLOG_N_TIMES
#undef DCVLOG_N_TIMES
// Normal logs
#define DCLOG(LEVEL, ...) \
if (ELPP_DEBUG_LOG) \
CLOG(LEVEL, __VA_ARGS__)
#define DCLOG_VERBOSE(vlevel, ...) \
if (ELPP_DEBUG_LOG) \
CLOG_VERBOSE(vlevel, __VA_ARGS__)
#define DCVLOG(vlevel, ...) \
if (ELPP_DEBUG_LOG) \
CVLOG(vlevel, __VA_ARGS__)
// Conditional logs
#define DCLOG_IF(condition, LEVEL, ...) \
if (ELPP_DEBUG_LOG) \
CLOG_IF(condition, LEVEL, __VA_ARGS__)
#define DCVLOG_IF(condition, vlevel, ...) \
if (ELPP_DEBUG_LOG) \
CVLOG_IF(condition, vlevel, __VA_ARGS__)
// Hit counts based logs
#define DCLOG_EVERY_N(n, LEVEL, ...) \
if (ELPP_DEBUG_LOG) \
CLOG_EVERY_N(n, LEVEL, __VA_ARGS__)
#define DCVLOG_EVERY_N(n, vlevel, ...) \
if (ELPP_DEBUG_LOG) \
CVLOG_EVERY_N(n, vlevel, __VA_ARGS__)
#define DCLOG_AFTER_N(n, LEVEL, ...) \
if (ELPP_DEBUG_LOG) \
CLOG_AFTER_N(n, LEVEL, __VA_ARGS__)
#define DCVLOG_AFTER_N(n, vlevel, ...) \
if (ELPP_DEBUG_LOG) \
CVLOG_AFTER_N(n, vlevel, __VA_ARGS__)
#define DCLOG_N_TIMES(n, LEVEL, ...) \
if (ELPP_DEBUG_LOG) \
CLOG_N_TIMES(n, LEVEL, __VA_ARGS__)
#define DCVLOG_N_TIMES(n, vlevel, ...) \
if (ELPP_DEBUG_LOG) \
CVLOG_N_TIMES(n, vlevel, __VA_ARGS__)
//
// Default Debug Only Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG()
// macros
//
#if !defined(ELPP_NO_DEBUG_MACROS)
// undef existing
#undef DLOG
#undef DVLOG
#undef DLOG_IF
#undef DVLOG_IF
#undef DLOG_EVERY_N
#undef DVLOG_EVERY_N
#undef DLOG_AFTER_N
#undef DVLOG_AFTER_N
#undef DLOG_N_TIMES
#undef DVLOG_N_TIMES
// Normal logs
#define DLOG(LEVEL) DCLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define DVLOG(vlevel) DCVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID)
// Conditional logs
#define DLOG_IF(condition, LEVEL) \
DCLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define DVLOG_IF(condition, vlevel) \
DCVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID)
// Hit counts based logs
#define DLOG_EVERY_N(n, LEVEL) DCLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define DVLOG_EVERY_N(n, vlevel) \
DCVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
#define DLOG_AFTER_N(n, LEVEL) DCLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define DVLOG_AFTER_N(n, vlevel) \
DCVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
#define DLOG_N_TIMES(n, LEVEL) DCLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define DVLOG_N_TIMES(n, vlevel) \
DCVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
#endif // defined(ELPP_NO_DEBUG_MACROS)
#if !defined(ELPP_NO_CHECK_MACROS)
// Check macros
#undef CCHECK
#undef CPCHECK
#undef CCHECK_EQ
#undef CCHECK_NE
#undef CCHECK_LT
#undef CCHECK_GT
#undef CCHECK_LE
#undef CCHECK_GE
#undef CCHECK_BOUNDS
#undef CCHECK_NOTNULL
#undef CCHECK_STRCASEEQ
#undef CCHECK_STRCASENE
#undef CHECK
#undef PCHECK
#undef CHECK_EQ
#undef CHECK_NE
#undef CHECK_LT
#undef CHECK_GT
#undef CHECK_LE
#undef CHECK_GE
#undef CHECK_BOUNDS
#undef CHECK_NOTNULL
#undef CHECK_STRCASEEQ
#undef CHECK_STRCASENE
#define CCHECK(condition, ...) \
CLOG_IF(!(condition), FATAL, __VA_ARGS__) \
<< "Check failed: [" << #condition << "] "
#define CPCHECK(condition, ...) \
CPLOG_IF(!(condition), FATAL, __VA_ARGS__) \
<< "Check failed: [" << #condition << "] "
#define CHECK(condition) CCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
#define PCHECK(condition) CPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
#define CCHECK_EQ(a, b, ...) CCHECK(a == b, __VA_ARGS__)
#define CCHECK_NE(a, b, ...) CCHECK(a != b, __VA_ARGS__)
#define CCHECK_LT(a, b, ...) CCHECK(a < b, __VA_ARGS__)
#define CCHECK_GT(a, b, ...) CCHECK(a > b, __VA_ARGS__)
#define CCHECK_LE(a, b, ...) CCHECK(a <= b, __VA_ARGS__)
#define CCHECK_GE(a, b, ...) CCHECK(a >= b, __VA_ARGS__)
#define CCHECK_BOUNDS(val, min, max, ...) \
CCHECK(val >= min && val <= max, __VA_ARGS__)
#define CHECK_EQ(a, b) CCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define CHECK_NE(a, b) CCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define CHECK_LT(a, b) CCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define CHECK_GT(a, b) CCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define CHECK_LE(a, b) CCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define CHECK_GE(a, b) CCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define CHECK_BOUNDS(val, min, max) \
CCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID)
#define CCHECK_NOTNULL(ptr, ...) CCHECK((ptr) != nullptr, __VA_ARGS__)
#define CCHECK_STREQ(str1, str2, ...) \
CLOG_IF(!el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \
<< "Check failed: [" << #str1 << " == " << #str2 << "] "
#define CCHECK_STRNE(str1, str2, ...) \
CLOG_IF(el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \
<< "Check failed: [" << #str1 << " != " << #str2 << "] "
#define CCHECK_STRCASEEQ(str1, str2, ...) \
CLOG_IF(!el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, \
__VA_ARGS__) \
<< "Check failed: [" << #str1 << " == " << #str2 << "] "
#define CCHECK_STRCASENE(str1, str2, ...) \
CLOG_IF(el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \
<< "Check failed: [" << #str1 << " != " << #str2 << "] "
#define CHECK_NOTNULL(ptr) CCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID)
#define CHECK_STREQ(str1, str2) \
CCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
#define CHECK_STRNE(str1, str2) \
CCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
#define CHECK_STRCASEEQ(str1, str2) \
CCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
#define CHECK_STRCASENE(str1, str2) \
CCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
#undef DCCHECK
#undef DCCHECK_EQ
#undef DCCHECK_NE
#undef DCCHECK_LT
#undef DCCHECK_GT
#undef DCCHECK_LE
#undef DCCHECK_GE
#undef DCCHECK_BOUNDS
#undef DCCHECK_NOTNULL
#undef DCCHECK_STRCASEEQ
#undef DCCHECK_STRCASENE
#undef DCPCHECK
#undef DCHECK
#undef DCHECK_EQ
#undef DCHECK_NE
#undef DCHECK_LT
#undef DCHECK_GT
#undef DCHECK_LE
#undef DCHECK_GE
#undef DCHECK_BOUNDS_
#undef DCHECK_NOTNULL
#undef DCHECK_STRCASEEQ
#undef DCHECK_STRCASENE
#undef DPCHECK
#define DCCHECK(condition, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK(condition, __VA_ARGS__)
#define DCCHECK_EQ(a, b, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_EQ(a, b, __VA_ARGS__)
#define DCCHECK_NE(a, b, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_NE(a, b, __VA_ARGS__)
#define DCCHECK_LT(a, b, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_LT(a, b, __VA_ARGS__)
#define DCCHECK_GT(a, b, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_GT(a, b, __VA_ARGS__)
#define DCCHECK_LE(a, b, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_LE(a, b, __VA_ARGS__)
#define DCCHECK_GE(a, b, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_GE(a, b, __VA_ARGS__)
#define DCCHECK_BOUNDS(val, min, max, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_BOUNDS(val, min, max, __VA_ARGS__)
#define DCCHECK_NOTNULL(ptr, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_NOTNULL((ptr), __VA_ARGS__)
#define DCCHECK_STREQ(str1, str2, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_STREQ(str1, str2, __VA_ARGS__)
#define DCCHECK_STRNE(str1, str2, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_STRNE(str1, str2, __VA_ARGS__)
#define DCCHECK_STRCASEEQ(str1, str2, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_STRCASEEQ(str1, str2, __VA_ARGS__)
#define DCCHECK_STRCASENE(str1, str2, ...) \
if (ELPP_DEBUG_LOG) \
CCHECK_STRCASENE(str1, str2, __VA_ARGS__)
#define DCPCHECK(condition, ...) \
if (ELPP_DEBUG_LOG) \
CPCHECK(condition, __VA_ARGS__)
#define DCHECK(condition) DCCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_EQ(a, b) DCCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_NE(a, b) DCCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_LT(a, b) DCCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_GT(a, b) DCCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_LE(a, b) DCCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_GE(a, b) DCCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_BOUNDS(val, min, max) \
DCCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_NOTNULL(ptr) DCCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_STREQ(str1, str2) \
DCCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_STRNE(str1, str2) \
DCCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_STRCASEEQ(str1, str2) \
DCCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
#define DCHECK_STRCASENE(str1, str2) \
DCCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
#define DPCHECK(condition) DCPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
#endif // defined(ELPP_NO_CHECK_MACROS)
#if defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING)
#define ELPP_USE_DEF_CRASH_HANDLER false
#else
#define ELPP_USE_DEF_CRASH_HANDLER true
#endif // defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING)
#define ELPP_CRASH_HANDLER_INIT
#define ELPP_INIT_EASYLOGGINGPP(val) \
namespace el { \
namespace base { \
el::base::type::StoragePointer elStorage(val); \
} \
el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER); \
}
#if ELPP_ASYNC_LOGGING
#define INITIALIZE_EASYLOGGINGPP \
ELPP_INIT_EASYLOGGINGPP(new el::base::Storage( \
el::LogBuilderPtr(new el::base::DefaultLogBuilder()), \
new el::base::AsyncDispatchWorker()))
#else
#define INITIALIZE_EASYLOGGINGPP \
ELPP_INIT_EASYLOGGINGPP(new el::base::Storage( \
el::LogBuilderPtr(new el::base::DefaultLogBuilder())))
#endif // ELPP_ASYNC_LOGGING
#define INITIALIZE_NULL_EASYLOGGINGPP \
namespace el { \
namespace base { \
el::base::type::StoragePointer elStorage; \
} \
el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER); \
}
#define SHARE_EASYLOGGINGPP(initializedStorage) \
namespace el { \
namespace base { \
el::base::type::StoragePointer elStorage(initializedStorage); \
} \
el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER); \
}
#if defined(ELPP_UNICODE)
#define START_EASYLOGGINGPP(argc, argv) \
el::Helpers::setArgs(argc, argv); \
std::locale::global(std::locale(""))
#else
#define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv)
#endif // defined(ELPP_UNICODE)
#endif // EASYLOGGINGPP_H