// // Bismillah ar-Rahmaan ar-Raheem // // Easylogging++ v9.94.1 // Single-header only, cross-platform logging library for C++ applications // // Copyright (c) 2017 muflihun.com // // This library is released under the MIT Licence. // http://labs.muflihun.com/easyloggingpp/licence.php // // https://github.com/muflihun/easyloggingpp // https://muflihun.github.io/easyloggingpp // 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() # include // Make __GLIBCXX__ defined when using libstdc++ # if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426 # define ELPP_CLANG_SUPPORTS_THREAD # endif // !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426 # endif // __has_include() #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__)) # 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 // Unix #if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_SOLARIS) && (!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 << " " << 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 << " " << 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) # 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 #define ELPP_LOGGING_ENABLED (!defined(ELPP_DISABLE_LOGS)) #if (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED) && ((defined(_DEBUG)) || (!defined(NDEBUG)))) # define ELPP_DEBUG_LOG 1 #else # define ELPP_DEBUG_LOG 0 #endif // (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED) && ((defined(_DEBUG)) || (!defined(NDEBUG)))) #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 #endif // defined(ELPP_SYSLOG) #include #include #include #include #include #include #include #include #if defined(ELPP_UNICODE) # include # if ELPP_OS_WINDOWS # include # endif // ELPP_OS_WINDOWS #endif // defined(ELPP_UNICODE) #if ELPP_STACKTRACE # include # include #endif // ELPP_STACKTRACE #if ELPP_OS_ANDROID # include #endif // ELPP_OS_ANDROID #if ELPP_OS_UNIX # include # include #elif ELPP_OS_WINDOWS # include # include # if defined(WIN32_LEAN_AND_MEAN) # if defined(ELPP_WINSOCK2) # include # else # include # endif // defined(ELPP_WINSOCK2) # endif // defined(WIN32_LEAN_AND_MEAN) #endif // ELPP_OS_UNIX #include #include #include #include #include #include #include #include #include #include #include #if ELPP_THREADING_ENABLED # if ELPP_USE_STD_THREADING # include # include # else # if ELPP_OS_UNIX # include # endif // ELPP_OS_UNIX # endif // ELPP_USE_STD_THREADING #endif // ELPP_THREADING_ENABLED #if ELPP_ASYNC_LOGGING # if defined(ELPP_NO_SLEEP_FOR) # include # endif // defined(ELPP_NO_SLEEP_FOR) # include # include # include #endif // ELPP_ASYNC_LOGGING #if defined(ELPP_STL_LOGGING) // For logging STL based templates # include # include # include # include # include # include # if defined(ELPP_LOG_STD_ARRAY) # include # endif // defined(ELPP_LOG_STD_ARRAY) # if defined(ELPP_LOG_UNORDERED_MAP) # include # endif // defined(ELPP_LOG_UNORDERED_MAP) # if defined(ELPP_LOG_UNORDERED_SET) # include # endif // defined(ELPP_UNORDERED_SET) #endif // defined(ELPP_STL_LOGGING) #if defined(ELPP_QT_LOGGING) // For logging Qt based classes & templates # include # include # include # include # include # include # include # include # include # include # include # include #endif // defined(ELPP_QT_LOGGING) #if defined(ELPP_BOOST_LOGGING) // For logging boost based classes & templates # include # include # include # include # include # include # include # include #endif // defined(ELPP_BOOST_LOGGING) #if defined(ELPP_WXWIDGETS_LOGGING) // For logging wxWidgets based classes & templates # include #endif // defined(ELPP_WXWIDGETS_LOGGING) // Forward declarations namespace el { class Logger; class LogMessage; class PerformanceTrackingData; class Loggers; class Helpers; template 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 StoragePointer; typedef std::shared_ptr LogDispatchCallbackPtr; typedef std::shared_ptr PerformanceTrackingCallbackPtr; typedef std::shared_ptr LoggerRegistrationCallbackPtr; typedef std::unique_ptr 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 situtaions 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 }; /// @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(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(Level::Info); /// @brief Casts level to int, useful for iterating through enum. static base::type::EnumType castToInt(Level level) { return static_cast(level); } /// @brief Casts int(ushort) to level, useful for iterating through enum. static Level castFromInt(base::type::EnumType l) { return static_cast(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& 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 correponding 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(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(ConfigurationType::MaxLogFileSize); /// @brief Casts configuration type to int, useful for iterating through enum. static base::type::EnumType castToInt(ConfigurationType configurationType) { return static_cast(configurationType); } /// @brief Casts int(ushort) to configurationt type, useful for iterating through enum. static ConfigurationType castFromInt(base::type::EnumType c) { return static_cast(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& 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 sensative) - 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 }; namespace base { /// @brief Namespace containing constants used internally. namespace consts { #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-variable" #endif // Level log values - These are values that are replaced in place of %level format specifier static const base::type::char_t* kInfoLevelLogValue = ELPP_LITERAL("INFO "); static const base::type::char_t* kDebugLevelLogValue = ELPP_LITERAL("DEBUG"); static const base::type::char_t* kWarningLevelLogValue = ELPP_LITERAL("WARN "); static const base::type::char_t* kErrorLevelLogValue = ELPP_LITERAL("ERROR"); static const base::type::char_t* kFatalLevelLogValue = ELPP_LITERAL("FATAL"); static const base::type::char_t* kVerboseLevelLogValue = ELPP_LITERAL("VER"); static const base::type::char_t* kTraceLevelLogValue = ELPP_LITERAL("TRACE"); static const base::type::char_t* kInfoLevelShortLogValue = ELPP_LITERAL("I"); static const base::type::char_t* kDebugLevelShortLogValue = ELPP_LITERAL("D"); static const base::type::char_t* kWarningLevelShortLogValue = ELPP_LITERAL("W"); static const base::type::char_t* kErrorLevelShortLogValue = ELPP_LITERAL("E"); static const base::type::char_t* kFatalLevelShortLogValue = ELPP_LITERAL("F"); static const base::type::char_t* kVerboseLevelShortLogValue = ELPP_LITERAL("V"); static const base::type::char_t* kTraceLevelShortLogValue = ELPP_LITERAL("T"); // Format specifiers - These are used to define log format static const base::type::char_t* kAppNameFormatSpecifier = ELPP_LITERAL("%app"); static const base::type::char_t* kLoggerIdFormatSpecifier = ELPP_LITERAL("%logger"); static const base::type::char_t* kThreadIdFormatSpecifier = ELPP_LITERAL("%thread"); static const base::type::char_t* kSeverityLevelFormatSpecifier = ELPP_LITERAL("%level"); static const base::type::char_t* kSeverityLevelShortFormatSpecifier = ELPP_LITERAL("%levshort"); static const base::type::char_t* kDateTimeFormatSpecifier = ELPP_LITERAL("%datetime"); static const base::type::char_t* kLogFileFormatSpecifier = ELPP_LITERAL("%file"); static const base::type::char_t* kLogFileBaseFormatSpecifier = ELPP_LITERAL("%fbase"); static const base::type::char_t* kLogLineFormatSpecifier = ELPP_LITERAL("%line"); static const base::type::char_t* kLogLocationFormatSpecifier = ELPP_LITERAL("%loc"); static const base::type::char_t* kLogFunctionFormatSpecifier = ELPP_LITERAL("%func"); static const base::type::char_t* kCurrentUserFormatSpecifier = ELPP_LITERAL("%user"); static const base::type::char_t* kCurrentHostFormatSpecifier = ELPP_LITERAL("%host"); static const base::type::char_t* kMessageFormatSpecifier = ELPP_LITERAL("%msg"); static const base::type::char_t* kVerboseLevelFormatSpecifier = ELPP_LITERAL("%vlevel"); static const char* kDateTimeFormatSpecifierForFilename = "%datetime"; // Date/time static const char* kDays[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; static const char* kDaysAbbrev[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static const char* kMonths[12] = { "January", "February", "March", "Apri", "May", "June", "July", "August", "September", "October", "November", "December" }; static const char* kMonthsAbbrev[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static const char* kDefaultDateTimeFormat = "%Y-%M-%d %H:%m:%s,%g"; static const char* kDefaultDateTimeFormatInFilename = "%Y-%M-%d_%H-%m"; static const int kYearBase = 1900; static const char* kAm = "AM"; static const char* kPm = "PM"; // Miscellaneous constants #ifdef ELPP_DEFAULT_LOGGER static const char* kDefaultLoggerId = ELPP_DEFAULT_LOGGER; #else static const char* kDefaultLoggerId = "default"; #endif #ifdef ELPP_DEFAULT_PERFORMANCE_LOGGER static const char* kPerformanceLoggerId = ELPP_DEFAULT_PERFORMANCE_LOGGER; #else static const char* kPerformanceLoggerId = "performance"; #endif #if defined(ELPP_SYSLOG) static const char* kSysLogLoggerId = "syslog"; #endif // defined(ELPP_SYSLOG) static const char* kNullPointer = "nullptr"; static const char kFormatSpecifierChar = '%'; #if ELPP_VARIADIC_TEMPLATES_SUPPORTED static const char kFormatSpecifierCharValue = 'v'; #endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED static const unsigned int kMaxLogPerContainer = 100; static const unsigned int kMaxLogPerCounter = 100000; static const unsigned int kDefaultSubsecondPrecision = 3; static const base::type::VerboseLevel kMaxVerboseLevel = 9; static const char* kUnknownUser = "user"; static const char* kUnknownHost = "unknown-host"; #if defined(ELPP_DEFAULT_LOG_FILE) static const char* kDefaultLogFile = ELPP_DEFAULT_LOG_FILE; #else # if ELPP_OS_UNIX # if ELPP_OS_ANDROID static const char* kDefaultLogFile = "logs/myeasylog.log"; # else static const char* kDefaultLogFile = "logs/myeasylog.log"; # endif // ELPP_OS_ANDROID # elif ELPP_OS_WINDOWS static const char* kDefaultLogFile = "logs\\myeasylog.log"; # endif // ELPP_OS_UNIX #endif // defined(ELPP_DEFAULT_LOG_FILE) #if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) static const char* kDefaultLogFileParam = "--default-log-file"; #endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) #if defined(ELPP_LOGGING_FLAGS_FROM_ARG) static const char* kLoggingFlagsParam = "--logging-flags"; #endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) #if ELPP_OS_WINDOWS static const char* kFilePathSeperator = "\\"; #else static const char* kFilePathSeperator = "/"; #endif // ELPP_OS_WINDOWS static const char* kValidLoggerIdSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._"; static const char* kConfigurationComment = "##"; static const char* kConfigurationLevel = "*"; static const char* kConfigurationLoggerId = "--"; 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", "Arithemetic 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]); #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif } // namespace consts } // namespace base typedef std::function 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 static typename std::enable_if::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
flag = bitwise::Or(MyEnum::val1, flag);
namespace bitwise { template static inline base::type::EnumType And(Enum e, base::type::EnumType flag) { return static_cast(flag) & static_cast(e); } template static inline base::type::EnumType Not(Enum e, base::type::EnumType flag) { return static_cast(flag) & ~(static_cast(e)); } template static inline base::type::EnumType Or(Enum e, base::type::EnumType flag) { return static_cast(flag) | static_cast(e); } } // namespace bitwise template static inline void addFlag(Enum e, base::type::EnumType* flag) { *flag = base::utils::bitwise::Or(e, *flag); } template static inline void removeFlag(Enum e, base::type::EnumType* flag) { *flag = base::utils::bitwise::Not(e, *flag); } template static inline bool hasFlag(Enum e, base::type::EnumType flag) { return base::utils::bitwise::And(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 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 ScopedLock; # else typedef std::recursive_mutex Mutex; typedef std::lock_guard 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 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 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* seperator = base::consts::kFilePathSeperator); /// @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* seperator = base::consts::kFilePathSeperator); }; /// @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 Converst 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 getenv(const char*) 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 seperated 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 seperate 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); private: static struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo); 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(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(argv)); } /// @brief Sets arguments and parses them void setArgs(int argc, char** argv); /// @brief Returns true if arguments contain paramKey with a value (seperated 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::map m_paramsWithValue; std::vector 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&) 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 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& 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& 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&) = 0; void reinitDeepCopy(const AbstractRegistry& 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. Any implementation of this class should be /// explicitly (by using lock functions) template class Registry : public AbstractRegistry> { public: typedef typename Registry::iterator iterator; typedef typename Registry::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>() { if (this == &sr) { return; } this->reinitDeepCopy(sr); } /// @brief Assignment operator that unregisters all the existing registeries 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) { base::utils::safeDelete(existing); this->list().erase(uniqKey); } } /// @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>& 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. Any implementation of this class /// should be made thread-safe explicitly template class RegistryWithPred : public AbstractRegistry> { public: typedef typename RegistryWithPred::iterator iterator; typedef typename RegistryWithPred::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>() { if (this == &sr) { return; } this->reinitDeepCopy(sr); } /// @brief Assignment operator that unregisters all the existing registeries 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 speicifed arguments. Arguments are passed to predicate /// in order to validate pointer. template 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>& sr) { for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) { registerNew(new T_Ptr(**it)); } } }; class Utils { public: template static bool installCallback(const std::string& id, std::map* mapT) { if (mapT->find(id) == mapT->end()) { mapT->insert(std::make_pair(id, TPtr(new T()))); return true; } return false; } template static void uninstallCallback(const std::string& id, std::map* mapT) { if (mapT->find(id) != mapT->end()) { mapT->erase(id); } } template static T* callback(const std::string& id, std::map* mapT) { typename std::map::iterator iter = mapT->find(id); if (iter != mapT->end()) { return static_cast(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 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 { 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::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 FileStreamPtr; typedef std::map LogStreamsReferenceMap; /// @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, base::LogStreamsReferenceMap* 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::map m_enabledMap; std::map m_toFileMap; std::map m_filenameMap; std::map m_toStandardOutputMap; std::map m_logFormatMap; std::map m_subsecondPrecisionMap; std::map m_performanceTrackingMap; std::map m_fileStreamMap; std::map m_maxLogFileSizeMap; std::map m_logFlushThresholdMap; base::LogStreamsReferenceMap* m_logStreamsReference; 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 inline Conf_T getConfigByVal(Level level, const std::map* confMap, const char* confName) { base::threading::ScopedLock scopedLock(lock()); return unsafeGetConfigByVal(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope } template inline Conf_T& getConfigByRef(Level level, std::map* confMap, const char* confName) { base::threading::ScopedLock scopedLock(lock()); return unsafeGetConfigByRef(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope } template Conf_T unsafeGetConfigByVal(Level level, const std::map* confMap, const char* confName) { ELPP_UNUSED(confName); typename std::map::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 Conf_T& unsafeGetConfigByRef(Level level, std::map* confMap, const char* confName) { ELPP_UNUSED(confName); typename std::map::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 void setValue(Level level, const Conf_T& value, std::map* 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::map::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 { 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 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; } private: LogMessage* m_logMessage; base::DispatchAction m_dispatchAction; friend class base::LogDispatcher; inline void setLogMessage(LogMessage* logMessage) { m_logMessage = logMessage; } inline void setDispatchAction(base::DispatchAction dispatchAction) { m_dispatchAction = dispatchAction; } }; class LogDispatchCallback : public Callback { private: friend class base::LogDispatcher; }; class PerformanceTrackingCallback : public Callback { private: friend class base::PerformanceTracker; }; class LoggerRegistrationCallback : public Callback { 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 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 configuations from. class Logger : public base::threading::ThreadSafe, public Loggable { public: Logger(const std::string& id, base::LogStreamsReferenceMap* logStreamsReference); Logger(const std::string& id, const Configurations& configurations, base::LogStreamsReferenceMap* 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 \ inline void FUNCTION_NAME(const char*, const T&, const Args&...);\ template \ inline void FUNCTION_NAME(const T&); template inline void verbose(int, const char*, const T&, const Args&...); template 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::map m_unflushedCount; base::LogStreamsReferenceMap* m_logStreamsReference; 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 void log_(Level, int, const char*, const T&, const Args&...); template inline void log_(Level, int, const T&); template void log(Level, const char*, const T&, const Args&...); template 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 { 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)); } inline Configurations* defaultConfigurations(void) { return &m_defaultConfigurations; } Logger* get(const std::string& id, bool forceCreation = true); template inline bool installLoggerRegistrationCallback(const std::string& id) { return base::utils::Utils::installCallback(id, &m_loggerRegistrationCallbacks); } template inline void uninstallLoggerRegistrationCallback(const std::string& id) { base::utils::Utils::uninstallCallback(id, &m_loggerRegistrationCallbacks); } template inline T* loggerRegistrationCallback(const std::string& id) { return base::utils::Utils::callback(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::unregister(logger->id()); } inline base::LogStreamsReferenceMap* 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::LogStreamsReferenceMap m_logStreamsReference; std::map 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::map& 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::map 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 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* customFormatSpecifiers(void) const { return &m_customFormatSpecifiers; } inline void setLoggingLevel(Level level) { m_loggingLevel = level; } template inline bool installLogDispatchCallback(const std::string& id) { return base::utils::Utils::installCallback(id, &m_logDispatchCallbacks); } template inline void uninstallLogDispatchCallback(const std::string& id) { base::utils::Utils::uninstallCallback(id, &m_logDispatchCallbacks); } template inline T* logDispatchCallback(const std::string& id) { return base::utils::Utils::callback(id, &m_logDispatchCallbacks); } #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) template inline bool installPerformanceTrackingCallback(const std::string& id) { return base::utils::Utils::installCallback(id, &m_performanceTrackingCallbacks); } template inline void uninstallPerformanceTrackingCallback(const std::string& id) { base::utils::Utils::uninstallCallback(id, &m_performanceTrackingCallbacks); } template inline T* performanceTrackingCallback(const std::string& id) { return base::utils::Utils::callback(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(lock()); m_threadNames[base::threading::getCurrentThreadId()] = name; } inline std::string getThreadName(const std::string& threadId) { std::map::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::map m_logDispatchCallbacks; std::map m_performanceTrackingCallbacks; std::map m_threadNames; std::vector m_customFormatSpecifiers; 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(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_continueRunningMutex); m_continueRunning = value; } bool continueRunning(void) const { return m_continueRunning; } private: std::condition_variable cv; bool m_continueRunning; base::threading::Mutex m_continueRunningMutex; }; #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(std::move(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 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 Comparator = std::less> class IterablePriorityQueue : public IterableContainer, public std::priority_queue { public: IterablePriorityQueue(std::priority_queue 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> class IterableQueue : public IterableContainer, public std::queue { public: IterableQueue(std::queue 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> class IterableStack : public IterableContainer, public std::stack { public: IterableStack(std::stack 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_containerLogSeperator(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 \ inline MessageBuilder& operator<<(const temp& template_inst) { \ return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ } #define ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(temp) \ template \ inline MessageBuilder& operator<<(const temp& template_inst) { \ return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ } #define ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(temp) \ template \ inline MessageBuilder& operator<<(const temp& template_inst) { \ return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ } #define ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(temp) \ template \ inline MessageBuilder& operator<<(const temp& template_inst) { \ return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ } #define ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(temp) \ template \ inline MessageBuilder& operator<<(const temp& 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 inline MessageBuilder& operator<<(const std::queue& queue_) { base::workarounds::IterableQueue iterableQueue_ = static_cast >(queue_); return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size()); } template inline MessageBuilder& operator<<(const std::stack& stack_) { base::workarounds::IterableStack iterableStack_ = static_cast >(stack_); return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size()); } template inline MessageBuilder& operator<<(const std::priority_queue& priorityQueue_) { base::workarounds::IterablePriorityQueue iterablePriorityQueue_ = static_cast >(priorityQueue_); return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size()); } template MessageBuilder& operator<<(const std::pair& pair_) { m_logger->stream() << ELPP_LITERAL("("); operator << (static_cast(pair_.first)); m_logger->stream() << ELPP_LITERAL(", "); operator << (static_cast(pair_.second)); m_logger->stream() << ELPP_LITERAL(")"); return *this; } template MessageBuilder& operator<<(const std::bitset& bitset_) { m_logger->stream() << ELPP_LITERAL("["); operator << (bitset_.to_string()); m_logger->stream() << ELPP_LITERAL("]"); return *this; } # if defined(ELPP_LOG_STD_ARRAY) template inline MessageBuilder& operator<<(const std::array& 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 MessageBuilder& operator<<(const QPair& pair_) { m_logger->stream() << ELPP_LITERAL("("); operator << (static_cast(pair_.first)); m_logger->stream() << ELPP_LITERAL(", "); operator << (static_cast(pair_.second)); m_logger->stream() << ELPP_LITERAL(")"); return *this; } template MessageBuilder& operator<<(const QMap& map_) { m_logger->stream() << ELPP_LITERAL("["); QList keys = map_.keys(); typename QList::const_iterator begin = keys.begin(); typename QList::const_iterator end = keys.end(); int max_ = static_cast(base::consts::kMaxLogPerContainer); // to prevent warning for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { m_logger->stream() << ELPP_LITERAL("("); operator << (static_cast(*begin)); m_logger->stream() << ELPP_LITERAL(", "); operator << (static_cast(map_.value(*begin))); m_logger->stream() << ELPP_LITERAL(")"); m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL("")); } if (begin != end) { m_logger->stream() << ELPP_LITERAL("..."); } m_logger->stream() << ELPP_LITERAL("]"); return *this; } template inline MessageBuilder& operator<<(const QMultiMap& map_) { operator << (static_cast>(map_)); return *this; } template MessageBuilder& operator<<(const QHash& hash_) { m_logger->stream() << ELPP_LITERAL("["); QList keys = hash_.keys(); typename QList::const_iterator begin = keys.begin(); typename QList::const_iterator end = keys.end(); int max_ = static_cast(base::consts::kMaxLogPerContainer); // prevent type warning for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { m_logger->stream() << ELPP_LITERAL("("); operator << (static_cast(*begin)); m_logger->stream() << ELPP_LITERAL(", "); operator << (static_cast(hash_.value(*begin))); m_logger->stream() << ELPP_LITERAL(")"); m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL("")); } if (begin != end) { m_logger->stream() << ELPP_LITERAL("..."); } m_logger->stream() << ELPP_LITERAL("]"); return *this; } template inline MessageBuilder& operator<<(const QMultiHash& multiHash_) { operator << (static_cast>(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. Insance 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 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_containerLogSeperator; template 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_containerLogSeperator : 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 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_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel), m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) { } virtual ~Writer(void) { processDispatch(); } template 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: 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 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 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 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("")); } } else { base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log; } } template inline void Logger::log(Level level, const char* s, const T& value, const Args&... args) { base::threading::ScopedLock scopedLock(lock()); log_(level, 0, s, value, args...); } template inline void Logger::log(Level level, const T& log) { base::threading::ScopedLock scopedLock(lock()); log_(level, 0, log); } # if ELPP_VERBOSE_LOG template inline void Logger::verbose(int vlevel, const char* s, const T& value, const Args&... args) { base::threading::ScopedLock scopedLock(lock()); log_(el::Level::Verbose, vlevel, s, value, args...); } template inline void Logger::verbose(int vlevel, const T& log) { base::threading::ScopedLock scopedLock(lock()); log_(el::Level::Verbose, vlevel, log); } # else template inline void Logger::verbose(int, const char*, const T&, const Args&...) { return; } template inline void Logger::verbose(int, const T&) { return; } # endif // ELPP_VERBOSE_LOG # define LOGGER_LEVEL_WRITERS(FUNCTION_NAME, LOG_LEVEL)\ template \ inline void Logger::FUNCTION_NAME(const char* s, const T& value, const Args&... args) {\ log(LOG_LEVEL, s, value, args...);\ }\ template \ inline void Logger::FUNCTION_NAME(const T& value) {\ log(LOG_LEVEL, value);\ } # define LOGGER_LEVEL_WRITERS_DISABLED(FUNCTION_NAME, LOG_LEVEL)\ template \ inline void Logger::FUNCTION_NAME(const char*, const T&, const Args&...) {\ return;\ }\ template \ 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(&m_performanceTracker->m_blockName); } inline const struct timeval* PerformanceTrackingData::startTime() const { return const_cast(&m_performanceTracker->m_startTime); } inline const struct timeval* PerformanceTrackingData::endTime() const { return const_cast(&m_performanceTracker->m_endTime); } inline const struct timeval* PerformanceTrackingData::lastCheckpointTime() const { return const_cast(&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 char* loc, const char* demang, const char* hex, const char* addr); StackTraceEntry(std::size_t index, char* 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& getLatestStack(void) { return m_stack; } friend std::ostream& operator<<(std::ostream& os, const StackTrace& st); private: std::vector 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) 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(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 static inline bool installLogDispatchCallback(const std::string& id) { return ELPP->installLogDispatchCallback(id); } /// @brief Uninstalls log dispatch callback template static inline void uninstallLogDispatchCallback(const std::string& id) { ELPP->uninstallLogDispatchCallback(id); } template static inline T* logDispatchCallback(const std::string& id) { return ELPP->logDispatchCallback(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 static inline bool installPerformanceTrackingCallback(const std::string& id) { return ELPP->installPerformanceTrackingCallback(id); } /// @brief Uninstalls post performance tracking handler template static inline void uninstallPerformanceTrackingCallback(const std::string& id) { ELPP->uninstallPerformanceTrackingCallback(id); } template static inline T* performanceTrackingCallback(const std::string& id) { return ELPP->performanceTrackingCallback(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 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 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 (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 static inline bool installLoggerRegistrationCallback(const std::string& id) { return ELPP->registeredLoggers()->installLoggerRegistrationCallback(id); } /// @brief Uninstalls log dispatch callback template static inline void uninstallLoggerRegistrationCallback(const std::string& id) { ELPP->registeredLoggers()->uninstallLoggerRegistrationCallback(id); } template static inline T* loggerRegistrationCallback(const std::string& id) { return ELPP->registeredLoggers()->loggerRegistrationCallback(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::LogStreamsReferenceMap* 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* populateAllLoggerIds(std::vector* 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 attempeted 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