You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4003 lines
149 KiB
4003 lines
149 KiB
///////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// easylogging++.h - Core of EasyLogging++ //
|
|
// //
|
|
// EasyLogging++ v8.91 //
|
|
// Cross platform logging made easy for C++ applications //
|
|
// Author Majid Khan <mkhan3189@gmail.com> //
|
|
// http://www.icplusplus.com/tools/easylogging //
|
|
// https://github.com/mkhan3189/EasyLoggingPP //
|
|
// //
|
|
// Copyright (c) 2012-2013 Majid Khan //
|
|
// //
|
|
// This software is provided 'as-is', without any express or implied //
|
|
// warranty. In no event will the authors be held liable for any damages //
|
|
// arising from the use of this software. //
|
|
// //
|
|
// Permission is granted to anyone to use this software for any purpose, //
|
|
// including commercial applications, and to alter it and redistribute //
|
|
// it freely, subject to the following restrictions: //
|
|
// //
|
|
// 1. The origin of this software must not be misrepresented; you must //
|
|
// not claim that you wrote the original software. If you use this //
|
|
// software in a product, an acknowledgment in the product documentation //
|
|
// would be appreciated but is not required. //
|
|
// //
|
|
// 2. Altered source versions must be plainly marked as such, and must //
|
|
// not be misrepresented as being the original software. //
|
|
// //
|
|
// 3. This notice may not be removed or altered from any source //
|
|
// distribution //
|
|
// //
|
|
// PLEASE NOTE: THIS FILE MAY BE CHANGED. TO GET ORIGINAL VERSION //
|
|
// EITHER DOWNLOAD IT FROM http://www.icplusplus.com/tools/easylogging/ //
|
|
// OR PULL IT FROM https://github.com/mkhan3189/EasyLoggingPP (master branch) //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef EASYLOGGINGPP_H
|
|
#define EASYLOGGINGPP_H
|
|
#include <string>
|
|
#include <vector>
|
|
//
|
|
// Log location macros
|
|
//
|
|
#if !defined(__FILE__)
|
|
# define __FILE__ ""
|
|
#endif // !defined(__FILE__)
|
|
#if !defined(__LINE__)
|
|
# define __LINE__ 0
|
|
#endif // !defined(__LINE__)
|
|
// Appropriate function macro
|
|
#if defined(__func__)
|
|
# undef __func__
|
|
#endif // defined(__func__)
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
|
# define __func__ __FUNCSIG__
|
|
#elif defined(__GNUC__) && (__GNUC__ >= 2)
|
|
# define __func__ __PRETTY_FUNCTION__
|
|
#elif defined(__clang__) && (__clang__ == 1)
|
|
# define __func__ __PRETTY_FUNCTION__
|
|
#else
|
|
# define __func__ ""
|
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1020)
|
|
//
|
|
// Compiler evaluation
|
|
// http://isocpp.org/blog/2013/05/gcc-4.8.1-released-c11-feature-complete
|
|
// http://msdn.microsoft.com/en-us/library/vstudio/hh567368.aspx
|
|
//
|
|
// GNU
|
|
#if defined(__GNUC__)
|
|
# define _ELPP_GCC_VERSION (__GNUC__ * 10000 \
|
|
+ __GNUC_MINOR__ * 100 \
|
|
+ __GNUC_PATCHLEVEL__)
|
|
# if defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
# define _ELPP_CXX0X 1
|
|
# elif (_ELPP_GCC_VERSION >= 40801)
|
|
# define _ELPP_CXX11 1
|
|
# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
#endif // defined(__GNUC__)
|
|
// VC++
|
|
#if defined(_MSC_VER)
|
|
# if (_MSC_VER >= 1400) // VC++ 8.0
|
|
# define _ELPP_CRT_DBG_WARNINGS 1
|
|
# else
|
|
# define _ELPP_CRT_DBG_WARNINGS 0
|
|
# endif // (_MSC_VER >= 1400)
|
|
# if (_MSC_VER == 1600)
|
|
# define _ELPP_CXX0X 1
|
|
# elif (_MSC_VER == 1700)
|
|
# define _ELPP_CXX11 1
|
|
# endif // (_MSC_VER == 1600)
|
|
#else
|
|
# define _ELPP_CRT_DBG_WARNINGS 0
|
|
#endif // defined(_MSC_VER)
|
|
// Clang
|
|
#if defined(__clang__) && (__clang__ == 1)
|
|
# define _ELPP_CLANG_VERSION (__clang_major__ * 10000 \
|
|
+ __clang_minor__ * 100 \
|
|
+ __clang_patchlevel__)
|
|
# if (_ELPP_CLANG_VERSION >= 30300)
|
|
# define _ELPP_CXX11 1
|
|
# endif // (_ELPP_CLANG_VERSION >= 30300)
|
|
#endif // defined(__clang__) && (__clang__ == 1)
|
|
// MinGW
|
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
|
# define _ELPP_MINGW 1
|
|
#else
|
|
# define _ELPP_MINGW 0
|
|
#endif // defined(__MINGW32__) || defined(__MINGW64__)
|
|
#if defined(__ANDROID__)
|
|
# define _ELPP_NDK 1
|
|
#else
|
|
# define _ELPP_NDK 0
|
|
#endif // defined(__ANDROID__)
|
|
// Some special functions that are special for VC++
|
|
// This is to prevent CRT security warnings and to override deprecated methods but at the same time
|
|
// MinGW does not support some functions, so we need to make sure that proper function is used.
|
|
#if _ELPP_CRT_DBG_WARNINGS
|
|
# define SPRINTF sprintf_s
|
|
# define STRTOK(a,b,c) strtok_s(a,b,c)
|
|
#else
|
|
# define SPRINTF sprintf
|
|
# define STRTOK(a,b,c) strtok(a,b)
|
|
#endif
|
|
// std::thread availablity
|
|
#if defined(__GNUC__) && (!_ELPP_NDK) && (_ELPP_CXX0X || _ELPP_CXX11)
|
|
# define _ELPP_STD_THREAD_AVAILABLE 1
|
|
#elif defined(_MSC_VER) && (!_ELPP_NDK) && (_ELPP_CXX11)
|
|
# define _ELPP_STD_THREAD_AVAILABLE 1
|
|
#elif defined(__clang__) && (!_ELPP_NDK) && (__clang__ == 1) && (_ELPP_CXX11)
|
|
# define _ELPP_STD_THREAD_AVAILABLE 1
|
|
#else
|
|
# define _ELPP_STD_THREAD_AVAILABLE 0
|
|
#endif // defined(__GNUC__) && (_ELPP_CXX0X || _ELPP_CXX11)
|
|
// Qt
|
|
#if defined(QT_CORE_LIB)
|
|
# if (defined(QT_VERSION) && QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
|
# define _ELPP_QT_5 1
|
|
# else
|
|
# define _ELPP_QT_5 0
|
|
# endif // (defined(QT_VERSION) && QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
|
#endif // defined(QT_CORE_LIB)
|
|
//
|
|
// High-level log evaluation
|
|
//
|
|
#if (defined(_DISABLE_LOGS))
|
|
# define _ENABLE_EASYLOGGING 0
|
|
#else
|
|
# define _ENABLE_EASYLOGGING 1
|
|
#endif // (!defined(_DISABLE_LOGS))
|
|
//
|
|
// OS evaluation
|
|
//
|
|
// Windows
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
# define _ELPP_OS_WINDOWS 1
|
|
#else
|
|
# define _ELPP_OS_WINDOWS 0
|
|
#endif // defined(_WIN32) || defined(_WIN64)
|
|
// Linux
|
|
#if (defined(__linux) || defined(__linux__))
|
|
# define _ELPP_OS_LINUX 1
|
|
#else
|
|
# define _ELPP_OS_LINUX 0
|
|
#endif // (defined(__linux) || defined(__linux__))
|
|
// Mac
|
|
#if defined(__APPLE__)
|
|
# define _ELPP_OS_MAC 1
|
|
#else
|
|
# define _ELPP_OS_MAC 0
|
|
#endif // defined(__APPLE__)
|
|
// Unix
|
|
#define _ELPP_OS_UNIX ((_ELPP_OS_LINUX || _ELPP_OS_MAC) && (!_ELPP_OS_WINDOWS))
|
|
// Assembly
|
|
#if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || \
|
|
(defined(_MSC_VER) && (defined(_M_IX86)))
|
|
# define _ELPP_ASSEMBLY_SUPPORTED 1
|
|
#else
|
|
# define _ELPP_ASSEMBLY_SUPPORTED 0
|
|
#endif
|
|
#if (!defined(_DISABLE_ELPP_ASSERT))
|
|
# if (defined(_STOP_ON_FIRST_ELPP_ASSERTION))
|
|
# define __EASYLOGGINGPP_ASSERT(expr, msg) if (!(expr)) { std::cerr << "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] with message \"" << msg << "\"" << std::endl; exit(1); }
|
|
# else
|
|
# define __EASYLOGGINGPP_ASSERT(expr, msg) if (!(expr)) { std::cerr << "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] with message \"" << msg << "\"" << std::endl; }
|
|
# endif // (defined(_STOP_ON_FIRST_ELPP_ASSERTION))
|
|
#else
|
|
# define __EASYLOGGINGPP_ASSERT(x, y)
|
|
#endif // (!defined(_DISABLE_ELPP_ASSERT))
|
|
#define __EASYLOGGINGPP_SUPPRESS_UNSED(x) (void)x;
|
|
#if _ELPP_OS_UNIX
|
|
// Log file permissions for unix-based systems
|
|
# define _LOG_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH
|
|
#endif // _ELPP_OS_UNIX
|
|
#if (!defined(_DISABLE_MUTEX) && (_ENABLE_EASYLOGGING))
|
|
# define _ELPP_ENABLE_MUTEX 1
|
|
#else
|
|
# define _ELPP_ENABLE_MUTEX 0
|
|
#endif // (!defined(_DISABLE_MUTEX) && (_ENABLE_EASYLOGGING))
|
|
#if (!defined(_DISABLE_DEBUG_LOGS) && (_ENABLE_EASYLOGGING) && ((defined(_DEBUG)) || (!defined(NDEBUG))))
|
|
# define _ELPP_DEBUG_LOG 1
|
|
#else
|
|
# define _ELPP_DEBUG_LOG 0
|
|
#endif // (!defined(_DISABLE_DEBUG_LOGS) && (_ENABLE_EASYLOGGING) && ((defined(_DEBUG)) || (!defined(NDEBUG))))
|
|
#if (!defined(_DISABLE_INFO_LOGS) && (_ENABLE_EASYLOGGING))
|
|
# define _ELPP_INFO_LOG 1
|
|
#else
|
|
# define _ELPP_INFO_LOG 0
|
|
#endif // (!defined(_DISABLE_INFO_LOGS) && (_ENABLE_EASYLOGGING))
|
|
#if (!defined(_DISABLE_WARNING_LOGS) && (_ENABLE_EASYLOGGING))
|
|
# define _ELPP_WARNING_LOG 1
|
|
#else
|
|
# define _ELPP_WARNING_LOG 0
|
|
#endif // (!defined(_DISABLE_WARNING_LOGS) && (_ENABLE_EASYLOGGING))
|
|
#if (!defined(_DISABLE_ERROR_LOGS) && (_ENABLE_EASYLOGGING))
|
|
# define _ELPP_ERROR_LOG 1
|
|
#else
|
|
# define _ELPP_ERROR_LOG 0
|
|
#endif // (!defined(_DISABLE_ERROR_LOGS) && (_ENABLE_EASYLOGGING))
|
|
#if (!defined(_DISABLE_FATAL_LOGS) && (_ENABLE_EASYLOGGING))
|
|
# define _ELPP_FATAL_LOG 1
|
|
#else
|
|
# define _ELPP_FATAL_LOG 0
|
|
#endif // (!defined(_DISABLE_FATAL_LOGS) && (_ENABLE_EASYLOGGING))
|
|
#if (defined(_QUALITY_ASSURANCE) && (_ENABLE_EASYLOGGING))
|
|
# define _ELPP_QA_LOG 1
|
|
#else
|
|
# define _ELPP_QA_LOG 0
|
|
#endif // (defined(_QUALITY_ASSURANCE) && (_ENABLE_EASYLOGGING))
|
|
#if (!defined(_DISABLE_TRACE_LOGS) && (_ENABLE_EASYLOGGING))
|
|
# define _ELPP_TRACE_LOG 1
|
|
#else
|
|
# define _ELPP_TRACE_LOG 0
|
|
#endif // (!defined(_DISABLE_TRACE_LOGS) && (_ENABLE_EASYLOGGING))
|
|
#if (!defined(_DISABLE_VERBOSE_LOGS) && (_ENABLE_EASYLOGGING))
|
|
# define _ELPP_VERBOSE_LOG 1
|
|
#else
|
|
# define _ELPP_VERBOSE_LOG 0
|
|
#endif // (!defined(_DISABLE_VERBOSE_LOGS) && (_ENABLE_EASYLOGGING))
|
|
#define ELPP_FOR_EACH(variableName, initialValue, operation, limit) unsigned int variableName = initialValue; \
|
|
do { \
|
|
operation \
|
|
variableName = variableName << 1; \
|
|
if (variableName == 0) { ++variableName; } \
|
|
} while (variableName <= limit)
|
|
#define ELPP_FOR_EACH_LEVEL(variableName, initialValue, operation) \
|
|
ELPP_FOR_EACH(variableName, initialValue, operation, easyloggingpp::Level::kMaxValid)
|
|
#define ELPP_FOR_EACH_CONFIGURATION(variableName, initialValue, operation) \
|
|
ELPP_FOR_EACH(variableName, initialValue, operation, easyloggingpp::ConfigurationType::kMaxValid)
|
|
// Includes
|
|
#include <ctime>
|
|
#include <cstring>
|
|
#include <cstdlib>
|
|
#include <cctype>
|
|
#include <cwchar>
|
|
#if _ELPP_NDK
|
|
# include <sys/system_properties.h>
|
|
#endif // _ELPP_NDK
|
|
#if _ELPP_OS_UNIX
|
|
# include <sys/stat.h>
|
|
# include <sys/time.h>
|
|
# if (_ELPP_ENABLE_MUTEX)
|
|
# if (_ELPP_ASSEMBLY_SUPPORTED)
|
|
# include <sched.h>
|
|
# else
|
|
# include <pthread.h>
|
|
# endif // (_ELPP_ASSEMBLY_SUPPORTED)
|
|
# endif // (_ELPP_ENABLE_MUTEX)
|
|
#elif _ELPP_OS_WINDOWS
|
|
# include <direct.h>
|
|
# include <Windows.h>
|
|
#endif // _ELPP_OS_UNIX
|
|
#include <string>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <functional>
|
|
#include <algorithm>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#if (_ELPP_STD_THREAD_AVAILABLE)
|
|
# include <thread>
|
|
#endif // _ELPP_STD_THREAD_AVAILABLE
|
|
#if defined(_ELPP_STL_LOGGING)
|
|
// For logging STL based templates
|
|
# include <list>
|
|
# include <utility>
|
|
# include <queue>
|
|
# include <deque>
|
|
# include <set>
|
|
# include <bitset>
|
|
# include <stack>
|
|
#endif // defined(_ELPP_STL_LOGGING)
|
|
#if defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING)
|
|
// For logging Qt based classes & templates
|
|
# include <QString>
|
|
# include <QVector>
|
|
# include <QList>
|
|
# include <QPair>
|
|
# include <QMap>
|
|
# include <QQueue>
|
|
# include <QSet>
|
|
# include <QLinkedList>
|
|
# include <QHash>
|
|
# include <QMultiHash>
|
|
# include <QStack>
|
|
#endif // defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING)
|
|
namespace easyloggingpp {
|
|
namespace internal {
|
|
|
|
class NoCopy {
|
|
protected:
|
|
NoCopy(void) {}
|
|
private:
|
|
NoCopy(const NoCopy&);
|
|
NoCopy& operator=(const NoCopy&);
|
|
};
|
|
|
|
class StaticClass {
|
|
private:
|
|
StaticClass(void);
|
|
StaticClass(const StaticClass&);
|
|
StaticClass& operator=(const StaticClass&);
|
|
};
|
|
} // namespace internal
|
|
|
|
struct Level : private internal::StaticClass {
|
|
public:
|
|
enum {
|
|
All = 0, Debug = 1, Info = 2, Warning = 4, Error = 8,
|
|
Fatal = 16, Verbose = 32, QA = 64, Trace = 128, Unknown = 1010
|
|
};
|
|
|
|
static const unsigned int kMinValid = All;
|
|
static const unsigned int kMaxValid = Trace;
|
|
|
|
static std::string convertToString(unsigned int level_) {
|
|
switch (level_) {
|
|
case All:
|
|
return std::string("ALL");
|
|
case Debug:
|
|
return std::string("DEBUG");
|
|
case Info:
|
|
return std::string("INFO");
|
|
case Warning:
|
|
return std::string("WARNING");
|
|
case Error:
|
|
return std::string("ERROR");
|
|
case Fatal:
|
|
return std::string("FATAL");
|
|
case QA:
|
|
return std::string("QA");
|
|
case Verbose:
|
|
return std::string("VERBOSE");
|
|
case Trace:
|
|
return std::string("TRACE");
|
|
default:
|
|
return std::string("UNKNOWN");
|
|
}
|
|
}
|
|
|
|
static unsigned int convertFromString(const std::string& levelStr) {
|
|
if (levelStr == "all" || levelStr == "ALL") return Level::All;
|
|
if (levelStr == "debug" || levelStr == "DEBUG") return Level::Debug;
|
|
if (levelStr == "info" || levelStr == "INFO") return Level::Info;
|
|
if (levelStr == "warning" || levelStr == "WARNING") return Level::Warning;
|
|
if (levelStr == "error" || levelStr == "ERROR") return Level::Error;
|
|
if (levelStr == "fatal" || levelStr == "FATAL") return Level::Fatal;
|
|
if (levelStr == "qa" || levelStr == "QA") return Level::QA;
|
|
if (levelStr == "verbose" || levelStr == "VERBOSE") return Level::Verbose;
|
|
if (levelStr == "trace" || levelStr == "TRACE") return Level::Trace;
|
|
return Level::Unknown;
|
|
}
|
|
};
|
|
|
|
struct ConfigurationType : private internal::StaticClass {
|
|
public:
|
|
enum {
|
|
Enabled = 0, ToFile = 1, ToStandardOutput = 2, Format = 4, Filename = 8,
|
|
MillisecondsWidth = 16, PerformanceTracking = 32, RollOutSize = 64, Unknown = 1010
|
|
};
|
|
|
|
static const unsigned int kMinValid = Enabled;
|
|
static const unsigned int kMaxValid = RollOutSize;
|
|
|
|
static std::string convertToString(unsigned int configurationType_) {
|
|
switch (configurationType_) {
|
|
case Enabled:
|
|
return std::string("ENABLED");
|
|
case Filename:
|
|
return std::string("FILENAME");
|
|
case Format:
|
|
return std::string("FORMAT");
|
|
case ToFile:
|
|
return std::string("TO_FILE");
|
|
case ToStandardOutput:
|
|
return std::string("TO_STANDARD_OUTPUT");
|
|
case MillisecondsWidth:
|
|
return std::string("MILLISECONDS_WIDTH");
|
|
case PerformanceTracking:
|
|
return std::string("PERFORMANCE_TRACKING");
|
|
case RollOutSize:
|
|
return std::string("ROLL_OUT_SIZE");
|
|
default: return std::string("UNKNOWN");
|
|
}
|
|
}
|
|
|
|
static unsigned int convertFromString(const std::string& configStr) {
|
|
if (configStr == "enabled" || configStr == "ENABLED") return ConfigurationType::Enabled;
|
|
if (configStr == "to_file" || configStr == "TO_FILE") return ConfigurationType::ToFile;
|
|
if (configStr == "to_standard_output" || configStr == "TO_STANDARD_OUTPUT") return ConfigurationType::ToStandardOutput;
|
|
if (configStr == "format" || configStr == "FORMAT") return ConfigurationType::Format;
|
|
if (configStr == "filename" || configStr == "FILENAME") return ConfigurationType::Filename;
|
|
if (configStr == "milliseconds_width" || configStr == "MILLISECONDS_WIDTH") return ConfigurationType::MillisecondsWidth;
|
|
if (configStr == "performance_tracking" || configStr == "PERFORMANCE_TRACKING") return ConfigurationType::PerformanceTracking;
|
|
if (configStr == "roll_out_size" || configStr == "ROLL_OUT_SIZE") return ConfigurationType::RollOutSize;
|
|
return ConfigurationType::Unknown;
|
|
}
|
|
};
|
|
|
|
namespace internal {
|
|
struct Aspect : private internal::StaticClass {
|
|
public:
|
|
enum {
|
|
Normal = 0, Conditional = 1, Interval = 2
|
|
};
|
|
};
|
|
|
|
//!
|
|
//! Used internally. You should not need this class.
|
|
//!
|
|
class Constants : private internal::NoCopy {
|
|
public:
|
|
Constants (void) :
|
|
//
|
|
// Log level name outputs
|
|
//
|
|
LOG_INFO_LEVEL_VALUE ("INFO") ,
|
|
LOG_DEBUG_LEVEL_VALUE ("DEBUG"),
|
|
LOG_WARNING_LEVEL_VALUE("WARN"),
|
|
LOG_ERROR_LEVEL_VALUE ("ERROR"),
|
|
LOG_FATAL_LEVEL_VALUE ("FATAL"),
|
|
LOG_VERBOSE_LEVEL_VALUE("VER"),
|
|
LOG_QA_LEVEL_VALUE ("QA"),
|
|
LOG_TRACE_LEVEL_VALUE ("TRACE"),
|
|
//
|
|
// Format specifiers
|
|
//
|
|
APP_NAME_FORMAT_SPECIFIER ("%app"),
|
|
LOGGER_ID_FORMAT_SPECIFIER ("%logger"),
|
|
THREAD_ID_FORMAT_SPECIFIER ("%thread"),
|
|
LEVEL_FORMAT_SPECIFIER ("%level"),
|
|
DATE_ONLY_FORMAT_SPECIFIER ("%date"),
|
|
TIME_ONLY_FORMAT_SPECIFIER ("%time"),
|
|
DATE_TIME_FORMAT_SPECIFIER ("%datetime"),
|
|
LOCATION_FORMAT_SPECIFIER ("%loc"),
|
|
FUNCTION_FORMAT_SPECIFIER ("%func"),
|
|
USER_FORMAT_SPECIFIER ("%user"),
|
|
HOST_FORMAT_SPECIFIER ("%host"),
|
|
LOG_MESSAGE_FORMAT_SPECIFIER ("%log"),
|
|
VERBOSE_LEVEL_FORMAT_SPECIFIER ("%vlevel"),
|
|
//
|
|
// Others
|
|
//
|
|
NULL_POINTER ("nullptr"),
|
|
FORMAT_SPECIFIER_ESCAPE_CHAR ('E'),
|
|
MAX_LOG_PER_CONTAINER (100),
|
|
MAX_LOG_PER_COUNTER (100000),
|
|
DEFAULT_MILLISECOND_OFFSET (1000),
|
|
MAX_VERBOSE_LEVEL (9),
|
|
CURRENT_VERBOSE_LEVEL (0), // Set dynamically from registeredLoggers
|
|
#if _ELPP_OS_UNIX
|
|
PATH_SLASH ("/"),
|
|
#elif _ELPP_OS_WINDOWS
|
|
PATH_SLASH ("\\"),
|
|
#endif // _ELPP_OS_UNIX,
|
|
DEFAULT_LOG_FILENAME ("myeasylog.log")
|
|
{
|
|
// Trivial logger configuration - only to set format (difference: not using %logger)
|
|
//C:/logs/unv8TestLogs.log\n
|
|
//C:/logs/CCtest.log\n
|
|
std::stringstream ss;
|
|
ss << " * ALL:\n";
|
|
ss << " FORMAT = %datetime %level %log\n";
|
|
ss << " FILENAME = C:/log/CCtest.log\n";
|
|
ss << " ENABLED = true\n";
|
|
ss << " TO_FILE = true\n";
|
|
ss << " TO_STANDARD_OUTPUT = false\n";
|
|
ss << " MILLISECONDS_WIDTH = 3\n";
|
|
ss << " PERFORMANCE_TRACKING = false\n";
|
|
ss << " ROLL_OUT_SIZE = 2097152\n";
|
|
|
|
DEFAULT_LOGGER_CONFIGURATION = ss.str();
|
|
} // C'tor
|
|
//
|
|
// Log level name outputs
|
|
//
|
|
const std::string LOG_INFO_LEVEL_VALUE;
|
|
const std::string LOG_DEBUG_LEVEL_VALUE;
|
|
const std::string LOG_WARNING_LEVEL_VALUE;
|
|
const std::string LOG_ERROR_LEVEL_VALUE;
|
|
const std::string LOG_FATAL_LEVEL_VALUE;
|
|
const std::string LOG_VERBOSE_LEVEL_VALUE;
|
|
const std::string LOG_QA_LEVEL_VALUE;
|
|
const std::string LOG_TRACE_LEVEL_VALUE;
|
|
//
|
|
// Format specifiers
|
|
//
|
|
const std::string APP_NAME_FORMAT_SPECIFIER;
|
|
const std::string LOGGER_ID_FORMAT_SPECIFIER;
|
|
const std::string THREAD_ID_FORMAT_SPECIFIER;
|
|
const std::string LEVEL_FORMAT_SPECIFIER;
|
|
const std::string DATE_ONLY_FORMAT_SPECIFIER;
|
|
const std::string TIME_ONLY_FORMAT_SPECIFIER;
|
|
const std::string DATE_TIME_FORMAT_SPECIFIER;
|
|
const std::string LOCATION_FORMAT_SPECIFIER;
|
|
const std::string FUNCTION_FORMAT_SPECIFIER;
|
|
const std::string USER_FORMAT_SPECIFIER;
|
|
const std::string HOST_FORMAT_SPECIFIER;
|
|
const std::string LOG_MESSAGE_FORMAT_SPECIFIER;
|
|
const std::string VERBOSE_LEVEL_FORMAT_SPECIFIER;
|
|
//
|
|
// Others
|
|
//
|
|
const std::string NULL_POINTER;
|
|
const char FORMAT_SPECIFIER_ESCAPE_CHAR;
|
|
const unsigned int MAX_LOG_PER_CONTAINER;
|
|
const unsigned int MAX_LOG_PER_COUNTER;
|
|
const unsigned int DEFAULT_MILLISECOND_OFFSET;
|
|
const int MAX_VERBOSE_LEVEL;
|
|
int CURRENT_VERBOSE_LEVEL;
|
|
const std::string PATH_SLASH;
|
|
const std::string DEFAULT_LOG_FILENAME;
|
|
std::string DEFAULT_LOGGER_CONFIGURATION;
|
|
|
|
enum kFormatFlags {
|
|
kDateOnly = 2,
|
|
kTimeOnly = 4,
|
|
kDateTime = 8,
|
|
kLoggerId = 16,
|
|
kLocation = 32,
|
|
kFunction = 64,
|
|
kUser = 128,
|
|
kHost = 256,
|
|
kLogMessage = 512,
|
|
kVerboseLevel = 1024,
|
|
kAppName = 2048,
|
|
kThreadId = 4096
|
|
};
|
|
}; // class Constants
|
|
namespace threading {
|
|
|
|
//!
|
|
//! To take care of shared resources in multi-threaded application. Used internally, you should not need it.
|
|
//!
|
|
class Mutex {
|
|
public:
|
|
#if _ELPP_ASSEMBLY_SUPPORTED
|
|
# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
|
# define _ELPP_MUTEX_LOCK_GNU_ASM(lf_, old_) "movl $1,%%eax\n" \
|
|
"\txchg %%eax,%0\n" \
|
|
"\tmovl %%eax,%1\n" \
|
|
"\t" : "=m" (lf_), "=m" (old_) : : "%eax", "memory"
|
|
# define _ELPP_MUTEX_UNLOCK_GNU_ASM(lf_) "movl $0,%%eax\n" \
|
|
"\txchg %%eax,%0\n" \
|
|
"\t" : "=m" (lf_) : : "%eax", "memory"
|
|
# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
|
Mutex(void) : lockerFlag_(0) {
|
|
}
|
|
#else
|
|
Mutex(void) {
|
|
# if _ELPP_OS_UNIX
|
|
pthread_mutex_init(&underlyingMutex_, NULL);
|
|
# elif _ELPP_OS_WINDOWS
|
|
InitializeCriticalSection(&underlyingMutex_);
|
|
# endif // _ELPP_OS_UNIX
|
|
}
|
|
|
|
virtual ~Mutex(void) {
|
|
# if _ELPP_OS_UNIX
|
|
pthread_mutex_destroy(&underlyingMutex_);
|
|
# elif _ELPP_OS_WINDOWS
|
|
DeleteCriticalSection(&underlyingMutex_);
|
|
# endif // _ELPP_OS_UNIX
|
|
}
|
|
#endif // _ELPP_ASSEMBLY_SUPPORTED
|
|
|
|
inline void lock(void) {
|
|
#if _ELPP_ASSEMBLY_SUPPORTED
|
|
bool locked = false;
|
|
while (!locked) {
|
|
locked = tryLock();
|
|
if (!locked) {
|
|
# if _ELPP_OS_UNIX
|
|
sched_yield();
|
|
# elif _ELPP_OS_WINDOWS
|
|
Sleep(0);
|
|
# endif
|
|
}
|
|
}
|
|
#else
|
|
# if _ELPP_OS_UNIX
|
|
pthread_mutex_lock(&underlyingMutex_);
|
|
# elif _ELPP_OS_WINDOWS
|
|
EnterCriticalSection(&underlyingMutex_);
|
|
# endif // _ELPP_OS_UNIX
|
|
#endif // _ELPP_ASSEMBLY_SUPPORTED
|
|
}
|
|
|
|
inline bool tryLock(void) {
|
|
#if _ELPP_ASSEMBLY_SUPPORTED
|
|
int oldLock_;
|
|
# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
|
asm volatile (_ELPP_MUTEX_LOCK_GNU_ASM(lockerFlag_, oldLock_));
|
|
# elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
|
int *ptrLock = &lockerFlag_;
|
|
__asm {
|
|
mov eax,1
|
|
mov ecx,ptrLock
|
|
xchg eax,[ecx]
|
|
mov oldLock_,eax
|
|
}
|
|
# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
|
return (oldLock_ == 0);
|
|
#else
|
|
# if _ELPP_OS_UNIX
|
|
return (pthread_mutex_trylock(&underlyingMutex_) == 0) ? true : false;
|
|
# elif _ELPP_OS_WINDOWS
|
|
return TryEnterCriticalSection(&underlyingMutex_) ? true : false;
|
|
# endif // _ELPP_OS_UNIX
|
|
#endif // _ELPP_ASSEMBLY_SUPPORTED
|
|
}
|
|
|
|
inline void unlock(void) {
|
|
#if _ELPP_ASSEMBLY_SUPPORTED
|
|
# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
|
asm volatile (_ELPP_MUTEX_UNLOCK_GNU_ASM(lockerFlag_));
|
|
# elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
|
int *ptrLock = &lockerFlag_;
|
|
__asm {
|
|
mov eax,0
|
|
mov ecx,ptrLock
|
|
xchg eax,[ecx]
|
|
}
|
|
# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
|
#else
|
|
# if _ELPP_OS_UNIX
|
|
pthread_mutex_unlock(&underlyingMutex_);
|
|
# elif _ELPP_OS_WINDOWS
|
|
LeaveCriticalSection(&underlyingMutex_);
|
|
# endif // _ELPP_OS_UNIX
|
|
#endif // _ELPP_ASSEMBLY_SUPPORTED
|
|
}
|
|
private:
|
|
#if _ELPP_ASSEMBLY_SUPPORTED
|
|
int lockerFlag_;
|
|
#else
|
|
# if _ELPP_OS_UNIX
|
|
pthread_mutex_t underlyingMutex_;
|
|
# elif _ELPP_OS_WINDOWS
|
|
CRITICAL_SECTION underlyingMutex_;
|
|
# endif // _ELPP_OS_UNIX
|
|
#endif // _ELPP_ASSEMBLY_SUPPORTED
|
|
}; // class Mutex
|
|
//!
|
|
//! Scoped mutex that works same as C++11 <code>std::lock_guard<std::mutex></code>. Used internally, you should not use it.
|
|
//!
|
|
class ScopedLock : private internal::NoCopy {
|
|
public:
|
|
explicit ScopedLock(Mutex& m_) {
|
|
mutex_ = &m_;
|
|
mutex_->lock();
|
|
}
|
|
|
|
virtual ~ScopedLock(void) {
|
|
mutex_->unlock();
|
|
}
|
|
private:
|
|
Mutex* mutex_;
|
|
ScopedLock(void);
|
|
}; // class ScopedLock
|
|
|
|
//!
|
|
//! \return ID of current thread. If std::thread is available it uses get_id() otherwise if on windows it uses
|
|
//! GetCurrentThreadId() otherwise empty string. Used internally, you should not use it.
|
|
//!
|
|
inline std::string getCurrentThreadId(void) {
|
|
std::stringstream ss;
|
|
#if (_ELPP_STD_THREAD_AVAILABLE)
|
|
ss << std::this_thread::get_id();
|
|
#else
|
|
# if (_ELPP_OS_WINDOWS)
|
|
ss << GetCurrentThreadId();
|
|
# endif // (_ELPP_OS_WINDOWS)
|
|
#endif
|
|
return ss.str();
|
|
}
|
|
|
|
} // namespace threading
|
|
namespace utilities {
|
|
|
|
template <typename T>
|
|
inline void safeDelete(T*& pointer, bool checkNullity = true) {
|
|
if (checkNullity && pointer == NULL) return;
|
|
delete pointer;
|
|
pointer = NULL;
|
|
}
|
|
|
|
//!
|
|
//! String utilities class used internally. You should not use it.
|
|
//!
|
|
class StringUtils : private internal::StaticClass {
|
|
public:
|
|
static inline std::string trim(const std::string &str) {
|
|
std::size_t s = str.find_first_not_of(" \n\r\t");
|
|
std::size_t e = str.find_last_not_of(" \n\r\t");
|
|
if ((s == std::string::npos) || (e == std::string::npos)) {
|
|
return "";
|
|
}
|
|
else {
|
|
return str.substr(s, e - s + 1);
|
|
}
|
|
}
|
|
|
|
static inline bool startsWith(const std::string& str, const std::string& start) {
|
|
return (str.length() >= start.length()) && (str.compare(0, start.length(), start) == 0);
|
|
}
|
|
|
|
static inline bool endsWith(const std::string& str, const std::string& end) {
|
|
return (str.length() >= end.length()) && (str.compare(str.length() - end.length(), end.length(), end) == 0);
|
|
}
|
|
|
|
static inline std::vector<std::string>& split(const std::string& s, char delim, std::vector<std::string>& elems) {
|
|
std::stringstream ss(s);
|
|
std::string item;
|
|
while (std::getline(ss, item, delim)) {
|
|
elems.push_back(item);
|
|
}
|
|
return elems;
|
|
}
|
|
|
|
static inline std::string replaceAll(const std::string& str, const std::string& replaceWhat, const std::string& replaceWith) {
|
|
if (replaceWhat == replaceWith)
|
|
return str;
|
|
std::string result = str;
|
|
std::size_t foundAt = std::string::npos;
|
|
while ((foundAt = result.find(replaceWhat)) != std::string::npos) {
|
|
result.replace(foundAt, replaceWhat.length(), replaceWith);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static inline std::string stripAllWhiteSpaces(const std::string& str) {
|
|
std::string result = replaceAll(str, " ", "");
|
|
result = replaceAll(result, "\n", "");
|
|
result = replaceAll(result, "\r", "");
|
|
result = replaceAll(result, "\t", "");
|
|
return result;
|
|
}
|
|
|
|
static inline void tolower(std::string& str) {
|
|
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
|
}
|
|
};
|
|
|
|
//!
|
|
//! Operating System utilities class used internally. You should not use it.
|
|
//!
|
|
class OSUtils : private internal::StaticClass {
|
|
public:
|
|
#if _ELPP_OS_WINDOWS
|
|
static const char* getWindowsEnvironmentVariable(const char* variableName) {
|
|
const DWORD bufferLen = 50;
|
|
static char buffer[bufferLen];
|
|
if (GetEnvironmentVariableA(variableName, buffer, bufferLen)) {
|
|
return buffer;
|
|
}
|
|
return NULL;
|
|
}
|
|
#endif // _ELPP_OS_WINDOWS
|
|
#if _ELPP_NDK
|
|
static std::string getProperty(const char* prop) {
|
|
char propVal[PROP_VALUE_MAX + 1];
|
|
__system_property_get(prop, propVal);
|
|
return std::string(propVal);
|
|
}
|
|
|
|
static std::string getDeviceName(void) {
|
|
std::stringstream ss;
|
|
std::string manufacturer = getProperty("ro.product.manufacturer");
|
|
std::string model = getProperty("ro.product.model");
|
|
if (manufacturer.empty() && model.empty()) {
|
|
return std::string();
|
|
}
|
|
ss << manufacturer << " " << model;
|
|
return ss.str();
|
|
}
|
|
#endif // _ELPP_NDK
|
|
// Runs command on terminal and returns the output.
|
|
// This is applicable only on linux and mac, for all other OS, an empty string is returned.
|
|
static const std::string getBashOutput(const char* command_) {
|
|
if (command_ == NULL) {
|
|
return std::string();
|
|
}
|
|
#if _ELPP_OS_UNIX && !_ELPP_NDK
|
|
FILE* proc = NULL;
|
|
if ((proc = popen(command_, "r")) == NULL) {
|
|
std::cerr << "\nUnable to run command [" << command_ << "]" << std::endl;
|
|
return std::string();
|
|
}
|
|
char hBuff[4096];
|
|
if (fgets(hBuff, sizeof(hBuff), proc) != NULL) {
|
|
pclose(proc);
|
|
if (hBuff[strlen(hBuff) - 1] == '\n') {
|
|
hBuff[strlen(hBuff) - 1] = '\0';
|
|
}
|
|
return std::string(hBuff);
|
|
}
|
|
return std::string();
|
|
#else
|
|
return std::string();
|
|
#endif // _ELPP_OS_UNIX
|
|
}
|
|
|
|
static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal, const char* alternativeBashCommand = NULL) {
|
|
#if _ELPP_OS_UNIX
|
|
const char* val = getenv(variableName);
|
|
#elif _ELPP_OS_WINDOWS
|
|
const char* val = getWindowsEnvironmentVariable(variableName);
|
|
#endif // _ELPP_OS_UNIX
|
|
if ((val == NULL) || ((strcmp(val, "") == 0))) {
|
|
#if _ELPP_OS_UNIX
|
|
// Try harder on unix-based systems
|
|
std::string valBash = internal::utilities::OSUtils::getBashOutput(alternativeBashCommand);
|
|
if (valBash.empty()) {
|
|
return std::string(defaultVal);
|
|
} else {
|
|
return valBash;
|
|
}
|
|
#elif _ELPP_OS_WINDOWS
|
|
return std::string(defaultVal);
|
|
#endif // _ELPP_OS_WINDOWS
|
|
}
|
|
return std::string(val);
|
|
}
|
|
|
|
// Gets current username.
|
|
static const std::string currentUser(void) {
|
|
#if _ELPP_OS_UNIX && !_ELPP_NDK
|
|
return getEnvironmentVariable("USER", "user", "whoami");
|
|
#elif _ELPP_OS_WINDOWS
|
|
return getEnvironmentVariable("USERNAME", "user");
|
|
#elif _ELPP_NDK
|
|
return std::string("android");
|
|
#else
|
|
return std::string();
|
|
#endif // _ELPP_OS_UNIX
|
|
}
|
|
|
|
// Gets current host name or computer name.
|
|
static const std::string currentHost(void) {
|
|
#if _ELPP_OS_UNIX && !_ELPP_NDK
|
|
return getEnvironmentVariable("HOSTNAME", "unknown-host", "hostname");
|
|
#elif _ELPP_OS_WINDOWS
|
|
return getEnvironmentVariable("COMPUTERNAME", "unknown-host");
|
|
#elif _ELPP_NDK
|
|
return getDeviceName();
|
|
#else
|
|
return std::string();
|
|
#endif // _ELPP_OS_UNIX
|
|
}
|
|
|
|
// Determines whether or not provided path_ exist in current file system
|
|
static inline bool pathExists(const char* path_) {
|
|
if (path_ == NULL) {
|
|
return false;
|
|
}
|
|
#if _ELPP_OS_UNIX
|
|
struct stat st;
|
|
return (stat(path_, &st) == 0);
|
|
#elif _ELPP_OS_WINDOWS
|
|
DWORD fileType = GetFileAttributesA(path_);
|
|
if (fileType == INVALID_FILE_ATTRIBUTES) {
|
|
return false;
|
|
}
|
|
return (fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true;
|
|
#endif // _ELPP_OS_UNIX
|
|
}
|
|
|
|
// Creates path as specified
|
|
static bool createPath(const std::string& path_) {
|
|
if (path_.empty()) {
|
|
return false;
|
|
}
|
|
if (internal::utilities::OSUtils::pathExists(path_.c_str())) {
|
|
return true;
|
|
}
|
|
#if _ELPP_OS_UNIX
|
|
const char* pathDelim_ = "/";
|
|
#elif _ELPP_OS_WINDOWS
|
|
char pathDelim_[] = "\\";
|
|
#endif // _ELPP_OS_UNIX
|
|
int status = -1;
|
|
|
|
char* currPath_ = const_cast<char*>(path_.c_str());
|
|
std::string buildingPath_ = std::string();
|
|
#if _ELPP_OS_UNIX
|
|
if (path_[0] == '/') {
|
|
buildingPath_ = "/";
|
|
}
|
|
currPath_ = STRTOK(currPath_, pathDelim_, 0);
|
|
#elif _ELPP_OS_WINDOWS
|
|
// Use secure functions API
|
|
char* nextTok_;
|
|
currPath_ = STRTOK(currPath_, pathDelim_, &nextTok_);
|
|
#endif // _ELPP_OS_UNIX
|
|
while (currPath_ != NULL) {
|
|
buildingPath_.append(currPath_);
|
|
buildingPath_.append(pathDelim_);
|
|
#if _ELPP_OS_UNIX
|
|
status = mkdir(buildingPath_.c_str(), _LOG_PERMS);
|
|
currPath_ = STRTOK(NULL, pathDelim_, 0);
|
|
#elif _ELPP_OS_WINDOWS
|
|
status = _mkdir(buildingPath_.c_str());
|
|
currPath_ = STRTOK(NULL, pathDelim_, &nextTok_);
|
|
#endif // _ELPP_OS_UNIX
|
|
}
|
|
if (status == -1) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static std::string getPathFromFilename(const std::string& fullPath_, internal::Constants* constants_) {
|
|
if (fullPath_ == "" || fullPath_.find(constants_->PATH_SLASH) == std::string::npos) {
|
|
return fullPath_;
|
|
}
|
|
std::size_t lastSlashAt = fullPath_.find_last_of(constants_->PATH_SLASH);
|
|
if (lastSlashAt == 0) {
|
|
return constants_->PATH_SLASH;
|
|
}
|
|
return fullPath_.substr(0, lastSlashAt + 1);
|
|
}
|
|
}; // class OSUtils
|
|
|
|
//!
|
|
//! Contains static functions related to log manipulation used internally. You should not use it.
|
|
//!
|
|
class LogManipulator : private internal::StaticClass {
|
|
public:
|
|
// Updates the formatSpecifier_ for currentFormat_ to value_ provided
|
|
static void updateFormatValue(const std::string& formatSpecifier_,
|
|
const std::string& value_, std::string& currentFormat_,
|
|
internal::Constants* constants_) {
|
|
std::size_t foundAt = std::string::npos;
|
|
while ((foundAt = currentFormat_.find(formatSpecifier_, foundAt + 1)) != std::string::npos){
|
|
if (currentFormat_[foundAt > 0 ? foundAt - 1 : 0] == constants_->FORMAT_SPECIFIER_ESCAPE_CHAR) {
|
|
currentFormat_.erase(foundAt > 0 ? foundAt - 1 : 0, 1);
|
|
++foundAt;
|
|
} else {
|
|
currentFormat_ = currentFormat_.replace(foundAt, formatSpecifier_.size(), value_);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}; // class LogManipulator
|
|
|
|
//!
|
|
//! Contains utility functions related to date/time used internally. You should not use it.
|
|
//!
|
|
class DateUtils : private internal::StaticClass {
|
|
public:
|
|
#if _ELPP_OS_WINDOWS
|
|
static void gettimeofday(struct timeval *tv) {
|
|
if (tv != NULL) {
|
|
# if defined(_MSC_EXTENSIONS)
|
|
const unsigned __int64 delta_ = 11644473600000000Ui64;
|
|
# else
|
|
const unsigned __int64 delta_ = 11644473600000000ULL;
|
|
# endif // defined(_MSC_EXTENSIONS)
|
|
const double secOffSet = 0.000001;
|
|
const unsigned long usecOffSet = 1000000;
|
|
FILETIME fileTime_;
|
|
GetSystemTimeAsFileTime(&fileTime_);
|
|
unsigned __int64 present_ = 0;
|
|
present_ |= fileTime_.dwHighDateTime;
|
|
present_ = present_ << 32;
|
|
present_ |= fileTime_.dwLowDateTime;
|
|
present_ /= 10; // mic-sec
|
|
// Subtract the difference
|
|
present_ -= delta_;
|
|
tv->tv_sec = static_cast<long>(present_ * secOffSet);
|
|
tv->tv_usec = static_cast<long>(present_ % usecOffSet);
|
|
}
|
|
}
|
|
#endif // _ELPP_OS_WINDOWS
|
|
|
|
// Gets current date and time with milliseconds.
|
|
static std::string getDateTime(const std::string& bufferFormat_, unsigned int type_, internal::Constants* constants_, std::size_t milliSecondOffset_ = 1000) {
|
|
long milliSeconds = 0;
|
|
const int kDateBuffSize_ = 30;
|
|
char dateBuffer_[kDateBuffSize_] = "";
|
|
char dateBufferOut_[kDateBuffSize_] = "";
|
|
#if _ELPP_OS_UNIX
|
|
bool hasTime_ = ((type_ & constants_->kDateTime) || (type_ & constants_->kTimeOnly));
|
|
timeval currTime;
|
|
gettimeofday(&currTime, NULL);
|
|
if (hasTime_) {
|
|
milliSeconds = currTime.tv_usec / milliSecondOffset_ ;
|
|
}
|
|
struct tm * timeInfo = localtime(&currTime.tv_sec);
|
|
strftime(dateBuffer_, sizeof(dateBuffer_), bufferFormat_.c_str(), timeInfo);
|
|
if (hasTime_) {
|
|
SPRINTF(dateBufferOut_, "%s.%03ld", dateBuffer_, milliSeconds);
|
|
} else {
|
|
SPRINTF(dateBufferOut_, "%s", dateBuffer_);
|
|
}
|
|
#elif _ELPP_OS_WINDOWS
|
|
const char* kTimeFormatLocal_ = "HH':'mm':'ss";
|
|
const char* kDateFormatLocal_ = "dd/MM/yyyy";
|
|
if ((type_ & constants_->kDateTime) || (type_ & constants_->kDateOnly)) {
|
|
if (GetDateFormatA(LOCALE_USER_DEFAULT, 0, 0, kDateFormatLocal_, dateBuffer_, kDateBuffSize_) != 0) {
|
|
SPRINTF(dateBufferOut_, "%s", dateBuffer_);
|
|
}
|
|
}
|
|
if ((type_ & constants_->kDateTime) || (type_ & constants_->kTimeOnly)) {
|
|
if (GetTimeFormatA(LOCALE_USER_DEFAULT, 0, 0, kTimeFormatLocal_, dateBuffer_, kDateBuffSize_) != 0) {
|
|
milliSeconds = static_cast<long>(GetTickCount()) % milliSecondOffset_;
|
|
if (type_ & constants_->kDateTime) {
|
|
SPRINTF(dateBufferOut_, "%s %s.%03ld", dateBufferOut_, dateBuffer_, milliSeconds);
|
|
} else {
|
|
SPRINTF(dateBufferOut_, "%s.%03ld", dateBuffer_, milliSeconds);
|
|
}
|
|
}
|
|
}
|
|
#endif // _ELPP_OS_UNIX
|
|
return std::string(dateBufferOut_);
|
|
}
|
|
|
|
static std::string formatMilliSeconds(double milliSeconds_) {
|
|
double result = milliSeconds_;
|
|
std::string unit = "ms";
|
|
std::stringstream stream_;
|
|
if (result > 1000.0f) {
|
|
result /= 1000; unit = "seconds";
|
|
if (result > 60.0f) {
|
|
result /= 60; unit = "minutes";
|
|
if (result > 60.0f) {
|
|
result /= 60; unit = "hours";
|
|
if (result > 24.0f) {
|
|
result /= 24; unit = "days";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
stream_ << result << " " << unit;
|
|
return stream_.str();
|
|
}
|
|
|
|
static inline double getTimeDifference(const timeval& endTime_, const timeval& startTime_) {
|
|
return static_cast<double>((((endTime_.tv_sec - startTime_.tv_sec) * 1000000) + (endTime_.tv_usec - startTime_.tv_usec)) / 1000);
|
|
}
|
|
}; // class DateUtils
|
|
} // namespace utilities
|
|
|
|
//!
|
|
//! Internal repository base to manage memory on heap. Used internally, you should not use it.
|
|
//!
|
|
template<class Class, class Predicate>
|
|
class Registry {
|
|
public:
|
|
Registry(void) {
|
|
}
|
|
|
|
virtual ~Registry(void) {
|
|
unregisterAll();
|
|
}
|
|
|
|
Registry(const Registry& other_) {
|
|
if (this != &other_) {
|
|
unregisterAll();
|
|
for (std::size_t i = 0; i < other_.list_.size(); ++i) {
|
|
Class* curr_ = other_.list_.at(i);
|
|
if (curr_) {
|
|
list_.push_back(new Class(*curr_));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Registry& operator=(const Registry& other_) {
|
|
if (this == &other_) {
|
|
return *this;
|
|
}
|
|
unregisterAll();
|
|
for (std::size_t i = 0; i < other_.list_.size(); ++i) {
|
|
Class* curr_ = other_.list_.at(i);
|
|
if (curr_) {
|
|
list_.push_back(new Class(*curr_));
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
inline void registerNew(Class* c_) {
|
|
list_.push_back(c_);
|
|
}
|
|
|
|
bool operator!=(const Registry<Class, Predicate>& other_) {
|
|
if (list_.size() != other_.list_.size()) {
|
|
return true;
|
|
}
|
|
for (std::size_t i = 0; i < list_.size(); ++i) {
|
|
if (list_.at(i) != other_.list_.at(i)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool operator==(const Registry<Class, Predicate>& other_) {
|
|
if (list_.size() != other_.list_.size()) {
|
|
return false;
|
|
}
|
|
for (std::size_t i = 0; i < list_.size(); ++i) {
|
|
if (list_.at(i) != other_.list_.at(i)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template<typename T>
|
|
Class* get(const T& t_) {
|
|
Iterator iter = std::find_if(list_.begin(), list_.end(), Predicate(t_));
|
|
if (iter != list_.end() && *iter != NULL) {
|
|
return *iter;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
template<typename T, typename T2>
|
|
Class* get(const T& t_, const T2& t2_) {
|
|
Iterator iter = std::find_if(list_.begin(), list_.end(), Predicate(t_, t2_));
|
|
if (iter != list_.end() && *iter != NULL) {
|
|
return *iter;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
template<typename T>
|
|
inline bool exist(const T& t_) {
|
|
return (get(t_) != NULL);
|
|
}
|
|
|
|
inline std::size_t count(void) const {
|
|
return list_.size();
|
|
}
|
|
|
|
inline bool empty(void) const {
|
|
return list_.empty();
|
|
}
|
|
|
|
Class* at(std::size_t i) const {
|
|
return list_.at(i);
|
|
}
|
|
|
|
protected:
|
|
typedef typename std::vector<Class*>::iterator Iterator;
|
|
|
|
inline void unregisterAll(void) {
|
|
if (!empty()) {
|
|
std::for_each(list_.begin(), list_.end(), std::bind1st(std::mem_fun(&Registry::release), this));
|
|
list_.clear();
|
|
}
|
|
}
|
|
|
|
inline void unregister(Class*& c_) {
|
|
if (c_) {
|
|
Iterator iter = list_.begin();
|
|
for (; iter != list_.end(); ++iter) {
|
|
if (c_ == *iter) {
|
|
break;
|
|
}
|
|
}
|
|
if (iter != list_.end() && *iter != NULL) {
|
|
list_.erase(iter);
|
|
internal::utilities::safeDelete(c_);
|
|
}
|
|
}
|
|
}
|
|
|
|
inline std::vector<Class*>& list(void) {
|
|
return list_;
|
|
}
|
|
private:
|
|
std::vector<Class*> list_;
|
|
|
|
inline void release(Class* c_) {
|
|
internal::utilities::safeDelete(c_);
|
|
}
|
|
}; // class Registry
|
|
|
|
//!
|
|
//! Scoped pointer used internally. You should not use it.
|
|
//!
|
|
template <typename T>
|
|
class ScopedPointer {
|
|
public:
|
|
explicit ScopedPointer(T* ptr_ = 0) :
|
|
ptr_(ptr_), referenceCounter_(0) {
|
|
referenceCounter_ = new ReferenceCounter();
|
|
referenceCounter_->increment();
|
|
}
|
|
|
|
ScopedPointer(const ScopedPointer<T>& scopedPointer_) :
|
|
ptr_(scopedPointer_.ptr_), referenceCounter_(scopedPointer_.referenceCounter_) {
|
|
referenceCounter_->increment();
|
|
}
|
|
|
|
ScopedPointer<T>& operator=(const ScopedPointer<T>& other_) {
|
|
if (this != &other_)
|
|
{
|
|
validate();
|
|
ptr_ = other_.ptr_;
|
|
referenceCounter_ = other_.referenceCounter_;
|
|
referenceCounter_->increment();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
virtual ~ScopedPointer(void) {
|
|
validate();
|
|
}
|
|
|
|
T& operator*(void) {
|
|
return *ptr_;
|
|
}
|
|
|
|
T* operator->(void) {
|
|
return ptr_;
|
|
}
|
|
|
|
T* pointer(void) {
|
|
return ptr_;
|
|
}
|
|
|
|
class ReferenceCounter {
|
|
public:
|
|
ReferenceCounter(void) : count_(0) {
|
|
}
|
|
|
|
ReferenceCounter& operator=(const ReferenceCounter& other_) {
|
|
if (this != &other_) {
|
|
count_ = other_.count_;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void increment(void) {
|
|
++count_;
|
|
}
|
|
|
|
int decrement(void) {
|
|
return this == NULL ? 0 : --count_;
|
|
}
|
|
|
|
private:
|
|
int count_;
|
|
};
|
|
private:
|
|
T* ptr_;
|
|
ReferenceCounter* referenceCounter_;
|
|
|
|
void validate(void) {
|
|
if(referenceCounter_->decrement() == 0) {
|
|
internal::utilities::safeDelete(ptr_, false);
|
|
internal::utilities::safeDelete(referenceCounter_, false);
|
|
}
|
|
}
|
|
};
|
|
|
|
//!
|
|
//! Class that represents single configuration.
|
|
//!
|
|
//! Single configuration has a level (easyloggingpp::Level), type (easyloggingpp::ConfigurationType)
|
|
//! and std::string based value. This value is later parsed into more appropriate data type depending on
|
|
//! type
|
|
//!
|
|
class Configuration {
|
|
public:
|
|
//!
|
|
//! Full constructor used to set initial value of configuration
|
|
//! \param level_
|
|
//! \param type_
|
|
//! \param value_
|
|
//!
|
|
Configuration(unsigned int level_, unsigned int type_, const std::string& value_) :
|
|
level_(level_),
|
|
type_(type_),
|
|
value_(value_) {
|
|
}
|
|
|
|
//!
|
|
//! \return Level of current configuration
|
|
//!
|
|
unsigned int level(void) const {
|
|
return level_;
|
|
}
|
|
|
|
//!
|
|
//! \return Configuration type of current configuration
|
|
//!
|
|
unsigned int type(void) const {
|
|
return type_;
|
|
}
|
|
|
|
//!
|
|
//! \return String based configuration value
|
|
//!
|
|
std::string value(void) const {
|
|
return value_;
|
|
}
|
|
|
|
//!
|
|
//! 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
|
|
//!
|
|
void setValue(const std::string& value_) {
|
|
this->value_ = value_;
|
|
}
|
|
|
|
//!
|
|
//! Predicate used to find configuration from configuration repository. This is used internally.
|
|
//!
|
|
class Predicate {
|
|
public:
|
|
Predicate(unsigned int level_, unsigned int type_) :
|
|
level_(level_),
|
|
type_(type_) {
|
|
}
|
|
|
|
bool operator()(const Configuration* conf_) {
|
|
return ((conf_ != NULL) && (conf_->level() == level_) && (conf_->type() == type_));
|
|
}
|
|
|
|
private:
|
|
unsigned int level_;
|
|
unsigned int type_;
|
|
};
|
|
private:
|
|
unsigned int level_;
|
|
unsigned int type_;
|
|
std::string value_;
|
|
};
|
|
|
|
} // namespace internal
|
|
|
|
//!
|
|
//! Configuration repository that represents configuration for single logger
|
|
//!
|
|
class Configurations : public internal::Registry<internal::Configuration, internal::Configuration::Predicate> {
|
|
public:
|
|
//!
|
|
//! Default constructor
|
|
//!
|
|
Configurations(void) :
|
|
isFromFile_(false) {
|
|
}
|
|
|
|
//!
|
|
//! Constructor used to set configurations via configuration 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.
|
|
//!
|
|
Configurations(const std::string& configurationFile_, Configurations* base_ = NULL) :
|
|
configurationFile_(configurationFile_),
|
|
isFromFile_(false) {
|
|
parseFromFile(configurationFile_, base_);
|
|
}
|
|
|
|
//!
|
|
//! Set configurations based on other configurations
|
|
//! \param base_ Pointer to existing configurations.
|
|
//!
|
|
inline void setFromBase(Configurations* base_) {
|
|
if (base_ == NULL || base_ == this) return;
|
|
std::for_each(base_->list().begin(), base_->list().end(), std::bind1st(std::mem_fun(&Configurations::set), this));
|
|
}
|
|
|
|
//!
|
|
//! Checks to see whether specified configuration type exist in this repository
|
|
//! \param configurationType_ Configuration type to check against. Use easyloggingpp::ConfigurationType to prevent confusions
|
|
//! \return True if exist, false otherwise
|
|
//!
|
|
inline bool contains(unsigned int configurationType_) {
|
|
ELPP_FOR_EACH_CONFIGURATION(i, ConfigurationType::kMinValid,
|
|
if (get(i, configurationType_) != NULL) {
|
|
return true;
|
|
}
|
|
);
|
|
return false;
|
|
}
|
|
|
|
//!
|
|
//! Sets configuration for specified level_ and configurationType_. If configuration already exists for specified
|
|
//! level and configuration type, value just gets updated.
|
|
//! Remember, it is not recommended to set skip_ELPPALL_Check to false unless you know exactly what you are doing
|
|
//! \param level_ Level to set configuration for. Use easyloggingpp::Level to prevent confusion
|
|
//! \param configurationType_ Configuration type to set configuration against. Use easyloggingpp::ConfigurationType to prevent confusion
|
|
//! \param value_ String based configuration value
|
|
//! \param skipLEVEL_ALL Determines whether to skip 'easyloggingpp::Level::All'. This is skipped by default because setting
|
|
//! 'All' may override configuration. Be careful with this.
|
|
//!
|
|
void set(unsigned int level_, unsigned int configurationType_, const std::string& value_, bool skipLEVEL_ALL = false) {
|
|
if (value_ == "") return; // ignore empty values
|
|
if ((configurationType_ == ConfigurationType::PerformanceTracking && level_ != Level::All) ||
|
|
(configurationType_ == ConfigurationType::MillisecondsWidth && level_ != Level::All)) {
|
|
// configurationType_ not applicable for this level_
|
|
return;
|
|
}
|
|
internal::Configuration* conf_ = get(level_, configurationType_);
|
|
if (conf_ == NULL) {
|
|
registerNew(new internal::Configuration(level_, configurationType_, value_));
|
|
} else {
|
|
// Configuration already there, just update the value!
|
|
conf_->setValue(value_);
|
|
}
|
|
if (!skipLEVEL_ALL && level_ == Level::All) {
|
|
setAll(configurationType_, value_, true);
|
|
}
|
|
}
|
|
|
|
//!
|
|
//! Parse configuration from file.
|
|
//! \param configurationFile_
|
|
//! \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_FIRST_ELPP_ASSERTION' to make sure you
|
|
//! do not proceed without successful parse.
|
|
//!
|
|
bool parseFromFile(const std::string& configurationFile_, Configurations* base_ = NULL) {
|
|
setFromBase(base_);
|
|
std::ifstream fileStream_(configurationFile_.c_str(), std::ifstream::in);
|
|
__EASYLOGGINGPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file [" << configurationFile_ << "] for parsing.");
|
|
bool parsedSuccessfully_ = false;
|
|
std::string line = std::string();
|
|
unsigned int currLevel = 0;
|
|
while (fileStream_.good()) {
|
|
std::getline(fileStream_, line);
|
|
parsedSuccessfully_ = Parser::parseLine(line, currLevel, this);
|
|
__EASYLOGGINGPP_ASSERT(parsedSuccessfully_, "Unable to parse configuration line: " << line);
|
|
}
|
|
isFromFile_ = true;
|
|
return parsedSuccessfully_;
|
|
}
|
|
|
|
//!
|
|
//! Parse configurations from configuration string. This configuration string has same syntax as configuration file contents. Make
|
|
//! sure all the necessary new line characters are provided.
|
|
//! \param configurationsString
|
|
//! \return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRST_ELPP_ASSERTION' to make sure you
|
|
//! do not proceed without successful parse.
|
|
//!
|
|
bool parseFromText(const std::string& configurationsString) {
|
|
bool parsedSuccessfully_ = false;
|
|
std::string line = std::string();
|
|
unsigned int currLevel = 0;
|
|
std::vector<std::string> lines;
|
|
internal::utilities::StringUtils::split(configurationsString, '\n', lines);
|
|
for (std::size_t i = 0; i < lines.size(); ++i) {
|
|
line = lines.at(i);
|
|
parsedSuccessfully_ = Parser::parseLine(line, currLevel, this);
|
|
__EASYLOGGINGPP_ASSERT(parsedSuccessfully_, "Unable to parse configuration line: " << line);
|
|
}
|
|
isFromFile_ = false;
|
|
return parsedSuccessfully_;
|
|
}
|
|
|
|
//!
|
|
//! Sets configurations to default configurations set by easylogging++.
|
|
//! NOTE: This has nothing to do with Loggers::setDefaultConfigurations - thats completely different thing. This is
|
|
//! library's own default format.
|
|
//!
|
|
void setToDefault(void) {
|
|
setAll(ConfigurationType::Enabled, "true");
|
|
#if _ELPP_OS_UNIX
|
|
# if _ELPP_NDK
|
|
setAll(ConfigurationType::Filename, "/data/local/tmp/myeasylog.txt");
|
|
# else
|
|
setAll(ConfigurationType::Filename, "/tmp/logs/myeasylog.log");
|
|
# endif // _ELPP_NDK
|
|
#elif _ELPP_OS_WINDOWS
|
|
setAll(ConfigurationType::Filename, "logs\\myeasylog.log");
|
|
#endif // _ELPP_OS_UNIX
|
|
setAll(ConfigurationType::ToFile, "true");
|
|
setAll(ConfigurationType::ToStandardOutput, "true");
|
|
setAll(ConfigurationType::MillisecondsWidth, "3");
|
|
setAll(ConfigurationType::PerformanceTracking, "false");
|
|
setAll(easyloggingpp::ConfigurationType::RollOutSize, "0");
|
|
setAll(ConfigurationType::Format, "%datetime %level [%logger] %log");
|
|
set(Level::Debug, ConfigurationType::Format, "%datetime %level [%logger] [%user@%host] [%func] [%loc] %log");
|
|
// INFO and WARNING are set to default by Level::ALL
|
|
set(Level::Error, ConfigurationType::Format, "%datetime %level [%logger] %log");
|
|
set(Level::Fatal, ConfigurationType::Format, "%datetime %level [%logger] %log");
|
|
set(Level::Verbose, ConfigurationType::Format, "%datetime %level-%vlevel [%logger] %log");
|
|
set(Level::QA, ConfigurationType::Format, "%datetime %level [%logger] %log");
|
|
set(Level::Trace, ConfigurationType::Format, "%datetime %level [%logger] [%func] [%loc] %log");
|
|
}
|
|
|
|
//!
|
|
//! Sets configuration for all levels.
|
|
//! Remember, it is not recommended to set skip_ELPPALL_Check to false unless you know exactly what you are doing
|
|
//! \param configurationType_
|
|
//! \param value_
|
|
//! \param skipLEVEL_ALL Determines whether to skip 'easyloggingpp::Level::All'. This is skipped by default because setting
|
|
//! 'All' may override configuration. Be careful with this.
|
|
//!
|
|
inline void setAll(unsigned int configurationType_, const std::string& value_, bool skipLEVEL_ALL = false) {
|
|
if (!skipLEVEL_ALL) {
|
|
set(Level::All, configurationType_, value_);
|
|
}
|
|
ELPP_FOR_EACH_LEVEL(i, Level::Debug,
|
|
set(i, configurationType_, value_);
|
|
);
|
|
}
|
|
|
|
//!
|
|
//! Clears the repository.
|
|
//! All the configurations are maintained on heap for faster access so if you are sure you will not use this
|
|
//! repository and you have configured all the loggers against this or you have used this configuration for all the
|
|
//! purposes you need it for, you may retain memory by using this method. If you do not do this, internal memory management
|
|
//! does it itself at the end of application execution.
|
|
//!
|
|
inline void clear(void) {
|
|
unregisterAll();
|
|
}
|
|
|
|
//!
|
|
//! \return Returns configuration file used in parsing this configurations. If this repository was set manually or by text
|
|
//! this returns empty string.
|
|
//!
|
|
std::string configurationFile(void) const {
|
|
return configurationFile_;
|
|
}
|
|
|
|
//!
|
|
//! Parser used internally to parse configurations from file or text. You should not need this unless you are working on
|
|
//! some tool for EasyLogging++
|
|
//!
|
|
class Parser : private internal::StaticClass {
|
|
public:
|
|
static void ignoreComments(std::string& line) {
|
|
std::size_t foundAt = 0;
|
|
std::size_t quotesStart = line.find("\"");
|
|
std::size_t quotesEnd = std::string::npos;
|
|
if (quotesStart != std::string::npos) {
|
|
quotesEnd = line.find("\"", quotesStart + 1);
|
|
}
|
|
if ((foundAt = line.find("//")) != std::string::npos) {
|
|
if (foundAt < quotesEnd) {
|
|
foundAt = line.find("//", quotesEnd + 1);
|
|
}
|
|
line = line.substr(0, foundAt);
|
|
}
|
|
}
|
|
|
|
static inline bool isLevel(const std::string& line) {
|
|
return internal::utilities::StringUtils::startsWith(line, "*");
|
|
}
|
|
|
|
static inline bool isConfig(const std::string& line) {
|
|
std::size_t assignment = line.find('=');
|
|
return line != "" &&
|
|
(line[0] >= 65 || line[0] <= 90 || line[0] >= 97 || line[0] <= 122) &&
|
|
(assignment != std::string::npos) &&
|
|
(line.size() > assignment);
|
|
}
|
|
|
|
static inline bool isComment(const std::string& line) {
|
|
return internal::utilities::StringUtils::startsWith(line, "//");
|
|
}
|
|
|
|
static bool parseLine(std::string& line, unsigned int& currLevel, Configurations* conf) {
|
|
std::string currLevelStr = std::string();
|
|
unsigned int currConfig = 0;
|
|
std::string currConfigStr = std::string();
|
|
std::string currValue = std::string();
|
|
line = internal::utilities::StringUtils::trim(line);
|
|
if (isComment(line)) return true;
|
|
ignoreComments(line);
|
|
if (line == "") {
|
|
// Comment ignored
|
|
return true;
|
|
}
|
|
if (isLevel(line)) {
|
|
currLevelStr = internal::utilities::StringUtils::stripAllWhiteSpaces(line);
|
|
if (currLevelStr.size() <= 2) {
|
|
return true;
|
|
}
|
|
currLevelStr = currLevelStr.substr(1, currLevelStr.size() - 2);
|
|
internal::utilities::StringUtils::tolower(currLevelStr);
|
|
currLevel = Level::convertFromString(currLevelStr);
|
|
return true;
|
|
}
|
|
if (isConfig(line)) {
|
|
std::size_t assignment = line.find('=');
|
|
currConfigStr = line.substr(0, assignment);
|
|
currConfigStr = internal::utilities::StringUtils::stripAllWhiteSpaces(currConfigStr);
|
|
internal::utilities::StringUtils::tolower(currConfigStr);
|
|
currConfig = ConfigurationType::convertFromString(currConfigStr);
|
|
currValue = line.substr(assignment + 1);
|
|
currValue = internal::utilities::StringUtils::trim(currValue);
|
|
std::size_t quotesStart = currValue.find("\"", 0);
|
|
std::size_t quotesEnd = std::string::npos;
|
|
if (quotesStart != std::string::npos) {
|
|
quotesEnd = currValue.find("\"", quotesStart + 1);
|
|
}
|
|
if (quotesStart != std::string::npos && quotesEnd != std::string::npos) {
|
|
// Quote provided - check and strip if valid
|
|
__EASYLOGGINGPP_ASSERT((quotesStart < quotesEnd), "Configuration error - No ending quote found in [" << currConfigStr << "]");
|
|
__EASYLOGGINGPP_ASSERT((quotesStart + 1 != quotesEnd), "Empty configuration value for [" << currConfigStr << "]");
|
|
if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) {
|
|
// Explicit check in case if assertion is disabled
|
|
currValue = currValue.substr(quotesStart + 1, quotesEnd - 1);
|
|
}
|
|
}
|
|
}
|
|
__EASYLOGGINGPP_ASSERT(currLevel != Level::Unknown, "Unrecognized severity level [" << currLevelStr << "]");
|
|
__EASYLOGGINGPP_ASSERT(currConfig != ConfigurationType::Unknown, "Unrecognized configuration [" << currConfigStr << "]");
|
|
if (currLevel == Level::Unknown || currConfig == ConfigurationType::Unknown) {
|
|
return false; // unrecognizable level or config
|
|
}
|
|
conf->set(currLevel, currConfig, currValue);
|
|
return true;
|
|
}
|
|
}; // class Parser
|
|
private:
|
|
std::string configurationFile_;
|
|
bool isFromFile_;
|
|
internal::threading::Mutex mutex_;
|
|
|
|
inline void set(internal::Configuration* conf_) {
|
|
if (conf_ == NULL) return;
|
|
set(conf_->level(), conf_->type(), conf_->value());
|
|
}
|
|
}; // class Configurations
|
|
|
|
class Loggers; // fwd declaration
|
|
|
|
namespace internal {
|
|
|
|
class RegisteredLoggers; // fwd declaration
|
|
class Writer; // fwd declaration
|
|
|
|
//!
|
|
//! Configuration map used internally for faster access of configuration while executing.
|
|
//!
|
|
template <typename T>
|
|
class ConfigurationMap {
|
|
public:
|
|
typedef typename std::pair<unsigned int, T> Entry;
|
|
|
|
ConfigurationMap(void) {
|
|
table = new Entry*[Level::kMaxValid + 1];
|
|
for (unsigned int i = 0; i < (Level::kMaxValid + 1); ++i) {
|
|
table[i] = NULL;
|
|
}
|
|
count = 0;
|
|
}
|
|
|
|
const T& get(unsigned int level_, bool forceGetLevel = false) {
|
|
if (forceGetLevel || table[level_] != NULL) {
|
|
if (table[level_] == NULL) {
|
|
return default_;
|
|
}
|
|
return table[level_]->second;
|
|
} else if (table[Level::All] != NULL) {
|
|
return table[Level::All]->second;
|
|
}
|
|
return default_;
|
|
}
|
|
|
|
void set(unsigned int level_, const T& value) {
|
|
// Unset any existing value for this level
|
|
unset(level_);
|
|
table[level_] = new Entry(level_, value);
|
|
++count;
|
|
}
|
|
|
|
void unset(unsigned int level_) {
|
|
if (table[level_] != NULL) {
|
|
internal::utilities::safeDelete(table[level_]);
|
|
if (count > 0)
|
|
--count;
|
|
}
|
|
}
|
|
|
|
inline bool exist(unsigned int level_) const {
|
|
return table[level_] != NULL;
|
|
}
|
|
|
|
inline bool exist(unsigned int level_, const T& value) {
|
|
return get(level_, true) == value;
|
|
}
|
|
|
|
void clear(void) {
|
|
for (unsigned int i = 0; i < (Level::kMaxValid + 1); ++i) {
|
|
internal::utilities::safeDelete(table[i]);
|
|
}
|
|
delete[] table;
|
|
count = 0;
|
|
}
|
|
|
|
virtual ~ConfigurationMap(void) {
|
|
clear();
|
|
}
|
|
|
|
inline void setDefault(const T& default_) {
|
|
this->default_ = default_;
|
|
}
|
|
|
|
inline std::size_t size(void) const {
|
|
return count;
|
|
}
|
|
private:
|
|
Entry** table;
|
|
std::size_t count;
|
|
T default_;
|
|
};
|
|
|
|
//!
|
|
//! Configurations used internally that defines data type of each configuration from easyloggingpp::ConfigurationType
|
|
//!
|
|
class TypedConfigurations {
|
|
public:
|
|
TypedConfigurations(const Configurations& configurations, internal::Constants* constants_) {
|
|
this->constants_ = constants_;
|
|
this->configurations_ = configurations;
|
|
enabledMap_.setDefault(false);
|
|
toFileMap_.setDefault(false);
|
|
toStandardOutputMap_.setDefault(false);
|
|
filenameMap_.setDefault("");
|
|
logFormatMap_.setDefault("");
|
|
dateFormatMap_.setDefault("");
|
|
dateFormatSpecifierMap_.setDefault("");
|
|
millisecondsWidthMap_.setDefault(3);
|
|
performanceTrackingMap_.setDefault(false);
|
|
fileStreamMap_.setDefault(NULL);
|
|
formatFlagMap_.setDefault(0x0);
|
|
rollOutSizeMap_.setDefault(0);
|
|
parse(configurations);
|
|
}
|
|
|
|
virtual ~TypedConfigurations(void) {
|
|
deleteFileStreams();
|
|
}
|
|
|
|
const Configurations& configurations(void) const {
|
|
return configurations_;
|
|
}
|
|
private:
|
|
internal::ConfigurationMap<bool> enabledMap_;
|
|
internal::ConfigurationMap<bool> toFileMap_;
|
|
internal::ConfigurationMap<std::string> filenameMap_;
|
|
internal::ConfigurationMap<bool> toStandardOutputMap_;
|
|
internal::ConfigurationMap<std::string> logFormatMap_;
|
|
internal::ConfigurationMap<std::string> dateFormatMap_;
|
|
internal::ConfigurationMap<std::string> dateFormatSpecifierMap_;
|
|
internal::ConfigurationMap<int> millisecondsWidthMap_;
|
|
internal::ConfigurationMap<bool> performanceTrackingMap_;
|
|
internal::ConfigurationMap<std::fstream*> fileStreamMap_;
|
|
internal::ConfigurationMap<unsigned int> formatFlagMap_;
|
|
internal::ConfigurationMap<std::size_t> rollOutSizeMap_;
|
|
internal::Constants* constants_;
|
|
Configurations configurations_;
|
|
|
|
friend class Writer;
|
|
friend class easyloggingpp::Loggers;
|
|
|
|
inline bool enabled(unsigned int level_) {
|
|
return enabledMap_.get(level_);
|
|
}
|
|
|
|
inline bool toFile(unsigned int level_) {
|
|
return toFileMap_.get(level_);
|
|
}
|
|
|
|
inline const std::string& filename(unsigned int level_) {
|
|
return filenameMap_.get(level_);
|
|
}
|
|
|
|
inline bool toStandardOutput(unsigned int level_) {
|
|
return toStandardOutputMap_.get(level_);
|
|
}
|
|
|
|
inline const std::string& logFormat(unsigned int level_) {
|
|
return logFormatMap_.get(level_);
|
|
}
|
|
|
|
inline const std::string& dateFormat(unsigned int level_) {
|
|
return dateFormatMap_.get(level_);
|
|
}
|
|
|
|
inline const std::string& dateFormatSpecifier(unsigned int level_) {
|
|
return dateFormatSpecifierMap_.get(level_);
|
|
}
|
|
|
|
inline int millisecondsWidth(unsigned int level_ = Level::All) {
|
|
return millisecondsWidthMap_.get(level_);
|
|
}
|
|
|
|
inline bool performanceTracking(unsigned int level_ = Level::All) {
|
|
return performanceTrackingMap_.get(level_);
|
|
}
|
|
|
|
inline std::fstream* fileStream(unsigned int level_) {
|
|
return fileStreamMap_.get(level_);
|
|
}
|
|
|
|
inline std::size_t rollOutSize(unsigned int level_) {
|
|
return rollOutSizeMap_.get(level_);
|
|
}
|
|
|
|
inline int formatFlag(unsigned int level_) {
|
|
return formatFlagMap_.get(level_);
|
|
}
|
|
|
|
void parse(const Configurations& configurations_) {
|
|
for (std::size_t i = 0; i < configurations_.count(); ++i) {
|
|
Configuration* conf = configurations_.at(i);
|
|
switch (conf->type()) {
|
|
case ConfigurationType::Enabled:
|
|
setValue(conf->level(), getBool(conf->value()), enabledMap_);
|
|
break;
|
|
case ConfigurationType::ToFile:
|
|
setValue(conf->level(), getBool(conf->value()), toFileMap_);
|
|
break;
|
|
case ConfigurationType::Filename:
|
|
insertFilename(conf->level(), conf->value());
|
|
break;
|
|
case ConfigurationType::ToStandardOutput:
|
|
setValue(conf->level(), getBool(conf->value()), toStandardOutputMap_);
|
|
break;
|
|
case ConfigurationType::Format:
|
|
determineFormats(conf->level(), conf->value());
|
|
break;
|
|
case ConfigurationType::MillisecondsWidth:
|
|
if (conf->level() == Level::All) {
|
|
int origVal = getInt(conf->value());
|
|
int msl_;
|
|
#if _ELPP_OS_UNIX
|
|
switch (origVal) {
|
|
case 3:
|
|
msl_ = 1000;
|
|
break;
|
|
case 4:
|
|
msl_ = 100;
|
|
break;
|
|
case 5:
|
|
msl_ = 10;
|
|
break;
|
|
case 6:
|
|
msl_ = 1;
|
|
break;
|
|
default:
|
|
msl_ = constants_->DEFAULT_MILLISECOND_OFFSET;
|
|
}
|
|
#elif _ELPP_OS_WINDOWS
|
|
msl_ = 1000;
|
|
__EASYLOGGINGPP_SUPPRESS_UNSED(origVal);
|
|
#endif // _ELPP_OS_UNIX
|
|
setValue(conf->level(), msl_, millisecondsWidthMap_);
|
|
}
|
|
break;
|
|
case ConfigurationType::PerformanceTracking:
|
|
if (conf->level() == Level::All) {
|
|
setValue(conf->level(), getBool(conf->value()), performanceTrackingMap_);
|
|
}
|
|
break;
|
|
case ConfigurationType::RollOutSize:
|
|
setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())), rollOutSizeMap_);
|
|
unsigned int validLevel_ = 0;
|
|
std::string rolloutFilename_ = std::string();
|
|
checkRollOuts(conf->level(), validLevel_, rolloutFilename_);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void determineFormats(unsigned int level_, const std::string& originalFormat) {
|
|
unsigned int formatSpec = 0x0;
|
|
if (originalFormat.find(constants_->APP_NAME_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kAppName;
|
|
}
|
|
if (originalFormat.find(constants_->LOGGER_ID_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kLoggerId;
|
|
}
|
|
if (originalFormat.find(constants_->THREAD_ID_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kThreadId;
|
|
}
|
|
if (originalFormat.find(constants_->LOCATION_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kLocation;
|
|
}
|
|
if (originalFormat.find(constants_->FUNCTION_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kFunction;
|
|
}
|
|
if (originalFormat.find(constants_->USER_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kUser;
|
|
}
|
|
if (originalFormat.find(constants_->HOST_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kHost;
|
|
}
|
|
if (originalFormat.find(constants_->LOG_MESSAGE_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kLogMessage;
|
|
}
|
|
if (originalFormat.find(constants_->VERBOSE_LEVEL_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kVerboseLevel;
|
|
}
|
|
if (originalFormat.find(constants_->DATE_TIME_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kDateTime;
|
|
setValue(level_, constants_->DATE_TIME_FORMAT_SPECIFIER, dateFormatSpecifierMap_);
|
|
} else if (originalFormat.find(constants_->DATE_ONLY_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kDateOnly;
|
|
setValue(level_, constants_->DATE_ONLY_FORMAT_SPECIFIER, dateFormatSpecifierMap_);
|
|
} else if (originalFormat.find(constants_->TIME_ONLY_FORMAT_SPECIFIER) != std::string::npos) {
|
|
formatSpec |= constants_->kTimeOnly;
|
|
setValue(level_, constants_->TIME_ONLY_FORMAT_SPECIFIER, dateFormatSpecifierMap_);
|
|
}
|
|
#if _ELPP_OS_UNIX
|
|
const std::string kTimeFormatLocal_ = "%H:%M:%S";
|
|
const std::string kDateFormatLocal_ = "%d/%m/%Y";
|
|
std::string dateFormat;
|
|
|
|
if (formatSpec & constants_->kDateOnly) {
|
|
dateFormat = kDateFormatLocal_;
|
|
} else if (formatSpec & constants_->kTimeOnly) {
|
|
dateFormat = kTimeFormatLocal_;
|
|
} else {
|
|
std::stringstream ss;
|
|
ss << kDateFormatLocal_ << " " << kTimeFormatLocal_;
|
|
dateFormat = ss.str();
|
|
}
|
|
setValue(level_, dateFormat, dateFormatMap_);
|
|
#endif // _ELPP_OS_UNIX
|
|
setValue(level_, formatSpec, formatFlagMap_);
|
|
// Update %level
|
|
std::string origFormatCopy = originalFormat;
|
|
switch (level_) {
|
|
case Level::Debug:
|
|
internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER,
|
|
constants_->LOG_DEBUG_LEVEL_VALUE, origFormatCopy, constants_);
|
|
break;
|
|
case Level::Info:
|
|
internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER,
|
|
constants_->LOG_INFO_LEVEL_VALUE, origFormatCopy, constants_);
|
|
break;
|
|
case Level::Warning:
|
|
internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER,
|
|
constants_->LOG_WARNING_LEVEL_VALUE, origFormatCopy, constants_);
|
|
break;
|
|
case Level::Error:
|
|
internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER,
|
|
constants_->LOG_ERROR_LEVEL_VALUE, origFormatCopy, constants_);
|
|
break;
|
|
case Level::Fatal:
|
|
internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER,
|
|
constants_->LOG_FATAL_LEVEL_VALUE, origFormatCopy, constants_);
|
|
break;
|
|
case Level::Verbose:
|
|
internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER,
|
|
constants_->LOG_VERBOSE_LEVEL_VALUE, origFormatCopy, constants_);
|
|
break;
|
|
case Level::QA:
|
|
internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER,
|
|
constants_->LOG_QA_LEVEL_VALUE, origFormatCopy, constants_);
|
|
break;
|
|
case Level::Trace:
|
|
internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER,
|
|
constants_->LOG_TRACE_LEVEL_VALUE, origFormatCopy, constants_);
|
|
break;
|
|
}
|
|
setValue(level_, origFormatCopy + "\n", logFormatMap_);
|
|
}
|
|
|
|
void deleteFileStreams(void) {
|
|
ELPP_FOR_EACH_LEVEL(i, Level::kMinValid,
|
|
removeFile(i);
|
|
);
|
|
}
|
|
|
|
// This is different since we need unique values
|
|
void insertFilename(unsigned int level_, const std::string& fname_, bool forceNew = false) {
|
|
std::string fnameFull = fname_;
|
|
if (internal::utilities::StringUtils::endsWith(fnameFull, constants_->PATH_SLASH)) {
|
|
fnameFull.append(constants_->DEFAULT_LOG_FILENAME);
|
|
}
|
|
std::string path_ = internal::utilities::OSUtils::getPathFromFilename(fnameFull, constants_);
|
|
if (path_.size() < fnameFull.size()) {
|
|
// Contains path - create it if it does not already exist
|
|
internal::utilities::OSUtils::createPath(path_);
|
|
}
|
|
if (filenameMap_.size() == 0) {
|
|
filenameMap_.set(Level::All, fnameFull);
|
|
std::fstream *fsAll = newFileStream(fnameFull, forceNew);
|
|
if (fsAll != NULL) {
|
|
fileStreamMap_.set(Level::All, fsAll);
|
|
}
|
|
return;
|
|
}
|
|
ELPP_FOR_EACH_LEVEL(i, Level::kMinValid,
|
|
if (filenameMap_.exist(i, fnameFull)) {
|
|
return;
|
|
}
|
|
);
|
|
filenameMap_.set(level_, fnameFull);
|
|
// Just before we proceed and create new file stream we check for existing one on same level,
|
|
// if we have existing one, we first delete it to prevent memory leak.
|
|
std::fstream *fs = fileStreamMap_.get(level_, true);
|
|
internal::utilities::safeDelete(fs);
|
|
fileStreamMap_.unset(level_);
|
|
fs = newFileStream(fnameFull, forceNew);
|
|
if (fs != NULL) {
|
|
fileStreamMap_.set(level_, fs);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void setValue(unsigned int level_, const T& value_, internal::ConfigurationMap<T>& map_, bool skipLEVEL_ALL = false) {
|
|
if (map_.size() == 0 && !skipLEVEL_ALL) {
|
|
map_.set(Level::All, value_);
|
|
return;
|
|
}
|
|
if (map_.exist(static_cast<unsigned int>(Level::All), value_)) {
|
|
return;
|
|
}
|
|
map_.set(level_, value_);
|
|
}
|
|
|
|
std::fstream* newFileStream(const std::string& filename, bool forceNew = false) {
|
|
std::fstream *fs = NULL;
|
|
if (forceNew) {
|
|
fs = new std::fstream(filename.c_str(), std::fstream::out);
|
|
} else {
|
|
fs = new std::fstream(filename.c_str(), std::fstream::out | std::fstream::app);
|
|
}
|
|
if (fs->is_open()) {
|
|
fs->flush();
|
|
} else {
|
|
internal::utilities::safeDelete(fs, false);
|
|
std::cerr << "Bad file [" << filename << "]" << std::endl;
|
|
return NULL;
|
|
}
|
|
return fs;
|
|
}
|
|
|
|
void removeFile(unsigned int level_) {
|
|
std::fstream* fs = fileStream(level_);
|
|
if (!fs) {
|
|
return;
|
|
}
|
|
if (fs->is_open()) {
|
|
fs->close();
|
|
}
|
|
internal::utilities::safeDelete(fs, false);
|
|
fileStreamMap_.unset(level_);
|
|
filenameMap_.unset(level_);
|
|
}
|
|
|
|
unsigned long getULong(const std::string& confValue_) {
|
|
bool valid = true;
|
|
std::string trimmedVal = internal::utilities::StringUtils::trim(confValue_);
|
|
if (trimmedVal.size() == 0) {
|
|
valid = false;
|
|
__EASYLOGGINGPP_SUPPRESS_UNSED(valid);
|
|
__EASYLOGGINGPP_ASSERT(valid, "Configuration value not a valid integer " << trimmedVal);
|
|
}
|
|
for (std::size_t i = 0; i < trimmedVal.size(); ++i) {
|
|
if (trimmedVal[i] < 48 || trimmedVal[i] > 57) {
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
__EASYLOGGINGPP_SUPPRESS_UNSED(valid);
|
|
__EASYLOGGINGPP_ASSERT(valid, "Configuration value not a valid integer " << trimmedVal);
|
|
return atol(confValue_.c_str());
|
|
}
|
|
|
|
inline int getInt(const std::string& confValue_) {
|
|
return static_cast<int>(getULong(confValue_));
|
|
}
|
|
|
|
inline bool getBool(const std::string& confValue_) {
|
|
std::string trimmedVal = internal::utilities::StringUtils::trim(confValue_);
|
|
return (trimmedVal == "1" || trimmedVal == "true" || trimmedVal == "TRUE");
|
|
}
|
|
|
|
std::size_t getSizeOfFile(std::fstream *fs) {
|
|
if (!fs) {
|
|
return 0;
|
|
}
|
|
std::streampos currPos = fs->tellg();
|
|
fs->seekg (0, fs->end);
|
|
std::size_t size = static_cast<std::size_t>(fs->tellg());
|
|
fs->seekg (currPos);
|
|
return size;
|
|
}
|
|
|
|
bool checkRollOuts(unsigned int level_, unsigned int& validLevel_, std::string& fname_) {
|
|
std::fstream* fs = fileStream(level_);
|
|
std::size_t rollOutSize_ = rollOutSize(level_);
|
|
if (rollOutSize_ != 0 && getSizeOfFile(fs) >= rollOutSize_) {
|
|
fname_ = filename(level_);
|
|
#if defined(_ELPP_INTERNAL_INFO)
|
|
std::cout << "Cleaning log file [" << fname_ << "]\n";
|
|
#endif // defined(_ELPP_INTERNAL_INFO)
|
|
// Find and reset correct level. By correct level we mean the current
|
|
// available level in fileStream because this level_ could actually be using
|
|
// configurations from Level::All and you do not want to create a brand new
|
|
// stream just because we are rolling log away
|
|
validLevel_ = findValidLevel(fileStreamMap_, level_);
|
|
forceReinitiateFile(validLevel_, fname_);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template <typename T>
|
|
inline unsigned int findValidLevel(internal::ConfigurationMap<T>& map_, unsigned int refLevel_) {
|
|
return map_.exist(refLevel_) ? refLevel_ : static_cast<unsigned int>(Level::All);
|
|
}
|
|
|
|
inline void forceReinitiateFile(unsigned int level_, const std::string& filename_) {
|
|
removeFile(level_);
|
|
insertFilename(level_, filename_, true);
|
|
}
|
|
};
|
|
} // namespace internal
|
|
|
|
//!
|
|
//! Represents single logger used to write log.
|
|
//!
|
|
class Logger {
|
|
public:
|
|
//!
|
|
//! Minimal constructor to set logger ID and constants. You should not use this constructor manually, instead use
|
|
//! easyloggingpp::Loggers::getLogger
|
|
//! \param uniqueIdentifier_ Logger ID that you will require to get logger from logger repository
|
|
//! \param constants_ Use <code>easyloggingpp::internal::registeredLoggers->constants()</code>
|
|
//!
|
|
Logger(const std::string& uniqueIdentifier_, internal::Constants* constants_) :
|
|
id_(uniqueIdentifier_),
|
|
constants_(constants_),
|
|
typedConfigurations_(NULL),
|
|
stream_(new std::stringstream()) {
|
|
Configurations defaultConfs;
|
|
defaultConfs.setToDefault();
|
|
configure(defaultConfs);
|
|
userConfigurations_ = defaultConfs;
|
|
defaultConfs.clear();
|
|
}
|
|
|
|
//!
|
|
//! Full constructor to set logger ID, constants and configuration.
|
|
//! \param uniqueIdentifier_ Logger ID that you will require to get logger from logger repository
|
|
//! \param constants_ Use <code>easyloggingpp::internal::registeredLoggers->constants()</code>
|
|
//! \param configurations Configurations to set logger against
|
|
//!
|
|
Logger(const std::string& uniqueIdentifier_, internal::Constants* constants_, const Configurations& configurations) :
|
|
id_(uniqueIdentifier_),
|
|
constants_(constants_),
|
|
typedConfigurations_(NULL),
|
|
stream_(new std::stringstream()) {
|
|
configure(configurations);
|
|
}
|
|
|
|
virtual ~Logger(void) {
|
|
internal::utilities::safeDelete(typedConfigurations_);
|
|
internal::utilities::safeDelete(stream_);
|
|
}
|
|
|
|
//!
|
|
//! \return Logger ID
|
|
//!
|
|
inline std::string id(void) const {
|
|
return id_;
|
|
}
|
|
|
|
//!
|
|
//! Configures logger against specified configurations
|
|
//! \param configurations_
|
|
//!
|
|
void configure(const Configurations& configurations_) {
|
|
#if _ELPP_ENABLE_MUTEX
|
|
internal::threading::ScopedLock slock_(mutex_);
|
|
__EASYLOGGINGPP_SUPPRESS_UNSED(slock_);
|
|
#endif // _ELPP_ENABLE_MUTEX
|
|
// Configuring uses existing configuration as starting point
|
|
// and then sets configurations_ as base to prevent losing any
|
|
// previous configurations
|
|
Configurations base_ = userConfigurations_;
|
|
if (userConfigurations_ != configurations_) {
|
|
userConfigurations_ = configurations_;
|
|
base_.setFromBase(const_cast<Configurations*>(&configurations_));
|
|
}
|
|
internal::utilities::safeDelete(typedConfigurations_);
|
|
typedConfigurations_ = new internal::TypedConfigurations(base_, constants_);
|
|
configured_ = true;
|
|
}
|
|
|
|
//!
|
|
//! Reconfigures logger
|
|
//!
|
|
inline void reconfigure(void) {
|
|
configure(this->userConfigurations_);
|
|
}
|
|
|
|
//!
|
|
//! \return Application name for this logger
|
|
//!
|
|
inline std::string applicationName(void) const {
|
|
return applicationName_;
|
|
}
|
|
|
|
|
|
//!
|
|
//! Application name can vary from logger to logger. For example for a library application name may be different.
|
|
//! This is whats used later when you use '%app' in log format
|
|
//!
|
|
inline void setApplicationName(const std::string& applicationName_) {
|
|
this->applicationName_ = applicationName_;
|
|
}
|
|
|
|
//!
|
|
//! \return Configurations that this logger is set against
|
|
//!
|
|
inline Configurations& configurations(void) {
|
|
return userConfigurations_;
|
|
}
|
|
|
|
//!
|
|
//! \return Whether or not logger is configured.
|
|
//!
|
|
inline bool configured(void) const {
|
|
return configured_;
|
|
}
|
|
|
|
//!
|
|
//! Predicate used in logger repository to find logger. This is used internally. You should not use it.
|
|
//!
|
|
class Predicate {
|
|
public:
|
|
explicit Predicate(const std::string& id_) :
|
|
id_(id_) {
|
|
}
|
|
inline bool operator()(const Logger* logger_) {
|
|
return ((logger_ != NULL) && (logger_->id() == id_));
|
|
}
|
|
private:
|
|
std::string id_;
|
|
};
|
|
private:
|
|
std::string id_;
|
|
internal::Constants* constants_;
|
|
Configurations userConfigurations_;
|
|
internal::TypedConfigurations* typedConfigurations_;
|
|
std::stringstream* stream_;
|
|
std::string applicationName_;
|
|
bool configured_;
|
|
internal::threading::Mutex mutex_;
|
|
friend class internal::Writer;
|
|
friend class Loggers;
|
|
friend class internal::RegisteredLoggers;
|
|
|
|
Logger(void);
|
|
|
|
std::stringstream* stream(void) {
|
|
return stream_;
|
|
}
|
|
|
|
inline void acquireLock(void) {
|
|
mutex_.lock();
|
|
}
|
|
|
|
inline void releaseLock(void) {
|
|
mutex_.unlock();
|
|
}
|
|
};
|
|
|
|
namespace internal {
|
|
//!
|
|
//! Internal log counter used for interval logging
|
|
//!
|
|
class LogCounter : private internal::NoCopy {
|
|
public:
|
|
explicit LogCounter(internal::Constants* constants_) :
|
|
file_(""),
|
|
line_(0),
|
|
position_(1),
|
|
constants_(constants_) {
|
|
}
|
|
|
|
LogCounter(const char* file_,
|
|
unsigned long int line_,
|
|
internal::Constants* constants_) :
|
|
file_(file_),
|
|
line_(line_),
|
|
position_(1),
|
|
constants_(constants_) {
|
|
}
|
|
|
|
virtual ~LogCounter(void) {
|
|
}
|
|
|
|
inline void resetLocation(const char* file_,
|
|
unsigned long int line_) {
|
|
this->file_ = file_;
|
|
this->line_ = line_;
|
|
}
|
|
|
|
inline void reset(std::size_t n_) {
|
|
if (position_ >= constants_->MAX_LOG_PER_COUNTER) {
|
|
position_ = (n_ >= 1 ? constants_->MAX_LOG_PER_COUNTER % n_ : 0);
|
|
}
|
|
++position_;
|
|
}
|
|
|
|
inline const char* file(void) const {
|
|
return file_;
|
|
}
|
|
|
|
inline unsigned long int line(void) const {
|
|
return line_;
|
|
}
|
|
|
|
inline std::size_t position(void) const {
|
|
return position_;
|
|
}
|
|
|
|
class Predicate {
|
|
public:
|
|
Predicate(const char* file_, unsigned long int line_)
|
|
: file_(file_),
|
|
line_(line_) {
|
|
}
|
|
inline bool operator()(const LogCounter* counter_) {
|
|
return ((counter_ != NULL) &&
|
|
(counter_->file_ == file_) &&
|
|
(counter_->line_ == line_));
|
|
}
|
|
|
|
private:
|
|
const char* file_;
|
|
unsigned long int line_;
|
|
};
|
|
private:
|
|
const char* file_;
|
|
unsigned long int line_;
|
|
std::size_t position_;
|
|
internal::Constants* constants_;
|
|
}; // class LogCounter
|
|
|
|
//!
|
|
//! Internal LogCounter repository
|
|
//!
|
|
class RegisteredCounters : public Registry<internal::LogCounter, internal::LogCounter::Predicate> {
|
|
public:
|
|
bool validate(const char* file_, unsigned long int line_, std::size_t n_, internal::Constants* constants_) {
|
|
#if _ELPP_ENABLE_MUTEX
|
|
internal::threading::ScopedLock slock_(mutex_);
|
|
__EASYLOGGINGPP_SUPPRESS_UNSED(slock_);
|
|
#endif // _ELPP_ENABLE_MUTEX
|
|
bool result_ = false;
|
|
internal::LogCounter* counter_ = get(file_, line_);
|
|
if (counter_ == NULL) {
|
|
registerNew(counter_ = new internal::LogCounter(file_, line_, constants_));
|
|
}
|
|
if (n_ >= 1 && counter_->position() != 0 && counter_->position() % n_ == 0) {
|
|
result_ = true;
|
|
}
|
|
counter_->reset(n_);
|
|
return result_;
|
|
}
|
|
private:
|
|
internal::threading::Mutex mutex_;
|
|
}; // class RegisteredCounters
|
|
|
|
//!
|
|
//! Internal logger repository. You should not access functionalities directly, you should use easyloggingpp::Loggers instead
|
|
//!
|
|
class RegisteredLoggers : public internal::Registry<Logger, Logger::Predicate> {
|
|
public:
|
|
RegisteredLoggers(void) :
|
|
constants_(new internal::Constants()),
|
|
username_(internal::utilities::OSUtils::currentUser()),
|
|
hostname_(internal::utilities::OSUtils::currentHost()),
|
|
counters_(new internal::RegisteredCounters()) {
|
|
defaultConfigurations_.setToDefault();
|
|
Configurations conf;
|
|
conf.setToDefault();
|
|
conf.parseFromText(constants_->DEFAULT_LOGGER_CONFIGURATION);
|
|
registerNew(new Logger("trivial", constants_, conf));
|
|
registerNew(new Logger("business", constants_));
|
|
registerNew(new Logger("security", constants_));
|
|
Configurations confPerformance;
|
|
confPerformance.setToDefault();
|
|
confPerformance.setAll(ConfigurationType::PerformanceTracking, "true");
|
|
registerNew(new Logger("performance", constants_, confPerformance));
|
|
}
|
|
|
|
virtual ~RegisteredLoggers(void) {
|
|
internal::utilities::safeDelete(constants_);
|
|
internal::utilities::safeDelete(counters_);
|
|
}
|
|
|
|
inline internal::Constants* constants(void) const {
|
|
return constants_;
|
|
}
|
|
|
|
inline RegisteredCounters* counters(void) {
|
|
return counters_;
|
|
}
|
|
|
|
inline bool validateCounter(const char* file_, unsigned long int line_, std::size_t n_) {
|
|
return counters_->validate(file_, line_, n_, constants_);
|
|
}
|
|
private:
|
|
internal::Constants* constants_;
|
|
std::string username_;
|
|
std::string hostname_;
|
|
internal::threading::Mutex mutex_;
|
|
internal::RegisteredCounters* counters_;
|
|
Configurations defaultConfigurations_;
|
|
|
|
friend class Writer;
|
|
friend class easyloggingpp::Loggers;
|
|
|
|
inline const std::string& username(void) {
|
|
return username_;
|
|
}
|
|
|
|
inline const std::string& hostname(void) {
|
|
return hostname_;
|
|
}
|
|
|
|
inline void setDefaultConfigurations(const Configurations& configurations) {
|
|
defaultConfigurations_.setFromBase(const_cast<Configurations*>(&configurations));
|
|
}
|
|
|
|
Logger* get(const std::string& id_, bool forceCreation_ = true) {
|
|
#if _ELPP_ENABLE_MUTEX
|
|
internal::threading::ScopedLock slock_(mutex_);
|
|
__EASYLOGGINGPP_SUPPRESS_UNSED(slock_);
|
|
#endif // _ELPP_ENABLE_MUTEX
|
|
Logger* logger_ = internal::Registry<Logger, Logger::Predicate>::get(id_);
|
|
if (logger_ == NULL && forceCreation_) {
|
|
logger_ = new Logger(id_, constants_, defaultConfigurations_);
|
|
registerNew(logger_);
|
|
}
|
|
return logger_;
|
|
}
|
|
|
|
inline void unregister(Logger*& logger_) {
|
|
#if _ELPP_ENABLE_MUTEX
|
|
internal::threading::ScopedLock slock_(mutex_);
|
|
#endif // _ELPP_ENABLE_MUTEX
|
|
internal::Registry<Logger, Logger::Predicate>::unregister(logger_);
|
|
}
|
|
|
|
inline void acquireLock(void) {
|
|
mutex_.lock();
|
|
}
|
|
|
|
inline void releaseLock(void) {
|
|
mutex_.unlock();
|
|
}
|
|
|
|
void setApplicationArguments(int argc, char** argv) {
|
|
while (argc-- > 0) {
|
|
// Look for --v=X argument
|
|
if ((strlen(argv[argc]) >= 5) && (argv[argc][0] == '-') && (argv[argc][1] == '-') &&
|
|
(argv[argc][2] == 'v') && (argv[argc][3] == '=') && (isdigit(argv[argc][4]))) {
|
|
// Current argument is --v=X
|
|
// where X is a digit between 0-9
|
|
constants_->CURRENT_VERBOSE_LEVEL = atoi(argv[argc] + 4);
|
|
}
|
|
// Look for -v argument
|
|
else if ((strlen(argv[argc]) == 2) && (argv[argc][0] == '-') && (argv[argc][1] == 'v')) {
|
|
constants_->CURRENT_VERBOSE_LEVEL = constants_->MAX_VERBOSE_LEVEL;
|
|
}
|
|
// Look for --verbose argument
|
|
else if ((strlen(argv[argc]) == 9) && (argv[argc][0] == '-') && (argv[argc][1] == '-') &&
|
|
(argv[argc][2] == 'v') && (argv[argc][3] == 'e') && (argv[argc][4] == 'r') &&
|
|
(argv[argc][5] == 'b') && (argv[argc][6] == 'o') && (argv[argc][7] == 's') &&
|
|
(argv[argc][8] == 'e')) {
|
|
constants_->CURRENT_VERBOSE_LEVEL = constants_->MAX_VERBOSE_LEVEL;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void setApplicationArguments(int argc, const char** argv) {
|
|
setApplicationArguments(argc, const_cast<char**>(argv));
|
|
}
|
|
};
|
|
|
|
extern internal::ScopedPointer<internal::RegisteredLoggers> registeredLoggers;
|
|
#if defined(_ELPP_STL_LOGGING)
|
|
namespace workarounds {
|
|
// 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 O(class_.size()) or O(constants->MAX_LOG_PER_COUNTER) which ever is smaller.
|
|
|
|
//
|
|
// Abstract IterableContainer template that provides interface for iterable classes of type T
|
|
//
|
|
template <typename T, typename Container>
|
|
class IterableContainer {
|
|
public:
|
|
typedef typename Container::iterator iterator;
|
|
typedef typename Container::const_iterator const_iterator;
|
|
IterableContainer(void){}
|
|
virtual ~IterableContainer(void) {}
|
|
iterator begin(void) { return getContainer().begin(); }
|
|
iterator end(void) { return getContainer().end(); }
|
|
const_iterator begin(void) const { return getContainer().begin(); }
|
|
const_iterator end(void) const { return getContainer().end(); }
|
|
private:
|
|
virtual Container& getContainer(void) = 0;
|
|
};
|
|
|
|
//
|
|
// Implements IterableContainer and provides iterable std::priority_queue class
|
|
//
|
|
template<typename T, typename Container = std::vector<T>, typename Comparator = std::less<typename Container::value_type> >
|
|
class IterablePriorityQueue : public IterableContainer<T, Container>, public std::priority_queue<T, Container, Comparator> {
|
|
public:
|
|
IterablePriorityQueue(std::priority_queue<T, Container, Comparator> queue_) {
|
|
std::size_t count_ = 0;
|
|
while (++count_ < registeredLoggers->constants()->MAX_LOG_PER_CONTAINER && !queue_.empty()) {
|
|
this->push(queue_.top());
|
|
queue_.pop();
|
|
}
|
|
}
|
|
private:
|
|
inline Container& getContainer(void) {
|
|
return this->c;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Implements IterableContainer and provides iterable std::queue class
|
|
//
|
|
template<typename T, typename Container = std::deque<T> >
|
|
class IterableQueue : public IterableContainer<T, Container>, public std::queue<T, Container> {
|
|
public:
|
|
IterableQueue(std::queue<T, Container> queue_) {
|
|
std::size_t count_ = 0;
|
|
while (++count_ < registeredLoggers->constants()->MAX_LOG_PER_CONTAINER && !queue_.empty()) {
|
|
this->push(queue_.front());
|
|
queue_.pop();
|
|
}
|
|
}
|
|
private:
|
|
inline Container& getContainer(void) {
|
|
return this->c;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Implements IterableContainer and provides iterable std::stack class
|
|
//
|
|
template<typename T, typename Container = std::deque<T> >
|
|
class IterableStack : public IterableContainer<T, Container>, public std::stack<T, Container> {
|
|
public:
|
|
IterableStack(std::stack<T, Container> stack_) {
|
|
std::size_t count_ = 0;
|
|
while (++count_ < registeredLoggers->constants()->MAX_LOG_PER_CONTAINER && !stack_.empty()) {
|
|
this->push(stack_.top());
|
|
stack_.pop();
|
|
}
|
|
}
|
|
private:
|
|
inline Container& getContainer(void) {
|
|
return this->c;
|
|
}
|
|
};
|
|
} // namespace workarounds
|
|
#endif //defined(_ELPP_STL_LOGGING)
|
|
|
|
#define _ELPP_STREAM(l) (*(l->stream()))
|
|
|
|
class NullWriter : private internal::NoCopy {
|
|
public:
|
|
NullWriter(void) {}
|
|
|
|
template <typename T>
|
|
inline NullWriter& operator<<(const T&) {
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
class Writer : private internal::NoCopy {
|
|
public:
|
|
Writer(const std::string& loggerId_,
|
|
unsigned int aspect_,
|
|
unsigned int severity_,
|
|
const char* func_,
|
|
const char* file_,
|
|
const unsigned long int line_,
|
|
bool condition_ = true,
|
|
int verboseLevel_ = 0,
|
|
int counter_ = 0) :
|
|
aspect_(aspect_),
|
|
severity_(severity_),
|
|
func_(func_),
|
|
file_(file_),
|
|
line_(line_),
|
|
condition_(condition_),
|
|
verboseLevel_(verboseLevel_),
|
|
counter_(counter_),
|
|
proceed_(true) {
|
|
constants_ = registeredLoggers->constants();
|
|
logger_ = registeredLoggers->get(loggerId_, false);
|
|
if (logger_ == NULL) {
|
|
__EASYLOGGINGPP_ASSERT(logger_ != NULL, "Logger [" << loggerId_ << "] not registered or configured yet!");
|
|
proceed_ = false;
|
|
}
|
|
#if _ELPP_ENABLE_MUTEX
|
|
registeredLoggers->acquireLock();
|
|
mutex_.lock();
|
|
#endif // _ELPP_ENABLE_MUTEX
|
|
|
|
if (proceed_) {
|
|
proceed_ = logger_->typedConfigurations_->enabled(severity_);
|
|
}
|
|
if (proceed_) {
|
|
#if (defined(_ELPP_STRICT_ROLLOUT))
|
|
checkRollOuts(severity_, logger_);
|
|
#endif // (defined(_ELPP_STRICT_ROLLOUT))
|
|
}
|
|
if (proceed_ && (severity_ == Level::Verbose)) {
|
|
proceed_ = (verboseLevel_ <= constants_->CURRENT_VERBOSE_LEVEL);
|
|
}
|
|
if (proceed_ && (aspect_ == Aspect::Conditional)) {
|
|
proceed_ = condition_;
|
|
}
|
|
}
|
|
|
|
virtual ~Writer(void) {
|
|
if (proceed_) {
|
|
buildAndWriteLine();
|
|
}
|
|
#if _ELPP_ENABLE_MUTEX
|
|
registeredLoggers->releaseLock();
|
|
mutex_.unlock();
|
|
#endif // _ELPP_ENABLE_MUTEX
|
|
}
|
|
|
|
inline Writer& operator<<(const std::string& log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(char log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(bool log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(signed short log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(unsigned short log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(signed int log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(unsigned int log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(signed long log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(unsigned long log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(float log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(double log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(char* log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(const char* log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(const void* log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(long double log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_;
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(const std::wstring& log_) {
|
|
if (!proceed_) { return *this; }
|
|
return operator<<(log_.c_str());
|
|
}
|
|
inline Writer& operator<<(const wchar_t* log_) {
|
|
if (!proceed_) { return *this; }
|
|
if (log_ == NULL) {
|
|
_ELPP_STREAM(logger_) << constants_->NULL_POINTER;
|
|
return *this;
|
|
}
|
|
std::size_t len_ = wcslen(log_) + 1;
|
|
char* buff_ = (char*)malloc(len_ + 1);
|
|
# if _ELPP_OS_UNIX || (_ELPP_OS_WINDOWS && !_ELPP_CRT_DBG_WARNINGS)
|
|
std::wcstombs(buff_, log_, len_);
|
|
# elif _ELPP_OS_WINDOWS
|
|
std::size_t convCount_ = 0;
|
|
mbstate_t mbState_;
|
|
::memset((void*)&mbState_, 0, sizeof(mbState_));
|
|
wcsrtombs_s(&convCount_, buff_, len_, &log_, len_, &mbState_);
|
|
# endif // _ELPP_OS_UNIX
|
|
_ELPP_STREAM(logger_) << buff_;
|
|
free(buff_);
|
|
return *this;
|
|
}
|
|
#if defined(_ELPP_STL_LOGGING)
|
|
template <typename T, typename Container>
|
|
inline Writer& operator<<(const std::vector<T, Container>& vec_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(vec_.begin(), vec_.end(), vec_.size());
|
|
}
|
|
template <typename T, typename Container>
|
|
inline Writer& operator<<(const std::list<T, Container>& list_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(list_.begin(), list_.end(), list_.size());
|
|
}
|
|
template <typename T, typename Container>
|
|
inline Writer& operator<<(const std::deque<T, Container>& deque_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(deque_.begin(), deque_.end(), deque_.size());
|
|
}
|
|
template <typename T, typename Container>
|
|
inline Writer& operator<<(const std::queue<T, Container>& queue_) {
|
|
if (!proceed_) { return *this; }
|
|
internal::workarounds::IterableQueue<T, Container> iterableQueue_ =
|
|
static_cast<internal::workarounds::IterableQueue<T, Container> >(queue_);
|
|
return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size());
|
|
}
|
|
template <typename T, typename Container>
|
|
inline Writer& operator<<(const std::stack<T, Container>& stack_) {
|
|
if (!proceed_) { return *this; }
|
|
internal::workarounds::IterableStack<T, Container> iterableStack_ =
|
|
static_cast<internal::workarounds::IterableStack<T, Container> >(stack_);
|
|
return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size());
|
|
}
|
|
template <typename T, typename Container, typename Comparator>
|
|
inline Writer& operator<<(const std::priority_queue<T, Container, Comparator>& priorityQueue_) {
|
|
if (!proceed_) { return *this; }
|
|
internal::workarounds::IterablePriorityQueue<T, Container, Comparator> iterablePriorityQueue_ =
|
|
static_cast<internal::workarounds::IterablePriorityQueue<T, Container, Comparator> >(priorityQueue_);
|
|
return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size());
|
|
}
|
|
template <typename T, typename Comparator, typename Container>
|
|
inline Writer& operator<<(const std::set<T, Comparator, Container>& set_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(set_.begin(), set_.end(), set_.size());
|
|
}
|
|
template <typename T, typename Comparator, typename Container>
|
|
inline Writer& operator<<(const std::multiset<T, Comparator, Comparator>& set_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(set_.begin(), set_.end(), set_.size());
|
|
}
|
|
template <typename First, typename Second>
|
|
inline Writer& operator<<(const std::pair<First, Second>& pair_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << "(";
|
|
operator << (static_cast<First>(pair_.first));
|
|
_ELPP_STREAM(logger_) << ", ";
|
|
operator << (static_cast<Second>(pair_.second));
|
|
_ELPP_STREAM(logger_) << ")";
|
|
return *this;
|
|
}
|
|
template <std::size_t Size>
|
|
inline Writer& operator<<(const std::bitset<Size>& bitset_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << "[";
|
|
_ELPP_STREAM(logger_) << bitset_.to_string();
|
|
_ELPP_STREAM(logger_) << "]";
|
|
return *this;
|
|
}
|
|
template <typename K, typename V, typename Comparator, typename Container>
|
|
inline Writer& operator<<(const std::map<K, V, Comparator, Container>& map_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(map_.begin(), map_.end(), map_.size());
|
|
}
|
|
template <typename K, typename V, typename Comparator, typename Container>
|
|
inline Writer& operator<<(const std::multimap<K, V, Comparator, Container>& map_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(map_.begin(), map_.end(), map_.size());
|
|
}
|
|
#endif // defined(_ELPP_STL_LOGGING)
|
|
#if defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING)
|
|
inline Writer& operator<<(const QString& log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_.toStdString();
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(const QStringRef& log_) {
|
|
if (!proceed_) { return *this; }
|
|
return operator<<(log_.toString());
|
|
}
|
|
inline Writer& operator<<(qint64 log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << QString::number(log_).toStdString();
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(quint64 log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << QString::number(log_).toStdString();
|
|
return *this;
|
|
}
|
|
inline Writer& operator<<(QChar log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_.toLatin1();
|
|
return *this;
|
|
}
|
|
# if (!_ELPP_QT_5)
|
|
inline Writer& operator<<(QBool log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << (bool(log_ != 0) ? "true" : "false");
|
|
return *this;
|
|
}
|
|
# endif // (!_ELPP_QT_5)
|
|
inline Writer& operator<<(const QLatin1String& log_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << log_.latin1();
|
|
return *this;
|
|
}
|
|
template <typename T>
|
|
inline Writer& operator<<(const QList<T>& list_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(list_.begin(), list_.end(), list_.size());
|
|
}
|
|
template <typename T>
|
|
inline Writer& operator<<(const QVector<T>& vec_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(vec_.begin(), vec_.end(), vec_.size());
|
|
}
|
|
template <typename T>
|
|
inline Writer& operator<<(const QQueue<T>& queue_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(queue_.begin(), queue_.end(), queue_.size());
|
|
}
|
|
template <typename T>
|
|
inline Writer& operator<<(const QSet<T>& set_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(set_.begin(), set_.end(), set_.size());
|
|
}
|
|
template <typename First, typename Second>
|
|
inline Writer& operator<<(const QPair<First, Second>& pair_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << "(";
|
|
operator << (static_cast<First>(pair_.first));
|
|
_ELPP_STREAM(logger_) << ", ";
|
|
operator << (static_cast<Second>(pair_.second));
|
|
_ELPP_STREAM(logger_) << ")";
|
|
return *this;
|
|
}
|
|
template <typename K, typename V>
|
|
inline Writer& operator<<(const QMap<K, V>& map_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << "[";
|
|
QList<K> keys = map_.keys();
|
|
typename QList<K>::const_iterator begin = keys.begin();
|
|
typename QList<K>::const_iterator end = keys.end();
|
|
int max_ = static_cast<int>(constants_->MAX_LOG_PER_CONTAINER); // to prevent warning
|
|
for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
|
|
_ELPP_STREAM(logger_) << "(";
|
|
operator << (static_cast<K>(*begin));
|
|
_ELPP_STREAM(logger_) << ", ";
|
|
operator << (static_cast<V>(map_.value(*begin)));
|
|
_ELPP_STREAM(logger_) << ")";
|
|
_ELPP_STREAM(logger_) << ((index_ < keys.size() -1) ? ", " : "");
|
|
}
|
|
if (begin != end) {
|
|
_ELPP_STREAM(logger_) << " ...";
|
|
}
|
|
_ELPP_STREAM(logger_) << "]";
|
|
return *this;
|
|
}
|
|
template <typename K, typename V>
|
|
inline Writer& operator<<(const QMultiMap<K, V>& map_) {
|
|
if (!proceed_) { return *this; }
|
|
operator << (static_cast<QMap<K, V> >(map_));
|
|
return *this;
|
|
}
|
|
template <typename K, typename V>
|
|
inline Writer& operator<<(const QHash<K, V>& hash_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << "[";
|
|
QList<K> keys = hash_.keys();
|
|
typename QList<K>::const_iterator begin = keys.begin();
|
|
typename QList<K>::const_iterator end = keys.end();
|
|
int max_ = static_cast<int>(constants_->MAX_LOG_PER_CONTAINER); // prevent type warning
|
|
for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
|
|
_ELPP_STREAM(logger_) << "(";
|
|
operator << (static_cast<K>(*begin));
|
|
_ELPP_STREAM(logger_) << ", ";
|
|
operator << (static_cast<V>(hash_.value(*begin)));
|
|
_ELPP_STREAM(logger_) << ")";
|
|
_ELPP_STREAM(logger_) << ((index_ < keys.size() -1) ? ", " : "");
|
|
}
|
|
if (begin != end) {
|
|
_ELPP_STREAM(logger_) << " ...";
|
|
}
|
|
_ELPP_STREAM(logger_) << "]";
|
|
return *this;
|
|
}
|
|
template <typename K, typename V>
|
|
inline Writer& operator<<(const QMultiHash<K, V>& multiHash_) {
|
|
if (!proceed_) { return *this; }
|
|
operator << (static_cast<QHash<K, V> >(multiHash_));
|
|
return *this;
|
|
}
|
|
template <typename T>
|
|
inline Writer& operator<<(const QLinkedList<T>& linkedList_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(linkedList_.begin(), linkedList_.end(), linkedList_.size());
|
|
}
|
|
template <typename T>
|
|
inline Writer& operator<<(const QStack<T>& stack_) {
|
|
if (!proceed_) { return *this; }
|
|
return writeIterator(stack_.begin(), stack_.end(), stack_.size());
|
|
}
|
|
#endif // defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING)
|
|
template <class Class>
|
|
inline Writer& operator<<(const Class& class_) {
|
|
if (!proceed_) { return *this; }
|
|
_ELPP_STREAM(logger_) << class_;
|
|
return *this;
|
|
}
|
|
private:
|
|
unsigned int aspect_;
|
|
unsigned int severity_;
|
|
const char* func_;
|
|
const char* file_;
|
|
const unsigned long int line_;
|
|
bool condition_;
|
|
int verboseLevel_;
|
|
int counter_;
|
|
Logger* logger_;
|
|
std::stringstream tempss_;
|
|
std::string currLine_;
|
|
bool proceed_;
|
|
internal::Constants* constants_;
|
|
internal::threading::Mutex mutex_;
|
|
|
|
friend class Logger;
|
|
|
|
template<class Iterator>
|
|
inline Writer& writeIterator(Iterator begin_, Iterator end_, std::size_t size_) {
|
|
_ELPP_STREAM(logger_) << "[";
|
|
for (std::size_t i = 0; begin_ != end_ && i < constants_->MAX_LOG_PER_CONTAINER; ++i, ++begin_) {
|
|
operator << (*begin_);
|
|
_ELPP_STREAM(logger_) << ((i < size_ - 1) ? ", " : "");
|
|
}
|
|
if (begin_ != end_) {
|
|
_ELPP_STREAM(logger_) << " ...";
|
|
}
|
|
_ELPP_STREAM(logger_) << "]";
|
|
return *this;
|
|
}
|
|
|
|
void buildAndWriteLine(void) {
|
|
internal::RegisteredLoggers* rl_ = registeredLoggers.pointer();
|
|
TypedConfigurations* conf_ = logger_->typedConfigurations_;
|
|
unsigned int f_ = conf_->formatFlag(severity_); // format spec
|
|
currLine_ = conf_->logFormat(severity_);
|
|
std::string dateFormat = conf_->dateFormat(severity_);
|
|
std::string fs_; // format specifier
|
|
std::string v_; // value
|
|
// App name
|
|
if (f_ & constants_->kAppName) {
|
|
v_ = logger_->applicationName();
|
|
fs_ = constants_->APP_NAME_FORMAT_SPECIFIER;
|
|
internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_);
|
|
}
|
|
// Logger ID
|
|
if (f_ & constants_->kLoggerId) {
|
|
v_ = logger_->id();
|
|
fs_ = constants_->LOGGER_ID_FORMAT_SPECIFIER;
|
|
internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_);
|
|
}
|
|
// Thread ID
|
|
if (f_ & constants_->kThreadId) {
|
|
std::stringstream ss;
|
|
ss << threading::getCurrentThreadId();
|
|
fs_ = constants_->THREAD_ID_FORMAT_SPECIFIER;
|
|
internal::utilities::LogManipulator::updateFormatValue(fs_, ss.str(), currLine_, constants_);
|
|
}
|
|
// Date/Time
|
|
if ((f_ & constants_->kDateOnly) || (f_ & constants_->kTimeOnly) || (f_ & constants_->kDateTime)) {
|
|
v_ = internal::utilities::DateUtils::getDateTime(dateFormat,
|
|
f_, constants_, conf_->millisecondsWidth(Level::All));
|
|
fs_ = conf_->dateFormatSpecifier(severity_);
|
|
internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_);
|
|
}
|
|
// Function
|
|
if (f_ & constants_->kFunction) {
|
|
v_ = std::string(func_);
|
|
fs_ = constants_->FUNCTION_FORMAT_SPECIFIER;
|
|
internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_);
|
|
}
|
|
// Location
|
|
if (f_ & constants_->kLocation) {
|
|
tempss_ << file_ << ":" << line_;
|
|
fs_ = constants_->LOCATION_FORMAT_SPECIFIER;
|
|
internal::utilities::LogManipulator::updateFormatValue(fs_, tempss_.str(), currLine_, constants_);
|
|
tempss_.str("");
|
|
}
|
|
// User
|
|
if (f_ & constants_->kUser) {
|
|
v_ = rl_->username();
|
|
fs_ = constants_->USER_FORMAT_SPECIFIER;
|
|
internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_);
|
|
}
|
|
// Host
|
|
if (f_ & constants_->kHost) {
|
|
v_ = rl_->hostname();
|
|
fs_ = constants_->HOST_FORMAT_SPECIFIER;
|
|
internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_);
|
|
}
|
|
// Verbose level
|
|
if ((severity_ == Level::Verbose) && (f_ & constants_->kVerboseLevel)) {
|
|
tempss_ << verboseLevel_;
|
|
fs_ = constants_->VERBOSE_LEVEL_FORMAT_SPECIFIER;
|
|
internal::utilities::LogManipulator::updateFormatValue(fs_, tempss_.str(), currLine_, constants_);
|
|
}
|
|
// Log message
|
|
if (f_ & constants_->kLogMessage) {
|
|
fs_ = constants_->LOG_MESSAGE_FORMAT_SPECIFIER;
|
|
internal::utilities::LogManipulator::updateFormatValue(fs_, logger_->stream()->str(), currLine_, constants_);
|
|
}
|
|
log();
|
|
}
|
|
|
|
#if (defined(_ELPP_STRICT_ROLLOUT))
|
|
bool checkRollOuts(unsigned int level_, Logger* baseLogger_) {
|
|
unsigned int validLevel_ = 0;
|
|
std::string rolledOutFile = std::string();
|
|
if (baseLogger_->typedConfigurations_->checkRollOuts(level_, validLevel_, rolledOutFile)) {
|
|
Logger* currLogger_ = NULL;
|
|
for (unsigned int i = 0; i < registeredLoggers->count(); ++i) {
|
|
currLogger_ = registeredLoggers->list().at(i);
|
|
if (currLogger_ == baseLogger_)
|
|
continue;
|
|
std::string fname = currLogger_->typedConfigurations_->filename(validLevel_);
|
|
if (fname == rolledOutFile) {
|
|
currLogger_->typedConfigurations_->forceReinitiateFile(validLevel_, fname);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
#endif // (defined(_ELPP_STRICT_ROLLOUT))
|
|
|
|
inline void syncWritePointer(unsigned int level_, Logger* targetLogger_, std::fstream* baseStream_) {
|
|
targetLogger_->acquireLock();
|
|
targetLogger_->typedConfigurations_->fileStream(level_)->seekg(baseStream_->tellg());
|
|
targetLogger_->releaseLock();
|
|
}
|
|
|
|
void safeWriteToFile(unsigned int level_, Logger* logger_, const std::string& line) {
|
|
std::string baseFilename_ = logger_->typedConfigurations_->filename(level_);
|
|
std::fstream* fstr = logger_->typedConfigurations_->fileStream(level_);
|
|
(*fstr) << line;
|
|
fstr->flush();
|
|
Logger* currLogger_ = NULL;
|
|
for (std::size_t i = 0; i < registeredLoggers->count(); ++i) {
|
|
currLogger_ = registeredLoggers->list().at(i);
|
|
if (currLogger_ == logger_)
|
|
continue;
|
|
std::string fname = currLogger_->typedConfigurations_->filename(level_);
|
|
if (fname == baseFilename_) {
|
|
syncWritePointer(level_, currLogger_, fstr);
|
|
}
|
|
}
|
|
}
|
|
|
|
void log(void) {
|
|
if (logger_->stream_) {
|
|
if (logger_->typedConfigurations_->toFile(severity_)) {
|
|
safeWriteToFile(severity_, logger_, currLine_);
|
|
}
|
|
if (logger_->typedConfigurations_->toStandardOutput(severity_)) {
|
|
std::cout << currLine_;
|
|
}
|
|
logger_->stream_->str("");
|
|
}
|
|
}
|
|
};
|
|
} // namespace internal
|
|
|
|
class VersionInfo : private internal::StaticClass {
|
|
public:
|
|
// Minimal formatted displayable information
|
|
static inline const std::string formattedInfo(void) {
|
|
std::stringstream ss;
|
|
ss << "EasyLogging++ v" << version() << " (" << releaseDate() << ")";
|
|
ss << std::endl;
|
|
ss << website();
|
|
ss << std::endl;
|
|
ss << copyright();
|
|
return ss.str();
|
|
}
|
|
|
|
// Current version number
|
|
static inline const std::string version(void) { return std::string("8.91"); }
|
|
|
|
// Release date of current version
|
|
static inline const std::string releaseDate(void) { return std::string("12-07-2013 1243hrs"); }
|
|
|
|
// Original author and maintainer
|
|
static inline const std::string author(void) { return std::string("Majid Khan <mkhan3189@gmail.com>"); }
|
|
|
|
// Web link
|
|
static inline const std::string website(void) { return std::string("http://icplusplus.com/tools/easylogging"); }
|
|
|
|
// Link to source code
|
|
static inline const std::string sourceCodeLink(void) { return std::string("https://github.com/mkhan3189/EasyLoggingPP"); }
|
|
|
|
// Copyright information
|
|
static inline const std::string copyright(void) { return std::string("Copyright (c) 2012 - 2013 Majid Khan"); }
|
|
|
|
// Full licence
|
|
static const std::string licence(void) {
|
|
std::stringstream ss;
|
|
ss << " This software is provided 'as-is', without any express or implied" << std::endl;
|
|
ss << " warranty. In no event will the authors be held liable for any damages" << std::endl;
|
|
ss << " arising from the use of this software." << std::endl;
|
|
ss << std::endl;
|
|
ss << " Permission is granted to anyone to use this software for any purpose," << std::endl;
|
|
ss << " including commercial applications, and to alter it and redistribute" << std::endl;
|
|
ss << " it freely, subject to the following restrictions:" << std::endl;
|
|
ss << std::endl;
|
|
ss << " 1. The origin of this software must not be misrepresented; you must" << std::endl;
|
|
ss << " not claim that you wrote the original software. If you use this" << std::endl;
|
|
ss << " software in a product, an acknowledgment in the product documentation" << std::endl;
|
|
ss << " would be appreciated but is not required." << std::endl;
|
|
ss << std::endl;
|
|
ss << " 2. Altered source versions must be plainly marked as such, and must" << std::endl;
|
|
ss << " not be misrepresented as being the original software." << std::endl;
|
|
ss << std::endl;
|
|
ss << " 3. This notice may not be removed or altered from any source" << std::endl;
|
|
ss << " distribution";
|
|
return ss.str();
|
|
}
|
|
}; // class VersionInfo
|
|
|
|
//!
|
|
//! \brief Helper class to manage loggers and configurations
|
|
//!
|
|
//! A static helper class for users of library. This class contains functions related to register
|
|
//! and configure logger/s
|
|
//!
|
|
class Loggers : private internal::StaticClass {
|
|
public:
|
|
|
|
//!
|
|
//! Get existing logger, if logger does not exist a newly created logger is returned
|
|
//! \param identifier_ A unique ID for logger
|
|
//! \return Pointer to easyloggingpp::Logger from logger repository
|
|
//!
|
|
static inline Logger* getLogger(const std::string& identifier_) {
|
|
return internal::registeredLoggers->get(identifier_);
|
|
}
|
|
|
|
//!
|
|
//! Reconfigures logger with easyloggingpp::Configurations
|
|
//! \param logger_ Pointer to Logger to configure. You get use getLogger() to get pointer from logger repository
|
|
//! \param configurations_ easyloggingpp::Configurations to configure logger against
|
|
//! \return Updated pointer to Logger
|
|
//!
|
|
static inline Logger* reconfigureLogger(Logger* logger_, const Configurations& configurations_) {
|
|
if (!logger_) return NULL;
|
|
logger_->configure(configurations_);
|
|
return logger_;
|
|
}
|
|
|
|
//!
|
|
//! Reconfigures logger with easyloggingpp::Configurations
|
|
//! \param identifier_ Logger ID
|
|
//! \param configurations_ easyloggingpp::Configurations to configure logger against
|
|
//! \return Updated pointer to Logger
|
|
//!
|
|
static inline Logger* reconfigureLogger(const std::string& identifier_, Configurations& configurations_) {
|
|
Logger* logger_ = Loggers::getLogger(identifier_);
|
|
Loggers::reconfigureLogger(logger_, configurations_);
|
|
return logger_;
|
|
}
|
|
|
|
//!
|
|
//! Reconfigures all loggers available in logger repository
|
|
//! \param configurations_ easyloggingpp::Configurations to configure logger against
|
|
//!
|
|
static inline void reconfigureAllLoggers(Configurations& configurations_) {
|
|
for (std::size_t i = 0; i < internal::registeredLoggers->count(); ++i) {
|
|
Logger* l = internal::registeredLoggers->at(i);
|
|
Loggers::reconfigureLogger(l, configurations_);
|
|
}
|
|
}
|
|
|
|
//!
|
|
//! Reconfigures all loggers for single configuration.
|
|
//! \param configurationType_ Configuration type to update. Use easyloggingpp::ConfigurationType to prevent confusion
|
|
//! \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
|
|
//!
|
|
static inline void reconfigureAllLoggers(unsigned int configurationType_, const std::string& value_) {
|
|
for (std::size_t i = 0; i < internal::registeredLoggers->count(); ++i) {
|
|
Logger* l = internal::registeredLoggers->at(i);
|
|
l->configurations().setAll(configurationType_, value_);
|
|
l->reconfigure();
|
|
}
|
|
}
|
|
|
|
//!
|
|
//! Sets default configurations. This configuration is used for future loggers.
|
|
//! \param configurations
|
|
//! \param configureExistingLoggers If true, all loggers are updated against provided configuration otherwise only future loggers
|
|
//! will be updated and all the existing loggers will use configurations that have been set previously.
|
|
//!
|
|
static inline void setDefaultConfigurations(Configurations& configurations, bool configureExistingLoggers = false) {
|
|
internal::registeredLoggers->setDefaultConfigurations(configurations);
|
|
if (configureExistingLoggers) {
|
|
Loggers::reconfigureAllLoggers(configurations);
|
|
}
|
|
}
|
|
|
|
//!
|
|
//! Sets application arguments and uses them where needed. Example use is when application is run with '--v=X' or '-v', verbose logging
|
|
//! turns on
|
|
//! \param argc Argument count
|
|
//! \param argv Argument value array pointer
|
|
//!
|
|
static inline void setApplicationArguments(int argc, char** argv) {
|
|
internal::registeredLoggers->setApplicationArguments(argc, argv);
|
|
}
|
|
|
|
//!
|
|
//! Sets application arguments and uses them where needed. Example use is when application is run with '--v=X' or '-v', verbose logging
|
|
//! turns on
|
|
//! \param argc
|
|
//! \param argv
|
|
//!
|
|
static inline void setApplicationArguments(int argc, const char** argv) {
|
|
internal::registeredLoggers->setApplicationArguments(argc, argv);
|
|
}
|
|
|
|
//!
|
|
//! Disables all loggers
|
|
//!
|
|
static inline void disableAll(void) {
|
|
reconfigureAllLoggers(ConfigurationType::Enabled, "false");
|
|
}
|
|
|
|
//!
|
|
//! Enable all loggers
|
|
//!
|
|
static inline void enableAll(void) {
|
|
reconfigureAllLoggers(ConfigurationType::Enabled, "true");
|
|
}
|
|
|
|
//!
|
|
//! Reconfigure all loggers to write to single log file
|
|
//! \param logFilename_ Full path to log file
|
|
//!
|
|
static inline void setFilename(const std::string& logFilename_) {
|
|
reconfigureAllLoggers(ConfigurationType::Filename, logFilename_);
|
|
}
|
|
|
|
//!
|
|
//! Reconfigure specified logger to write to specified log file
|
|
//! \param logger_ Pointer to logger. You may use Loggers::get(id) to get pointer
|
|
//! \param logFilename_ Full path to log file
|
|
//!
|
|
static inline void setFilename(Logger* logger_, const std::string& logFilename_) {
|
|
if (!logger_) return;
|
|
logger_->configurations().setAll(ConfigurationType::Filename, logFilename_);
|
|
logger_->reconfigure();
|
|
}
|
|
|
|
//!
|
|
//! Determines whether or not performance tracking is enabled
|
|
//! \return True if enabled, false otherwise
|
|
//!
|
|
static inline bool performanceTrackingEnabled(void) {
|
|
return performanceLogger()->typedConfigurations_->performanceTracking();
|
|
}
|
|
|
|
//!
|
|
//! Disables performance tracking.
|
|
//! Performance tracking is logged using 'performance' logger.
|
|
//!
|
|
static inline void disablePerformanceTracking(void) {
|
|
Logger* l = Loggers::performanceLogger();
|
|
l->configurations().setAll(ConfigurationType::PerformanceTracking, "false");
|
|
l->reconfigure();
|
|
}
|
|
|
|
//!
|
|
//! Enable performance tracking
|
|
//! Performance tracking is logged using 'performance' logger.
|
|
//!
|
|
static inline void enablePerformanceTracking(void) {
|
|
Logger* l = Loggers::performanceLogger();
|
|
l->configurations().setAll(ConfigurationType::PerformanceTracking, "true");
|
|
l->reconfigure();
|
|
}
|
|
|
|
//!
|
|
//! Iterates through logger repository and puts IDs into listOfIds
|
|
//! \param listOfIds (Passed by reference) Vector to fill up
|
|
//!
|
|
static inline void getAllLogIdentifiers(std::vector<std::string>& listOfIds) {
|
|
listOfIds.clear();
|
|
for (std::size_t i = 0; i < internal::registeredLoggers->count(); ++i) {
|
|
listOfIds.push_back(internal::registeredLoggers->at(i)->id());
|
|
}
|
|
}
|
|
|
|
//!
|
|
//! \return Returns one of default loggers 'trivial' logger
|
|
//!
|
|
static inline Logger* trivialLogger(void) {
|
|
return Loggers::getLogger("trivial");
|
|
}
|
|
|
|
//!
|
|
//! \return Returns one of default loggers 'business' logger
|
|
//!
|
|
static inline Logger* businessLogger(void) {
|
|
return Loggers::getLogger("business");
|
|
}
|
|
|
|
//!
|
|
//! \return Returns one of default loggers 'security' logger
|
|
//!
|
|
static inline Logger* securityLogger(void) {
|
|
return Loggers::getLogger("security");
|
|
}
|
|
|
|
//!
|
|
//! \return Returns one of default loggers 'performance' logger
|
|
//!
|
|
static inline Logger* performanceLogger(void) {
|
|
return Loggers::getLogger("performance");
|
|
}
|
|
|
|
//!
|
|
//! Static class that contains static helper functions used to read configurations
|
|
//!
|
|
class ConfigurationsReader : private internal::StaticClass {
|
|
public:
|
|
static inline bool enabled(Logger* logger_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr");
|
|
return constConf(logger_)->enabled(level_);
|
|
}
|
|
|
|
static inline bool enabled(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr");
|
|
return conf_->enabled(level_);
|
|
}
|
|
|
|
static inline bool toFile(Logger* logger_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr");
|
|
return constConf(logger_)->toFile(level_);
|
|
}
|
|
|
|
static inline bool toFile(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr");
|
|
return conf_->toFile(level_);
|
|
}
|
|
|
|
static inline const std::string& filename(Logger* logger_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr");
|
|
return constConf(logger_)->filename(level_);
|
|
}
|
|
|
|
static inline const std::string& filename(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr");
|
|
return conf_->filename(level_);
|
|
}
|
|
|
|
static inline bool toStandardOutput(Logger* logger_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr");
|
|
return constConf(logger_)->toStandardOutput(level_);
|
|
}
|
|
|
|
static inline bool toStandardOutput(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr");
|
|
return conf_->toStandardOutput(level_);
|
|
}
|
|
|
|
static inline const std::string& logFormat(Logger* logger_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr");
|
|
return constConf(logger_)->logFormat(level_);
|
|
}
|
|
|
|
static inline const std::string& logFormat(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr");
|
|
return conf_->logFormat(level_);
|
|
}
|
|
|
|
static inline int millisecondsWidth(Logger* logger_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr");
|
|
return constConf(logger_)->millisecondsWidth(level_);
|
|
}
|
|
|
|
static inline int millisecondsWidth(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr");
|
|
return conf_->millisecondsWidth(level_);
|
|
}
|
|
|
|
static inline bool performanceTracking(Logger* logger_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr");
|
|
return constConf(logger_)->performanceTracking(level_);
|
|
}
|
|
|
|
static inline bool performanceTracking(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr");
|
|
return conf_->performanceTracking(level_);
|
|
}
|
|
|
|
static inline std::size_t logRollOutSize(Logger* logger_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr");
|
|
return constConf(logger_)->rollOutSize(level_);
|
|
}
|
|
|
|
static inline std::size_t logRollOutSize(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) {
|
|
__EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr");
|
|
return conf_->rollOutSize(level_);
|
|
}
|
|
|
|
private:
|
|
static inline internal::TypedConfigurations* constConf(Logger* logger_) {
|
|
return logger_->typedConfigurations_;
|
|
}
|
|
}; // class ConfigurationsReader
|
|
private:
|
|
internal::threading::Mutex mutex_;
|
|
};
|
|
//
|
|
// Helping Macros
|
|
//
|
|
// Performance tracking macros
|
|
#if ((!defined(_DISABLE_PERFORMANCE_TRACKING)) || (!defined(_DISABLE_INFO_LOGS)))
|
|
# if _ELPP_OS_UNIX
|
|
# define _ELPP_GET_CURR_TIME(tm) gettimeofday(tm, NULL);
|
|
# elif _ELPP_OS_WINDOWS
|
|
# define _ELPP_GET_CURR_TIME(tm) easyloggingpp::internal::utilities::DateUtils::gettimeofday(tm);
|
|
# endif
|
|
# define START_FUNCTION_LOG "Executing [" << __func__ << "]"
|
|
# define TIME_OUTPUT "Executed [" << __func__ << "] in [" << \
|
|
easyloggingpp::internal::utilities::DateUtils::formatMilliSeconds( \
|
|
easyloggingpp::internal::utilities::DateUtils::getTimeDifference(functionEndTime, functionStartTime)) << "]"
|
|
# define FUNC_SUB_COMMON_START { timeval functionStartTime, functionEndTime; _ELPP_GET_CURR_TIME(&functionStartTime)
|
|
# define WRITE_FUNC_PERFORMANCE _ELPP_GET_CURR_TIME(&functionEndTime); \
|
|
if (easyloggingpp::Loggers::performanceTrackingEnabled()) { PINFO << TIME_OUTPUT; }
|
|
# define FUNC_SUB_COMMON_END WRITE_FUNC_PERFORMANCE;
|
|
# define SUB(FUNCTION_NAME,PARAMS) void FUNCTION_NAME PARAMS FUNC_SUB_COMMON_START
|
|
# define END_SUB FUNC_SUB_COMMON_END }
|
|
# define FUNC(RETURNING_TYPE,FUNCTION_NAME,PARAMS) RETURNING_TYPE FUNCTION_NAME PARAMS FUNC_SUB_COMMON_START
|
|
# define RETURN(return_value) FUNC_SUB_COMMON_END return return_value;
|
|
# define END_FUNC(return_value) RETURN(return_value) }
|
|
# define MAIN(argc, argv) FUNC(int, main, (argc, argv))
|
|
# define END_MAIN(return_value) FUNC_SUB_COMMON_END; return return_value; }
|
|
# define RETURN_MAIN(exit_status) return exit_status;
|
|
#else
|
|
# define SUB(FUNCTION_NAME,PARAMS) void FUNCTION_NAME PARAMS {
|
|
# define END_SUB }
|
|
# define FUNC(RETURNING_TYPE,FUNCTION_NAME,PARAMS) RETURNING_TYPE FUNCTION_NAME PARAMS {
|
|
# define END_FUNC(x) return x; }
|
|
# define RETURN(expr) return expr;
|
|
# define MAIN(argc, argv) FUNC(int, main, (argc, argv))
|
|
# define END_MAIN(x) return x; }
|
|
# define RETURN_MAIN(exit_status) return exit_status;
|
|
#endif // ((!defined(_DISABLE_PERFORMANCE_TRACKING)) || (!defined(_DISABLE_INFO_LOGS)))
|
|
|
|
#define _ELPP_LOG_WRITER(_logger, _level) easyloggingpp::internal::Writer(\
|
|
_logger, easyloggingpp::internal::Aspect::Normal, _level, __func__, __FILE__, __LINE__)
|
|
#define _ELPP_LOG_WRITER_COND(_c, _logger, _level) if (_c) easyloggingpp::internal::Writer(\
|
|
_logger, easyloggingpp::internal::Aspect::Conditional, _level, __func__, __FILE__, __LINE__, _c)
|
|
#define _ELPP_LOG_WRITER_N(_n, _logger, _level) if (easyloggingpp::internal::registeredLoggers->validateCounter(\
|
|
__FILE__, __LINE__, _n)) easyloggingpp::internal::Writer(_logger, easyloggingpp::internal::Aspect::Interval,\
|
|
_level, __func__, __FILE__, __LINE__, true, 0, _n)
|
|
#undef VLOG_IS_ON
|
|
#define VLOG_IS_ON(verboseLevel) verboseLevel <= easyloggingpp::internal::registeredLoggers->constants()->CURRENT_VERBOSE_LEVEL
|
|
// Undef levels to support LOG(LEVEL)
|
|
#undef INFO
|
|
#undef DEBUG
|
|
#undef ERROR
|
|
#undef FATAL
|
|
#undef QA
|
|
#undef TRACE
|
|
#undef VERBOSE
|
|
//
|
|
// Custom loggers - macro names with levels - requires loggerId
|
|
//
|
|
// Undef existing
|
|
#undef CINFO
|
|
#undef CWARNING
|
|
#undef CDEBUG
|
|
#undef CERROR
|
|
#undef CFATAL
|
|
#undef ERROR
|
|
#undef CQA
|
|
#undef CTRACE
|
|
#undef CVERBOSE
|
|
#undef CINFO_IF
|
|
#undef CWARNING_IF
|
|
#undef CDEBUG_IF
|
|
#undef CERROR_IF
|
|
#undef CFATAL_IF
|
|
#undef ERROR_IF
|
|
#undef CQA_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 ERROR_EVERY_N
|
|
#undef CQA_EVERY_N
|
|
#undef CTRACE_EVERY_N
|
|
#undef CVERBOSE_EVERY_N
|
|
// Normal logs
|
|
#if _ELPP_INFO_LOG
|
|
# define CINFO(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Info)
|
|
#else
|
|
# define CINFO(loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_INFO_LOG
|
|
#if _ELPP_WARNING_LOG
|
|
# define CWARNING(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Warning)
|
|
#else
|
|
# define CWARNING(loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_WARNING_LOG
|
|
#if _ELPP_DEBUG_LOG
|
|
# define CDEBUG(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Debug)
|
|
#else
|
|
# define CDEBUG(loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_DEBUG_LOG
|
|
#if _ELPP_ERROR_LOG
|
|
# define CERROR(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Error)
|
|
#else
|
|
# define CERROR(loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_ERROR_LOG
|
|
#if _ELPP_FATAL_LOG
|
|
# define CFATAL(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Fatal)
|
|
#else
|
|
# define CFATAL(loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_FATAL_LOG
|
|
#if _ELPP_QA_LOG
|
|
# define CQA(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::QA)
|
|
#else
|
|
# define CQA(loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_QA_LOG
|
|
#if _ELPP_TRACE_LOG
|
|
# define CTRACE(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Trace)
|
|
#else
|
|
# define CTRACE(loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_TRACE_LOG
|
|
#if _ELPP_VERBOSE_LOG
|
|
# define CVERBOSE(vlevel_, loggerId) easyloggingpp::internal::Writer(loggerId, easyloggingpp::internal::Aspect::Normal, \
|
|
easyloggingpp::Level::Verbose, __func__, __FILE__, __LINE__, true, vlevel_)
|
|
#else
|
|
# define CVERBOSE(vlevel_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_VERBOSE_LOG
|
|
// Conditional logs
|
|
#if _ELPP_INFO_LOG
|
|
# define CINFO_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Info)
|
|
#else
|
|
# define CINFO_IF(condition_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_INFO_LOG
|
|
#if _ELPP_WARNING_LOG
|
|
# define CWARNING_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Warning)
|
|
#else
|
|
# define CWARNING_IF(condition_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_WARNING_LOG
|
|
#if _ELPP_DEBUG_LOG
|
|
# define CDEBUG_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Debug)
|
|
#else
|
|
# define CDEBUG_IF(condition_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_DEBUG_LOG
|
|
#if _ELPP_ERROR_LOG
|
|
# define CERROR_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Error)
|
|
#else
|
|
# define CERROR_IF(condition_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_ERROR_LOG
|
|
#if _ELPP_FATAL_LOG
|
|
# define CFATAL_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Fatal)
|
|
#else
|
|
# define CFATAL_IF(condition_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_FATAL_LOG
|
|
#if _ELPP_QA_LOG
|
|
# define CQA_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::QA)
|
|
#else
|
|
# define CQA_IF(condition_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_QA_LOG
|
|
#if _ELPP_TRACE_LOG
|
|
# define CTRACE_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Trace)
|
|
#else
|
|
# define CTRACE_IF(condition_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_TRACE_LOG
|
|
#if _ELPP_VERBOSE_LOG
|
|
# define CVERBOSE_IF(condition_, vlevel_, loggerId) if (condition_) easyloggingpp::internal::Writer(loggerId, easyloggingpp::internal::Aspect::Conditional, \
|
|
easyloggingpp::Level::Verbose, __func__, __FILE__, __LINE__, condition_, vlevel_)
|
|
#else
|
|
# define CVERBOSE_IF(condition_, vlevel_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_VERBOSE_LOG
|
|
// Interval logs
|
|
#if _ELPP_INFO_LOG
|
|
# define CINFO_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Info)
|
|
#else
|
|
# define CINFO_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_INFO_LOG
|
|
#if _ELPP_WARNING_LOG
|
|
# define CWARNING_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Warning)
|
|
#else
|
|
# define CWARNING_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_WARNING_LOG
|
|
#if _ELPP_DEBUG_LOG
|
|
# define CDEBUG_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Debug)
|
|
#else
|
|
# define CDEBUG_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_DEBUG_LOG
|
|
#if _ELPP_ERROR_LOG
|
|
# define CERROR_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Error)
|
|
#else
|
|
# define CERROR_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_ERROR_LOG
|
|
#if _ELPP_FATAL_LOG
|
|
# define CFATAL_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Fatal)
|
|
#else
|
|
# define CFATAL_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_FATAL_LOG
|
|
#if _ELPP_QA_LOG
|
|
# define CQA_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::QA)
|
|
#else
|
|
# define CQA_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_QA_LOG
|
|
#if _ELPP_TRACE_LOG
|
|
# define CTRACE_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Trace)
|
|
#else
|
|
# define CTRACE_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_TRACE_LOG
|
|
#if _ELPP_VERBOSE_LOG
|
|
# define CVERBOSE_EVERY_N(interval_, vlevel_, loggerId) if (easyloggingpp::internal::registeredLoggers->validateCounter(__FILE__, __LINE__, interval_)) \
|
|
easyloggingpp::internal::Writer(loggerId, easyloggingpp::internal::Aspect::Interval, \
|
|
easyloggingpp::Level::Verbose, __func__, __FILE__, __LINE__, true, vlevel_, interval_)
|
|
#else
|
|
# define CVERBOSE_EVERY_N(interval_, vlevel_, loggerId) easyloggingpp::internal::NullWriter()
|
|
#endif // _ELPP_VERBOSE_LOG
|
|
//
|
|
// Custom Loggers - Requires (level, loggerId)
|
|
//
|
|
// undef existing
|
|
#undef CLOG
|
|
#undef CLOG_VERBOSE
|
|
#undef CVLOG
|
|
#undef CLOG_IF
|
|
#undef CLOG_VERBOSE_IF
|
|
#undef CVLOG_IF
|
|
#undef CLOG_EVERY_N
|
|
#undef CLOG_VERBOSE_EVERY_N
|
|
#undef CVLOG_EVERY_N
|
|
// Normal logs
|
|
#define CLOG(LEVEL, loggerId) C##LEVEL(loggerId)
|
|
#define CLOG_VERBOSE(vlevel, loggerId) CVERBOSE(vlevel, loggerId)
|
|
#define CVLOG(vlevel, loggerId) CVERBOSE(vlevel, loggerId)
|
|
// Conditional logs
|
|
#define CLOG_IF(condition, LEVEL, loggerId) C##LEVEL##_IF(condition, loggerId)
|
|
#define CLOG_VERBOSE_IF(condition, vlevel, loggerId) CVERBOSE_IF(condition, vlevel, loggerId)
|
|
#define CVLOG_IF(condition, vlevel, loggerId) CVERBOSE_IF(condition, vlevel, loggerId)
|
|
// Interval logs
|
|
#define CLOG_EVERY_N(n, LEVEL, loggerId) C##LEVEL##_EVERY_N(n, loggerId)
|
|
#define CLOG_VERBOSE_EVERY_N(n, vlevel, loggerId) CVERBOSE_EVERY_N(n, vlevel, loggerId)
|
|
#define CVLOG_EVERY_N(n, vlevel, loggerId) CVERBOSE_EVERY_N(n, vlevel, loggerId)
|
|
//
|
|
// Default Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros
|
|
//
|
|
// undef existing
|
|
#undef LOG
|
|
#undef LOG_VERBOSE
|
|
#undef VLOG
|
|
#undef LOG_IF
|
|
#undef LOG_VERBOSE_IF
|
|
#undef VLOG_IF
|
|
#undef LOG_EVERY_N
|
|
#undef LOG_VERBOSE_EVERY_N
|
|
#undef VLOG_EVERY_N
|
|
// Normal logs
|
|
#define LOG(LEVEL) CLOG(LEVEL, "trivial")
|
|
#define LOG_VERBOSE(vlevel) CLOG_VERBOSE(vlevel, "trivial")
|
|
#define VLOG(vlevel) CVLOG(vlevel, "trivial")
|
|
// Conditional logs
|
|
#define LOG_IF(condition, LEVEL) CLOG_IF(condition, LEVEL, "trivial")
|
|
#define LOG_VERBOSE_IF(condition, vlevel) CLOG_VERBOSE_IF(condition, vlevel, "trivial")
|
|
#define VLOG_IF(condition, vlevel) CVLOG_IF(condition, vlevel, "trivial")
|
|
// Interval logs
|
|
#define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, "trivial")
|
|
#define LOG_VERBOSE_EVERY_N(n, vlevel) CLOG_VERBOSE_EVERY_N(n, vlevel, "trivial")
|
|
#define VLOG_EVERY_N(n, vlevel) CVLOG_EVERY_N(n, vlevel, "trivial")
|
|
//
|
|
// Default Loggers macro using C##LEVEL("trivial")
|
|
//
|
|
// undef existing
|
|
#undef LINFO
|
|
#undef LWARNING
|
|
#undef LDEBUG
|
|
#undef LERROR
|
|
#undef LFATAL
|
|
#undef LQA
|
|
#undef LTRACE
|
|
#undef LVERBOSE
|
|
#undef LINFO_IF
|
|
#undef LWARNING_IF
|
|
#undef LDEBUG_IF
|
|
#undef LERROR_IF
|
|
#undef LFATAL_IF
|
|
#undef LQA_IF
|
|
#undef LTRACE_IF
|
|
#undef LVERBOSE_IF
|
|
#undef LINFO_EVERY_N
|
|
#undef LWARNING_EVERY_N
|
|
#undef LDEBUG_EVERY_N
|
|
#undef LERROR_EVERY_N
|
|
#undef LFATAL_EVERY_N
|
|
#undef LQA_EVERY_N
|
|
#undef LTRACE_EVERY_N
|
|
#undef LVERBOSE_EVERY_N
|
|
// Normal logs
|
|
#define LINFO CINFO("trivial")
|
|
#define LWARNING CWARNING("trivial")
|
|
#define LDEBUG CDEBUG("trivial")
|
|
#define LERROR CERROR("trivial")
|
|
#define LFATAL CFATAL("trivial")
|
|
#define LQA CQA("trivial")
|
|
#define LTRACE CTRACE("trivial")
|
|
#define LVERBOSE(level) CVERBOSE(level, "trivial")
|
|
// Conditional logs
|
|
#define LINFO_IF(condition) CINFO_IF(condition, "trivial")
|
|
#define LWARNING_IF(condition) CWARNING_IF(condition, "trivial")
|
|
#define LDEBUG_IF(condition) CDEBUG_IF(condition, "trivial")
|
|
#define LERROR_IF(condition) CERROR_IF(condition, "trivial")
|
|
#define LFATAL_IF(condition) CFATAL_IF(condition, "trivial")
|
|
#define LQA_IF(condition) CQA_IF(condition, "trivial")
|
|
#define LTRACE_IF(condition) CTRACE_IF(condition, "trivial")
|
|
#define LVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "trivial")
|
|
// Interval logs
|
|
#define LINFO_EVERY_N(n) CINFO_EVERY_N(n, "trivial")
|
|
#define LWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "trivial")
|
|
#define LDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "trivial")
|
|
#define LERROR_EVERY_N(n) CERROR_EVERY_N(n, "trivial")
|
|
#define LFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "trivial")
|
|
#define LQA_EVERY_N(n) CQA_EVERY_N(n, "trivial")
|
|
#define LTRACE_EVERY_N(n) CTRACE_EVERY_N(n, "trivial")
|
|
#define LVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "trivial")
|
|
//
|
|
// Default Loggers macro using C##LEVEL("business")
|
|
//
|
|
// undef existing
|
|
#undef BINFO
|
|
#undef BWARNING
|
|
#undef BDEBUG
|
|
#undef BERROR
|
|
#undef BFATAL
|
|
#undef BQA
|
|
#undef BTRACE
|
|
#undef BVERBOSE
|
|
#undef BINFO_IF
|
|
#undef BWARNING_IF
|
|
#undef BDEBUG_IF
|
|
#undef BERROR_IF
|
|
#undef BFATAL_IF
|
|
#undef BQA_IF
|
|
#undef BTRACE_IF
|
|
#undef BVERBOSE_IF
|
|
#undef BINFO_EVERY_N
|
|
#undef BWARNING_EVERY_N
|
|
#undef BDEBUG_EVERY_N
|
|
#undef BERROR_EVERY_N
|
|
#undef BFATAL_EVERY_N
|
|
#undef BQA_EVERY_N
|
|
#undef BTRACE_EVERY_N
|
|
#undef BVERBOSE_EVERY_N
|
|
// Normal logs
|
|
#define BINFO CINFO("business")
|
|
#define BWARNING CWARNING("business")
|
|
#define BDEBUG CDEBUG("business")
|
|
#define BERROR CERROR("business")
|
|
#define BFATAL CFATAL("business")
|
|
#define BQA CQA("business")
|
|
#define BTRACE CTRACE("business")
|
|
#define BVERBOSE(level) CVERBOSE(level, "business")
|
|
// Conditional logs
|
|
#define BINFO_IF(condition) CINFO_IF(condition, "business")
|
|
#define BWARNING_IF(condition) CWARNING_IF(condition, "business")
|
|
#define BDEBUG_IF(condition) CDEBUG_IF(condition, "business")
|
|
#define BERROR_IF(condition) CERROR_IF(condition, "business")
|
|
#define BFATAL_IF(condition) CFATAL_IF(condition, "business")
|
|
#define BQA_IF(condition) CQA_IF(condition, "business")
|
|
#define BTRACE_IF(condition) CTRACE_IF(condition, "business")
|
|
#define BVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "business")
|
|
// Interval logs
|
|
#define BINFO_EVERY_N(n) CINFO_EVERY_N(n, "business")
|
|
#define BWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "business")
|
|
#define BDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "business")
|
|
#define BERROR_EVERY_N(n) CERROR_EVERY_N(n, "business")
|
|
#define BFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "business")
|
|
#define BQA_EVERY_N(n) CQA_EVERY_N(n, "business")
|
|
#define BTRACE_EVERY_N(n) CTRACE_EVERY_N(n, "business")
|
|
#define BVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "business")
|
|
//
|
|
// Default Loggers macro using C##LEVEL("security")
|
|
//
|
|
// undef existing
|
|
#undef SINFO
|
|
#undef SWARNING
|
|
#undef SDEBUG
|
|
#undef SERROR
|
|
#undef SFATAL
|
|
#undef SQA
|
|
#undef STRACE
|
|
#undef SVERBOSE
|
|
#undef SINFO_IF
|
|
#undef SWARNING_IF
|
|
#undef SDEBUG_IF
|
|
#undef SERROR_IF
|
|
#undef SFATAL_IF
|
|
#undef SQA_IF
|
|
#undef STRACE_IF
|
|
#undef SVERBOSE_IF
|
|
#undef SINFO_EVERY_N
|
|
#undef SWARNING_EVERY_N
|
|
#undef SDEBUG_EVERY_N
|
|
#undef SERROR_EVERY_N
|
|
#undef SFATAL_EVERY_N
|
|
#undef SQA_EVERY_N
|
|
#undef STRACE_EVERY_N
|
|
#undef SVERBOSE_EVERY_N
|
|
// Normal logs
|
|
#define SINFO CINFO("security")
|
|
#define SWARNING CWARNING("security")
|
|
#define SDEBUG CDEBUG("security")
|
|
#define SERROR CERROR("security")
|
|
#define SFATAL CFATAL("security")
|
|
#define SQA CQA("security")
|
|
#define STRACE CTRACE("security")
|
|
#define SVERBOSE(level) CVERBOSE(level, "security")
|
|
// Conditional logs
|
|
#define SINFO_IF(condition) CINFO_IF(condition, "security")
|
|
#define SWARNING_IF(condition) CWARNING_IF(condition, "security")
|
|
#define SDEBUG_IF(condition) CDEBUG_IF(condition, "security")
|
|
#define SERROR_IF(condition) CERROR_IF(condition, "security")
|
|
#define SFATAL_IF(condition) CFATAL_IF(condition, "security")
|
|
#define SQA_IF(condition) CQA_IF(condition, "security")
|
|
#define STRACE_IF(condition) CQA_IF(condition, "security")
|
|
#define SVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "security")
|
|
// Interval logs
|
|
#define SINFO_EVERY_N(n) CINFO_EVERY_N(n, "security")
|
|
#define SWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "security")
|
|
#define SDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "security")
|
|
#define SERROR_EVERY_N(n) CERROR_EVERY_N(n, "security")
|
|
#define SFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "security")
|
|
#define SQA_EVERY_N(n) CQA_EVERY_N(n, "security")
|
|
#define STRACE_EVERY_N(n) CTRACE_EVERY_N(n, "security")
|
|
#define SVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "security")
|
|
//
|
|
// Default Loggers macro using C##LEVEL("performance")
|
|
//
|
|
// undef existing
|
|
#undef PINFO
|
|
#undef PWARNING
|
|
#undef PDEBUG
|
|
#undef PERROR
|
|
#undef PFATAL
|
|
#undef PQA
|
|
#undef PTRACE
|
|
#undef PVERBOSE
|
|
#undef PINFO_IF
|
|
#undef PWARNING_IF
|
|
#undef PDEBUG_IF
|
|
#undef PERROR_IF
|
|
#undef PFATAL_IF
|
|
#undef PQA_IF
|
|
#undef PTRACE_IF
|
|
#undef PVERBOSE_IF
|
|
#undef PINFO_EVERY_N
|
|
#undef PWARNING_EVERY_N
|
|
#undef PDEBUG_EVERY_N
|
|
#undef PERROR_EVERY_N
|
|
#undef PFATAL_EVERY_N
|
|
#undef PQA_EVERY_N
|
|
#undef PTRACE_EVERY_N
|
|
#undef PVERBOSE_EVERY_N
|
|
// Normal logs
|
|
#define PINFO CINFO("performance")
|
|
#define PWARNING CWARNING("performance")
|
|
#define PDEBUG CDEBUG("performance")
|
|
#define PERROR CERROR("performance")
|
|
#define PFATAL CFATAL("performance")
|
|
#define PQA CQA("performance")
|
|
#define PTRACE CTRACE("performance")
|
|
#define PVERBOSE(level) CVERBOSE(level, "performance")
|
|
// Conditional logs
|
|
#define PINFO_IF(condition) CINFO_IF(condition, "performance")
|
|
#define PWARNING_IF(condition) CWARNING_IF(condition, "performance")
|
|
#define PDEBUG_IF(condition) CDEBUG_IF(condition, "performance")
|
|
#define PERROR_IF(condition) CERROR_IF(condition, "performance")
|
|
#define PFATAL_IF(condition) CFATAL_IF(condition, "performance")
|
|
#define PQA_IF(condition) CQA_IF(condition, "performance")
|
|
#define PTRACE_IF(condition) CQA_IF(condition, "performance")
|
|
#define PVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "performance")
|
|
// Interval logs
|
|
#define PINFO_EVERY_N(n) CINFO_EVERY_N(n, "performance")
|
|
#define PWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "performance")
|
|
#define PDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "performance")
|
|
#define PERROR_EVERY_N(n) CERROR_EVERY_N(n, "performance")
|
|
#define PFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "performance")
|
|
#define PQA_EVERY_N(n) CQA_EVERY_N(n, "performance")
|
|
#define PTRACE_EVERY_N(n) CTRACE_EVERY_N(n, "performance")
|
|
#define PVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "performance")
|
|
// Undefine macros that are not needed anymore
|
|
#undef _ELPP_ASSEMBLY_SUPPORTED
|
|
#undef _ELPP_STREAM
|
|
#undef _ELPP_MUTEX_LOCK_GNU_ASM
|
|
#undef _ELPP_MUTEX_UNLOCK_GNU_ASM
|
|
#undef _ELPP_ENABLE_MUTEX
|
|
#undef _ENABLE_EASYLOGGING
|
|
#undef __EASYLOGGINGPP_SUPPRESS_UNSED
|
|
#undef _ELPP_DEBUG_LOG
|
|
#undef _ELPP_INFO_LOG
|
|
#undef _ELPP_WARNING_LOG
|
|
#undef _ELPP_ERROR_LOG
|
|
#undef _ELPP_FATAL_LOG
|
|
#undef _ELPP_QA_LOG
|
|
#undef _ELPP_VERBOSE_LOG
|
|
#undef _ELPP_TRACE_LOG
|
|
#undef _INITIALIZE_EASYLOGGINGPP
|
|
#undef _START_EASYLOGGINGPP
|
|
#undef _ELPP_COUNTER
|
|
#undef _ELPP_COUNTER_POSITION
|
|
#define _INITIALIZE_EASYLOGGINGPP \
|
|
namespace easyloggingpp { \
|
|
namespace internal { \
|
|
ScopedPointer<RegisteredLoggers> registeredLoggers( \
|
|
new RegisteredLoggers()); \
|
|
} \
|
|
}
|
|
#define _START_EASYLOGGINGPP(argc, argv) easyloggingpp::Loggers::setApplicationArguments(argc, argv);
|
|
#define _ELPP_COUNTER easyloggingpp::internal::registeredLoggers->counters()->get(__FILE__, __LINE__)
|
|
#define _ELPP_COUNTER_POSITION (_ELPP_COUNTER == NULL ? 0 : _ELPP_COUNTER->position())
|
|
} // easyloggingpp
|
|
#endif // EASYLOGGINGPP_H
|