﷽
→ 最新版本
→ 变更日志
→ 样品
概述 为什么还要另一个图书馆 特点一览 入门 下载 快速入门 安装(可选) 设置应用程序参数 配置 等级 配置 使用配置文件 使用 el::Configurations 类 使用串联配置 默认配置 全局配置 记录格式说明符 日期/时间格式说明符 自定义格式说明符 记录标志 应用参数 配置宏 读取配置 记录 基本的 条件日志记录 偶尔记录 printf 类似日志记录 网络日志记录 详细日志记录 基本的 有条件和偶尔 详细级别 检查详细日志记录是否已打开 虚拟模块 注册新记录器 取消注册记录器 填充现有记录器 ID 共享日志存储库 额外功能 绩效追踪 条件绩效跟踪 利用绩效跟踪数据 日志文件轮换 碰撞处理 安装自定义崩溃处理程序 堆栈跟踪 多线程 检查宏 记录 perror() 使用系统日志 STL记录 支持的模板 Qt 日志记录 增强日志记录 wxWidgets 日志记录 扩展库 记录你自己的课程 记录第三方类 手动刷新和滚动日志文件 日志调度回调 记录器注册回调 异步日志记录 辅助类 贡献 提交补丁 报告错误 兼容性 构建矩阵 执照 免责声明
Easylogging++ 是用于 C++ 应用程序的单头高效日志库。它非常强大、高度可扩展并且可根据用户的要求进行配置。它提供了编写自己的接收器的能力(通过称为LogDispatchCallback
的功能)。该库目前被 github 和其他开源源代码控制管理网站上的数百个开源项目使用。
本手册适用于 Easylogging++ v9.97.1。其他版本请参考github上对应的release。
您可能还对残留日志服务器感兴趣。
转到顶部
如果您正在使用 C++ 开发小型实用程序或大型项目,这个库会很方便。它基于单个标头,只需要链接到单个源文件。 (最初它是仅标头的,在问题 #445 中更改为使用源文件。您仍然可以在 v9.89 中使用仅标头)。
该库的设计考虑了多种想法(即可移植性、性能、可用性、功能和易于设置)。
为什么还要另一个图书馆?嗯,答案非常简单,在编写时使用它,这样您就可以解决问题(如果有)或在 github 上提出问题。除此之外,我个人还没有看到任何基于单头的日志库具有这样的设计,您可以在旅途中进行配置,将其扩展到您的需求并获得快速的性能。我见过其他 C++ 的单头日志库,但它们要么使用外部库,例如 boost 或 Qt 来支持某些功能,如线程、正则表达式或日期等。该库内置了所有内容以防止使用外部库,并不是说我不喜欢这些库,事实上我喜欢它们,但因为并非所有项目都使用这些库,所以我不能冒险依赖它们。
转到顶部
Easylogging++ 功能丰富,包含典型和高级开发人员在编写软件时需要的许多功能;
转到顶部
从最新版本下载最新版本
对于其他版本,请访问版本页面。如果您的应用程序不支持 C++11,请考虑使用 v8.91。这是 C++98 和 C++03 的稳定版本,只是缺少一些功能。
转到顶部
为了开始使用 Easylogging++,您可以遵循三个简单的步骤:
easylogging++.h
和easylogging++.cc
)# include " easylogging++.h "
INITIALIZE_EASYLOGGINGPP
int main ( int argc, char * argv[]) {
LOG (INFO) << " My first info log using default logger " ;
return 0 ;
}
现在编译使用
g++ main.cc easylogging++.cc -o prog -std=c++11
就这么简单!请注意, INITIALIZE_EASYLOGGINGPP
应该使用一次,并且只能使用一次,否则最终会出现编译错误。这是几个extern
变量的定义。这意味着每个应用程序只能定义一次。放置此初始化语句的最佳位置是在定义int main(int, char**)
函数的文件中,就在最后一个包含语句之后。
如果您想在系统范围内安装此标头,您可以通过以下方式执行此操作:
mkdir build
cd build
cmake -Dtest=ON ../
make
make test
make install
Easylogging++ cmake 支持以下选项,您可以使用-D<option>=ON
打开这些选项
lib_utc_datetime
- 定义ELPP_UTC_DATETIME
build_static_lib
- 为 Easylogging++ 构建静态库尽管如此,您仍然需要easylogging++.cc
文件才能进行编译。仅对于标头,请检查 v9.89 及更低版本。
或者,您可以使用 vcpkg 依赖项管理器下载并安装 easyloggingpp:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install easyloggingpp
vcpkg 中的 easyloggingpp 端口由 Microsoft 团队成员和社区贡献者保持最新状态。如果版本已过时,请在 vcpkg 存储库上创建问题或拉取请求。
转到顶部
始终建议将应用程序参数传递给 Easylogging++。 Easylogging++ 的某些功能要求您设置应用程序参数,例如,设置详细级别或 vmodules 的详细日志记录(稍后解释)。为此,您可以使用辅助宏或辅助类;
int main ( int argc, char * argv[]) {
START_EASYLOGGINGPP (argc, argv);
...
}
转到顶部
为了开始配置日志库,您必须了解严重性级别。 Easylogging++ 故意不使用分层日志记录,以便完全控制启用和禁用的内容。话虽如此,仍然可以选择使用LoggingFlag::HierarchicalLogging
来使用分层日志记录。 Easylogging++ 有以下级别(按层次级别排序)
等级 | 描述 |
---|---|
全球的 | 代表所有级别的通用级别。在为所有级别设置全局配置时很有用。 |
痕迹 | 可用于回溯某些事件的信息 - 比调试日志更有用。 |
调试 | 对于开发人员调试应用程序最有用的信息事件。仅当未定义 NDEBUG(对于非 VC++)或定义 _DEBUG(对于 VC++)时才适用。 |
致命的 | 非常严重的错误事件,可能会导致应用程序中止。 |
错误 | 错误信息但会继续应用程序继续运行。 |
警告 | 表示应用程序中出现错误的信息,但应用程序将继续运行。 |
信息 | 主要用于表示当前应用程序的进度。 |
冗长 | 非常有用且随详细日志记录级别而变化的信息。详细日志记录不适用于分层日志记录。 |
未知 | 仅适用于分层日志记录,用于完全关闭日志记录。 |
转到顶部
Easylogging++ 易于配置。有三种可能的方法可以做到这一点,
配置可以通过Configurations
类在运行时加载的文件来完成。该文件具有以下格式;
* LEVEL:
CONFIGURATION NAME = "VALUE" ## Comment
ANOTHER CONFIG NAME = "VALUE"
级别名称以星号 (*) 开头,以冒号 (:) 结尾。强烈建议以Global
级别启动配置文件,以便文件中未指定的任何配置将自动使用Global
中的配置。例如,如果您在Global
中设置Filename
,并且希望所有级别使用相同的文件名,则不要为每个级别显式设置它,库将自动使用Global
中的配置值。下表包含配置文件支持的配置。
配置名称 | 类型 | 描述 |
---|---|---|
Enabled | 布尔值 | 确定是否启用记录器的相应级别。您可以使用el::Level::Global 禁用所有日志 |
To_File | 布尔值 | 是否将相应的日志写入日志文件 |
To_Standard_Output | 布尔值 | 是否将日志写入标准输出,例如终端或命令提示符 |
Format | 字符* | 确定相应级别和记录器的日志记录格式/模式。 |
Filename | 字符* | 确定将日志写入相应级别和记录器的日志文件(完整路径) |
Subsecond_Precision | 单位 | 指定亚秒精度(以前称为“毫秒宽度”)。宽度可以在范围 (1-6) 内 |
Performance_Tracking | 布尔值 | 确定是否启用性能跟踪。这不取决于记录器或级别。除非指定,否则性能跟踪始终使用“性能”记录器 |
Max_Log_File_Size | 尺寸_t | 如果相应级别的日志文件大小 >= 指定大小,日志文件将被截断。 |
Log_Flush_Threshold | 尺寸_t | 指定在刷新挂起的日志数据之前要保留的日志条目数 |
请不要在评论中的任何地方使用双引号,您可能会出现意外的行为。
配置文件示例
* GLOBAL:
FORMAT = "%datetime %msg"
FILENAME = "/tmp/logs/my.log"
ENABLED = true
TO_FILE = true
TO_STANDARD_OUTPUT = true
SUBSECOND_PRECISION = 6
PERFORMANCE_TRACKING = true
MAX_LOG_FILE_SIZE = 2097152 ## 2MB - Comment starts with two hashes (##)
LOG_FLUSH_THRESHOLD = 100 ## Flush after every 100 logs
* DEBUG:
FORMAT = "%datetime{%d/%M} %func %msg"
上面示例中的配置文件内容很简单。我们从GLOBAL
级别开始,以便覆盖所有级别。任何显式定义的后续级别都将覆盖GLOBAL
中的配置。例如,除DEBUG
之外的所有级别都具有相同的格式,即日期时间和日志消息。对于DEBUG
级别,我们只有日期(包含日期和月份)、源函数和日志消息。 DEBUG
的其余配置均使用GLOBAL
中的配置。另外,请注意上面DEBUG
格式中的{%d/%M}
,如果不指定日期格式,则使用默认格式。日期/时间的默认值为%d/%M/%Y %h:%m:%s,%g
有关这些格式说明符的更多信息,请参阅下面的日期/时间格式说明符部分
# include " easylogging++.h "
INITIALIZE_EASYLOGGINGPP
int main ( int argc, const char ** argv) {
// Load configuration from file
el::Configurations conf ( " /path/to/my-conf.conf " );
// Reconfigure single logger
el::Loggers::reconfigureLogger ( " default " , conf);
// Actually reconfigure all loggers instead
el::Loggers::reconfigureAllLoggers (conf);
// Now all the loggers will use configuration from file
}
您的配置文件可以转换为
el::Configurations
对象(使用构造函数),可以在需要的地方使用(如上面的示例)。
转到顶部
您可以设置配置或重置配置;
# include " easylogging++.h "
INITIALIZE_EASYLOGGINGPP
int main ( int argc, const char ** argv) {
el::Configurations defaultConf;
defaultConf. setToDefault ();
// Values are always std::string
defaultConf. set (el::Level::Info,
el::ConfigurationType::Format, " %datetime %level %msg " );
// default logger uses default configurations
el::Loggers::reconfigureLogger ( " default " , defaultConf);
LOG (INFO) << " Log using default file " ;
// To set GLOBAL configurations you may use
defaultConf. setGlobally (
el::ConfigurationType::Format, " %date %msg " );
el::Loggers::reconfigureLogger ( " default " , defaultConf);
return 0 ;
}
配置只需设置一次。如果您对默认配置感到满意,也可以使用它。
转到顶部
内联配置意味着您可以在std::string
中设置配置,但请确保添加所有换行符等。不建议这样做,因为它总是很混乱。
el::Configurations c;
c.setToDefault();
c.parseFromText( " *GLOBAL: n FORMAT = %level %msg " );
上面的代码仅设置 Configurations 对象,您仍然需要使用此配置重新配置记录器。
转到顶部
如果您希望对现有和未来的记录器进行配置,可以使用el::Loggers::setDefaultConfigurations(el::Configurations& configurations, bool configureExistingLoggers = false)
。当您的工作规模相当大或使用已经使用 Easylogging++ 的第三方库时,这非常有用。任何新创建的记录器都将使用默认配置。如果您还想配置现有记录器,可以将第二个参数设置为true
(默认为false
)。
转到顶部
Level::Global
与全局配置无关,它是您可以为所有/或某些记录器注册配置,甚至使用配置文件注册新记录器的概念。配置文件的语法为:
-- LOGGER ID ## Case sensitive
## Everything else is same as configuration file
-- ANOTHER LOGGER ID
## Configuration for this logger
记录器 ID 以两个破折号开头。一旦编写了全局配置文件,您就可以使用单个函数配置所有记录器(并注册新记录器);
int main ( void ) {
// Registers new and configures it or
// configures existing logger - everything in global.conf
el::Loggers::configureFromGlobal ( " global.conf " );
// .. Your prog
return 0 ;
}
请注意,如果不定义其配置,则无法使用全局配置注册新记录器。您必须至少定义单个配置。注册记录器的其他方法将在下面的“记录”部分讨论。
转到顶部
您可以使用以下说明符自定义日志记录格式:
说明符 | 替换为 |
---|---|
%logger | 记录器ID |
%thread | 线程 ID - 如果可用,则使用 std::thread,否则在 Windows 上使用 GetCurrentThreadId() |
%thread_name | 使用Helpers::setThreadName 设置当前线程的名称(从中运行setThreadName )。请参阅线程名称示例 |
%level | 严重级别(信息、调试、错误、警告、致命、详细、跟踪) |
%levshort | 严重级别(简称,I 表示信息,分别表示 D、E、W、F、V、T) |
%vlevel | 详细级别(适用于详细日志记录) |
%datetime | 日期和/或时间 - 模式可自定义 - 请参阅下面的日期/时间格式说明符 |
%user | 用户当前正在运行的应用程序 |
%host | 计算机名称 应用程序正在运行 |
%file * | 源文件的文件名(完整路径) - 此功能取决于编译器的__FILE__ 宏的可用性 |
%fbase * | 源文件的文件名(仅基本名称) |
%line * | 源行号 - 此功能取决于编译的__LINE__ 宏的可用性 |
%func * | 记录功能 |
%loc * | 源文件名和日志记录行号(用冒号分隔) |
%msg | 实际日志消息 |
% | 转义字符(例如,%%level 将写入 %level) |
__LINE__
、 __FILE__
等转到顶部
您可以使用以下说明符自定义日期/时间格式
说明符 | 替换为 |
---|---|
%d | 月份中的某一天(以零填充) |
%a | 一周中的某一天 - 简短(周一、周二、周三、周四、周五、周六、周日) |
%A | 一周中的某一天 - 长(星期一、星期二、星期三、星期四、星期五、星期六、星期日) |
%M | 月份(零填充) |
%b | 月份 - 短期(一月、二月、三月、四月、五月、六月、七月、八月、九月、十月、十一月、十二月) |
%B | 月 - 长(一月、二月、三月、四月、五月、六月、七月、八月、九月、十月、十一月、十二月) |
%y | 年份 - 两位数(13、14 等) |
%Y | 年份 - 四位数(2013、2014 等) |
%h | 小时(12 小时格式) |
%H | 小时(24 小时制) |
%m | 分钟(零填充) |
%s | 第二个(零填充) |
%g | 亚秒部分(精度由 ConfigurationType::SubsecondPrecision 配置) |
%F | 上午/下午指定 |
% | 转义字符 |
请注意,日期/时间最多不得超过30
字符。
转到顶部
您还可以指定自己的格式说明符。为此,您可以使用el::Helpers::installCustomFormatSpecifier
。一个完美的例子是 TCP 服务器应用程序的%ip_addr
;
const char * getIp ( const el::LogMessage*) {
return " 192.168.1.1 " ;
}
int main ( void ) {
el::Helpers::installCustomFormatSpecifier ( el::CustomFormatSpecifier ( " %ip_addr " , getIp));
el::Loggers::reconfigureAllLoggers (el::ConfigurationType::Format, " %datetime %level %ip_addr : %msg " );
LOG (INFO) << " This is request from client " ;
return 0 ;
}
转到顶部
形成日志记录的某些部分,您可以设置日志记录标志;以下是支持的标志:
旗帜 | 描述 |
---|---|
NewLineForContainer (1) | 确保每个容器日志条目都有新行 |
AllowVerboseIfModuleNotSpecified (2) | 确保如果使用 -vmodule 并且未指定模块,则允许通过该模块进行详细日志记录。假设参数为 -vmodule=main*=3 并且正在从名为 Something.cpp 的文件写入详细日志,那么如果启用此标志,则将写入日志,否则将不允许写入。注意:这样做违背了 -vmodule 的目的 |
LogDetailedCrashReason (4) | 默认情况下处理崩溃时,也会记录详细的崩溃原因(默认情况下禁用)(问题#90) |
DisableApplicationAbortOnFatalLog (8) | 允许在使用 FATAL 级别记录时禁用应用程序中止。请注意,这不适用于默认的崩溃处理程序,因为应用程序应在处理崩溃信号后中止。 (默认情况下不添加)(问题#119) |
ImmediateFlush (16) | 使用每个日志条目刷新日志(性能敏感)- 默认情况下禁用 |
StrictLogFileSizeCheck (32) | 确保每个日志都检查日志文件大小 |
ColoredTerminalOutput (64) | 如果终端支持,终端输出将会是彩色的。 |
MultiLoggerSupport (128) | 启用对使用多个记录器记录单个消息的支持。 (例如, CLOG(INFO, "default", "network") << This will be logged using default and network loggers; ) |
DisablePerformanceTrackingCheckpointComparison (256) | 禁用检查点比较 |
DisableVModules (512) | 禁用 vmodules 的使用 |
DisableVModulesExtensions (1024) | 禁用 vmodules 扩展。这意味着如果您有一个 vmodule -vmodule=main*=4 ,它将涵盖以 main 开头的所有内容,就好像您没有定义此定义一样,您将涵盖以 main 开头并以以下扩展名之一结尾的任何文件; .h .c .cpp .cc .cxx .-inl-.h .hxx .hpp。请注意,以下 vmodule 不正确 -vmodule=main.=4 ,未定义此宏,因为这将检查 main..c,注意双点。如果您希望它有效,请查看上面的日志记录标志:AllowVerboseIfModuleNotSpecified '?'和 '' 支持通配符 |
HierarchicalLogging (2048) | 启用分层日志记录。这不适用于详细日志记录。 |
CreateLoggerAutomatically (4096) | 不可用时自动创建记录器。 |
AutoSpacing (8192) | 自动添加空格。例如, LOG(INFO) << "DODGE" << "THIS!"; 将输出“DODGE THIS!” |
FixedTimeFormat (16384) | 仅适用于性能跟踪 - 这可以避免格式化时间。例如, 1001 ms 将按原样记录,而不是将其格式化为1.01 sec |
IgnoreSigInt (32768) | 当应用程序崩溃时忽略中断信号 |
您可以使用 static el::Loggers::addFlag
和el::Loggers::removeFlag
设置/取消设置这些标志。您可以使用el::Loggers::hasFlag
检查某个标志是否可用,所有这些函数都采用强类型枚举el::LoggingFlag
您可以使用
--logging-flags
命令行参数设置这些标志。您需要通过定义宏ELPP_LOGGING_FLAGS_FROM_ARG
来启用此功能(您需要确保使用START_EASYLOGGINGPP(argc, argv)
来配置参数)。
您还可以使用
ELPP_DEFAULT_LOGGING_FLAGS
设置默认(初始)标志,并为初始标志设置数值
转到顶部
下表将解释您可以用来定义某些行为的所有命令行参数;您需要在main(int, char**)
函数中使用START_EASYLOGGINGPP(argc, argv)
来初始化应用程序参数。
争论 | 描述 |
---|---|
-v | 激活最大详细程度 |
--v=2 | 激活详细级别,最高可达 2 级(有效范围:0-9) |
--verbose | 激活最大详细程度 |
-vmodule=MODULE_NAME | 激活从 main 开始到级别 1 的文件的详细程度,其余文件取决于日志记录标志AllowVerboseIfModuleNotSpecified 请参阅上面的日志记录标志部分。两个模块可以用逗号分隔。请注意,按照检查详细日志记录参数的优先顺序,vmodules 排在最后,例如,如果应用程序参数中的 -v 位于 vmodules 之前,则 vmodules 将被忽略。 |
--logging-flags=3 | 设置日志记录标志。在示例ie, 3 中,它将日志记录标志设置为NewLineForContainer 和AllowVerboseIfModuleNotSpecified 。有关更多详细信息和值,请参阅上面的日志记录标志部分。请参阅宏部分以禁用此功能。 |
--default-log-file=FILE | 为现有和未来的记录器设置默认日志文件。您可能需要考虑定义ELPP_NO_DEFAULT_LOG_FILE 以防止在预处理期间创建默认的空日志文件。请参阅宏部分以禁用此功能。 |
转到顶部
一些日志记录选项可以通过宏来设置,这是一个深思熟虑的决定,例如,如果我们定义了ELPP_THREAD_SAFE
,则所有线程安全功能都将启用,否则将禁用(确保线程安全的开销随之而来)。为了便于记忆并防止可能的冲突,所有宏都以ELPP_
开头
注意:所有宏都可以通过以下方式之一定义:
使用编译器的-D
选项定义宏,例如在g++
的情况下,您将执行g++ source.cpp ... -DELPP_SYSLOG -DELPP_THREAD_SAFE ...
(推荐方式)
在"easylogging++.h"
中定义宏(在其他文件中定义宏不起作用)
宏名称 | 描述 |
---|---|
ELPP_DEBUG_ASSERT_FAILURE | 第一次断言失败时中止应用程序。此断言是由于无效输入造成的,例如无效的配置文件等。 |
ELPP_UNICODE | 记录时启用 Unicode 支持。需要START_EASYLOGGINGPP |
ELPP_THREAD_SAFE | 启用线程安全 - 确保 Linux 的 -lpthread 链接。 |
ELPP_FORCE_USE_STD_THREAD | 强制使用 C++ 标准库进行线程处理(仅在使用ELPP_THREAD_SAFE 时有用 |
ELPP_FEATURE_CRASH_LOG | 仅适用于海湾合作委员会。在应用程序崩溃时启用堆栈跟踪 |
ELPP_DISABLE_DEFAULT_CRASH_HANDLING | 禁用默认的崩溃处理。您可以使用 el::Helpers::setCrashHandler 来使用您自己的处理程序。 |
ELPP_DISABLE_LOGS | 禁用所有日志 - (预处理) |
ELPP_DISABLE_DEBUG_LOGS | 禁用调试日志 - (预处理) |
ELPP_DISABLE_INFO_LOGS | 禁用信息日志 -(预处理) |
ELPP_DISABLE_WARNING_LOGS | 禁用警告日志 - (预处理) |
ELPP_DISABLE_ERROR_LOGS | 禁用错误日志 - (预处理) |
ELPP_DISABLE_FATAL_LOGS | 禁用致命日志 - (预处理) |
ELPP_DISABLE_VERBOSE_LOGS | 禁用详细日志 -(预处理) |
ELPP_DISABLE_TRACE_LOGS | 禁用跟踪日志 -(预处理) |
ELPP_FORCE_ENV_VAR_FROM_BASH | 如果找不到环境变量,则强制使用替代的 bash 命令来查找值,例如, whoami 作为用户名。 (请勿将此宏与LD_PRELOAD 一起用于已经使用 Easylogging++ 的库,否则您将最终导致进程堆栈溢出( popen )(有关详细信息,请参阅问题 #87)) |
ELPP_DEFAULT_LOG_FILE | 您想要在其中创建初始文件的完整文件名。您需要用引号嵌入此宏的值,例如-DELPP_DEFAULT_LOG_FILE='"logs/el.gtest.log"' 请注意单引号内的双引号,双引号是const char* 的值,单引号指定的值宏 |
ELPP_NO_LOG_TO_FILE | 最初禁用记录到文件 |
ELPP_NO_DEFAULT_LOG_FILE | 如果您不想使用默认日志文件初始化库,请定义此宏。对于 UNIX 和 Windows,这将记录到空设备。在其他平台上,您可能会收到错误,并且需要使用ELPP_DEFAULT_LOG_FILE 。 (欢迎其他平台空设备PR) |
ELPP_FRESH_LOG_FILE | 无论何时创建日志文件,都不要附加日志文件(请小心使用,因为这可能会给某些用户带来一些意外的结果) |
ELPP_DEBUG_ERRORS | 如果您希望找出 Easylogging++ 因配置或其他原因引发的内部错误,您可以通过定义此宏来启用它们。您将在标准输出(即终端或命令提示符)上收到错误。 |
ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS | 强制禁用自定义格式说明符 |
ELPP_DISABLE_LOGGING_FLAGS_FROM_ARG | 强制禁用使用命令行参数设置日志记录标志的功能 |
ELPP_DISABLE_LOG_FILE_FROM_ARG | 强制禁用从命令行参数设置默认日志文件的功能 |
ELPP_WINSOCK2 | 在 Windows 系统上,当定义WIN32_LEAN_AND_MEAN 时,强制使用winsock2.h 而不是winsock.h |
ELPP_CUSTOM_COUT (高级) | 解析为一个值,例如#define ELPP_CUSTOM_COUT qDebug() 或#define ELPP_CUSTOM_COUT std::cerr 。这将使用标准输出的值(而不是使用std::cout |
ELPP_CUSTOM_COUT_LINE (高级) | 与ELPP_CUSTOM_COUT 一起使用来定义如何使用自定义 cout 编写日志行。例如, #define ELPP_CUSTOM_COUT_LINE(msg) QString::fromStdString(msg).trimmed() |
ELPP_NO_CHECK_MACROS | 不要定义CHECK宏 |
ELPP_NO_DEBUG_MACROS | 不要定义DEBUG宏 |
ELPP_UTC_DATETIME | 使用 UTC 时间而不是本地时间(本质上使用gmtime 而不是localtime 和系列函数) |
ELPP_NO_GLOBAL_LOCK | 不要在调度时锁定整个存储。这应该小心使用。请参阅问题 #580 |
转到顶部
如果您希望读取某些记录器的配置,可以通过使用 Logger 类中的typedConfigurations()
函数来实现。
el::Logger* l = el::Loggers::getLogger( " default " );
bool enabled = l-> typedConfigurations ()->enabled(el::Level::Info);
// Or to read log format/pattern
std::string format =
l-> typedConfigurations ()->logFormat(el::Level::Info).format();
转到顶部
easylogging++ 中的登录是使用宏集合完成的。这是为了让用户更容易,并防止他们了解不必要的事情如何完成的更多细节。
为您提供了两个可用于写入日志的基本宏:
LOG(LEVEL)
CLOG(LEVEL, logger ID)
LOG
使用“默认”记录器,而在 CLOG(自定义 LOG)中您指定记录器 ID。对于级别,请参阅上面的配置 - 级别部分。根据您的需要,不同的记录器可能有不同的配置,您也可以编写自定义宏来访问自定义记录器。您还可以使用不同的宏来进行详细日志记录,这将在下面的部分中进行解释。这是在初始化 easylogging++ 后使用这些宏的非常简单的示例。
LOG (INFO) << "This is info log";
CLOG (ERROR, " performance " ) << "This is info log using performance logger";
还有另一种方法可以使用相同的宏,即LOG
(和关联的宏)。这是您使用已注册的记录器 ID 定义宏ELPP_DEFAULT_LOGGER
和ELPP_DEFAULT_PERFORMANCE_LOGGER
,现在当您使用LOG
宏时,它会自动使用指定的记录器而不是default
记录器。请注意,这应该在源文件而不是头文件中定义。这样,当我们包含标头时,我们就不会意外地使用无效的记录器。
一个简单的例子在这里
# ifndef ELPP_DEFAULT_LOGGER
# define ELPP_DEFAULT_LOGGER " update_manager "
# endif
# ifndef ELPP_DEFAULT_PERFORMANCE_LOGGER
# define ELPP_DEFAULT_PERFORMANCE_LOGGER ELPP_DEFAULT_LOGGER
# endif
# include " easylogging++.h "
UpdateManager::UpdateManager {
_TRACE; // Logs using LOG(TRACE) provided logger is already registered - i.e, update_manager
LOG (INFO) << " This will log using update_manager logger as well " ;
}
# include " easylogging++.h "
UpdateManager::UpdateManager {
_TRACE; // Logs using LOG(TRACE) using default logger because no `ELPP_DEFAULT_LOGGER` is defined unless you have it in makefile
}
您还可以直接使用
Logger
类来写入日志。此功能在支持可变参数模板的编译器上可用。您可以通过查看samples/STL/logger-log-functions.cpp
来探索更多信息。
转到顶部
Easylogging++ 提供了日志记录的某些方面,其中之一是条件日志记录,即仅当满足某些条件时才会写入日志。这在某些情况下非常方便。辅助宏以 _IF 结尾;
LOG_IF(condition, LEVEL)
CLOG_IF(condition, LEVEL, logger ID)
LOG_IF (condition, INFO) << "Logged if condition is true";
LOG_IF ( false , WARNING) << "Never logged";
CLOG_IF ( true , INFO, " performance " ) << "Always logged (performance logger)"
相同的宏可用于以V
开头的详细日志记录,即VLOG_IF
和CVLOG_IF
。有关详细信息,请参阅下面的详细日志记录部分。根据您的需要,您可以拥有任意复杂的条件。
转到顶部
偶尔记录日志是使用 Easylogging++ 进行日志记录的另一个有用的方面。这意味着如果命中了特定次数或特定次数的一部分,例如每第 10 次命中、第 100 次命中或第 2 次命中,就会写入日志。辅助宏以_EVERY_N
结尾;
LOG_EVERY_N(n, LEVEL)
CLOG_EVERY_N(n, LEVEL, logger ID)
还有一些其他基于点击次数的记录方式。这些有用的宏是
LOG_AFTER_N(n, LEVEL)
;仅当命中次数达到n
时才记录LOG_N_TIMES(n, LEVEL)
;记录n次 for ( int i = 1 ; i <= 10 ; ++i) {
LOG_EVERY_N ( 2 , INFO) << " Logged every second iter " ;
}
// 5 logs written; 2, 4, 6, 7, 10
for ( int i = 1 ; i <= 10 ; ++i) {
LOG_AFTER_N ( 2 , INFO) << " Log after 2 hits; " << i;
}
// 8 logs written; 3, 4, 5, 6, 7, 8, 9, 10
for ( int i = 1 ; i <= 100 ; ++i) {
LOG_N_TIMES ( 3 , INFO) << " Log only 3 times; " << i;
}
// 3 logs writter; 1, 2, 3
相同版本的宏可用于仅
DEBUG
模式,这些宏以D
(用于调试)开头,后跟相同的名称。例如,DLOG
仅在调试模式下记录(即,当定义_DEBUG
或未定义NDEBUG
时)
转到顶部
printf
类似日志记录对于支持 C++11 可变参数模板的编译器,可以使用“printf”等日志记录功能。这是通过使用Logger
类来完成的。此功能是线程和类型安全的(因为我们不使用任何宏,如LOG(INFO)
等)
这分两步完成:
el::Loggers::getLogger(<logger_id>);
拉取已注册的记录器与printf
的唯一区别是使用这些函数进行日志记录需要每个参数使用%v
(这是为了类型安全);而不是自定义格式说明符。你可以通过%%v
来逃避这个问题
以下是各种函数签名:
info(const char*, const T&, const Args&...)
warn(const char*, const T&, const Args&...)
error(const char*, const T&, const Args&...)
debug(const char*, const T&, const Args&...)
fatal(const char*, const T&, const Args&...)
trace(const char*, const T&, const Args&...)
verbose(int vlevel, const char*, const T&, const Args&...)
// Use default logger
el::Logger* defaultLogger = el::Loggers::getLogger( " default " );
// STL logging (`ELPP_STL_LOGGING` should be defined)
std::vector< int > i;
i.push_back( 1 );
defaultLogger-> warn ( " My first ultimate log message %v %v %v " , 123 , 222 , i);
// Escaping
defaultLogger-> info ( " My first ultimate log message %% %%v %v %v " , 123 , 222 );
%file
、%func
%line
和%loc
格式说明符不能与printf
一起使用(如日志记录)。
转到顶部
您可以将消息发送到网络。但您必须使用日志调度程序 API 来实现您自己的方式。我们为此目的编写了完整的工作示例。请参阅发送到网络示例
转到顶部
详细日志记录在每个软件中都很有用,可以记录比平常更多的信息。对于故障排除非常有用。以下是详细记录特定宏;
VLOG(verbose-level)
CVLOG(verbose-level, logger ID)
转到顶部
详细日志记录还具有条件和偶尔的日志记录方面,即
VLOG_IF(condition, verbose-level)
CVLOG_IF(condition, verbose-level, loggerID)
VLOG_EVERY_N(n, verbose-level)
CVLOG_EVERY_N(n, verbose-level, loggerID)
VLOG_AFTER_N(n, verbose-level)
CVLOG_AFTER_N(n, verbose-level, loggerID)
VLOG_N_TIMES(n, verbose-level)
CVLOG_N_TIMES(n, verbose-level, loggerID)
转到顶部
详细级别是详细级别,范围为 1-9。除非您为其设置应用程序参数,否则详细级别将不会处于活动状态。请通读应用程序参数部分以了解有关详细日志记录的更多信息。
为了动态更改详细级别,请使用Loggers::setVerboseLevel(base::type::VerboseLevel)
又名Loggers::setVerboseLevel(int)
函数。 (您可以通过Loggers::verboseLevel()
检查当前的详细级别
转到顶部
您可以使用宏VLOG_IS_ON(verbose-level)
来检查指定详细级别的源文件是否启用了某些日志记录。这会返回一个布尔值,您可以将其嵌入到 if 条件中。
if (VLOG_IS_ON( 2 )) {
// Verbosity level 2 is on for this file
}
转到顶部
VModule 是详细日志记录的功能(如上表所述),您可以通过模块/源文件指定详细程度。以下是一些带有解释的示例;下面的任何 vmodule 都以-vmodule=
开头,并且未设置LoggingFlag::DisableVModulesExtensions
标志。通过添加标志LoggingFlag::DisableVModules
可以完全禁用 Vmodule
带有LoggingFlag::AllowVerboseIfModuleNotSpecified
标志的示例;
main=3,parser*=4
:
main{.h, .c, .cpp, .cc, .cxx, -inl.h, .hxx, .hpp}
parser{.h, .c, .cpp, .cc, .cxx, -inl.h, .hxx, .hpp}