中文文档
BqLog是一款轻量级、高性能的日志系统,应用于《王者荣耀》等项目中,目前已成功部署并运行顺利。
Windows 64 位
苹果系统
Linux
iOS系统
Android(X86_64、arm64-v8a、armeabi-v7a)
Unix(在FreeBSD上通过测试)
C++
爪哇
科特林
C#
与现有的开源日志记录库相比,BqLog 提供了显着的性能优势(请参阅基准)。它不仅适用于服务器和客户端,而且与移动设备高度兼容。
内存消耗低,在10个线程、20,000,000条日志条目的Benchmark情况下,BqLog本身消耗的内存不到1MB。
提供高性能、高压缩的实时日志格式
可以在游戏引擎( Unity
、 Unreal
)中正常使用,支持Unreal提供的常见类型。
支持UTF-8
、 UTF-16
、 UTF-32
字符和字符串,以及常见的参数类型,如 bool、float、double 以及各种长度和类型的整数
支持C++20
format specifications
异步日志记录支持崩溃审查以避免数据丢失(受XLog启发)
体积极小,Android编译后动态库仅200k左右
在 Java 和 C# 中不会生成额外的堆分配,避免在运行时不断创建新对象
仅依赖于标准C语言库和平台API,并且可以在Android的ANDROID_STL = none
模式下编译
支持C++11
及以后的编译标准,可以在-Wall -Wextra -pedantic -Werror的严格要求下编译
编译模块基于CMake
,提供不同平台的编译脚本,使用方便
支持自定义参数类型
对代码建议非常友好
为什么 BqLog 这么快 - 高性能实时压缩日志格式
为什么BqLog这么快-高并发环形缓冲区
将 BqLog 集成到您的项目中
简单演示
架构概述
主流程API使用说明
1-创建日志对象
2-检索日志对象
3-记录消息
4-其他API
同步和异步日志记录
1. 异步日志记录的线程安全
追加器简介
1. 控制台Appender
2. 文本文件追加器
3. CompressedFileAppender(强烈推荐)
4.RawFileAppender
配置说明
1. 完整示例
2. 详细说明
二进制格式 Appender 的离线解码
构建说明
1. 库构建
2. 演示构建和运行
3. 自动化测试运行说明
4. 基准测试运行说明
高级使用主题
1. 无堆分配
2. 具有类别支持的日志对象
3、程序异常退出时的数据保护
4.关于NDK和ANDROID_STL=无
5. 自定义参数类型
6. 在虚幻引擎中使用BqLog
基准
1. 基准说明
2. BqLog C++ 基准代码
3. BqLog Java 基准代码
4.Log4j基准代码
5. 基准测试结果
BqLog 可以以多种形式集成到您的项目中。对于C++,它支持动态库、静态库和源文件。对于 Java 和 C#,它支持带有包装器源代码的动态库。以下是包含 BqLog 的方法:
代码存储库包含位于 /dist/dynamic_lib/ 中的预编译动态库文件。要使用库文件将 BqLog 集成到您的项目中,您需要执行以下操作:
选择与您的平台对应的动态库文件并将其添加到项目的构建系统中。
将 /dist/dynamic_lib/include 目录复制到您的项目中并将其添加到包含目录列表中。 (如果您使用的是 XCode 的 .framework 库,则可以跳过此步骤,因为 .framework 文件已包含头文件)。
代码存储库包含位于 /dist/static_lib/ 中的预编译静态库文件。要使用库文件将 BqLog 集成到您的项目中,您需要执行以下操作:
选择与您的平台对应的静态库文件并将其添加到项目的构建系统中。
将 /dist/static_lib/include 目录复制到您的项目中并将其添加到包含目录列表中。 (如果您使用的是 XCode 的 .framework 库,则可以跳过此步骤,因为 .framework 文件已包含头文件)。
BqLog还支持直接将源代码包含到您的项目中进行编译。要使用源代码集成 BqLog,请按照以下步骤操作:
将 /src 目录复制到您的项目中作为源代码参考。
将 /include 目录复制到您的项目中并将其添加到包含目录列表中。
如果在 Visual Studio 中编译 Windows 版本,请将 /Zc:__cplusplus 添加到编译选项,以确保正确确定当前 C++ 编译器标准支持。
如果使用 Android NDK 中的源代码,请参阅 4. 关于 NDK 和 ANDROID_STL = none 以了解重要注意事项。
在 C# 中,BqLog 可以通过本机动态库和 C# 包装器使用,支持 Mono、Microsoft CLR 和 Unity 引擎。 Unity 与 Mono 和 IL2CPP 模式兼容。要在 C# 中使用 BqLog,请按照下列步骤操作:
从/dist/dynamic_lib/中选择与您的平台对应的动态库文件并将其添加到您的项目中(对于Unity,请参阅Unity导入和配置插件)。
将 /wrapper/csharp/src 中的源代码文件复制到您的项目中。
在Java中,BqLog可以通过本机动态库和Java Wrapper使用,支持常见的JVM环境和Android。要将 BqLog 集成到 JVM 中,请执行以下步骤:
从/dist/dynamic_lib/中选择与您的平台对应的动态库文件并将其添加到您的项目中。
将 /wrapper/java/src 中的源代码文件复制到您的项目中。
(可选)如果您打算从 NDK 调用 BqLog,请将 /dist/dynamic_lib/include 目录复制到您的项目中并将其添加到包含目录列表中。
以下代码将向您的控制台输出超过 1000 条日志(如果在 Android 上,则为 ADB Logcat)
#如果已定义(WIN32) #include#endif#include <字符串>#include int main() { #if Defined(WIN32) // 将 Windows 命令行切换为 UTF-8,因为 BqLog 以 UTF-8 编码输出所有最终文本,以避免显示问题 SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); #endif // 该字符串是日志配置。这里它配置了一个带有一个名为appender_0的appender(输出目标)的记录器,它输出到控制台。 std::string config = R"( # 该appender的输出目标是控制台appenders_config.appender_0.type=console # 该appender使用本地时间作为时间戳appenders_config.appender_0.time_zone=默认本地时间 # 该appender输出这6个级别的日志(中间没有空格)appenders_config.appender_0.levels=[verbose,debug,info,warning,error,fatal] )"; bq::log log = bq::log::create_log("my_first_log", config); // 使用配置创建日志对象 for(int i = 0; i < 1024; ++i) { log.info("这是一条信息测试日志,格式字符串为UTF-8,param int:{}, param bool :{}, param string8:{}, param string16:{}, param string32:{} , param float:{}", i, true, "utf8-string", u"utf16-string", U"utf32-string", 4.3464f); } log.error(U"这是一个错误测试日志,格式字符串为UTF-32"); bq::log::force_flush_all_logs(); // BqLog默认为异步输出。为了确保日志在程序退出之前可见,请强制刷新以同步输出一次。 返回0; }
使用 System.Text;使用 System;public class demo_main { public static void Main(string[] args) { Console.OutputEncoding = Encoding.UTF8; Console.InputEncoding = Encoding.UTF8; string config = @" # 该appender的输出目标是控制台appenders_config.appender_0.type=console # 该appender使用本地时间作为时间戳 ppenders_config.appender_0.time_zone=默认本地时间 # 该appender输出这6个级别的日志(中间没有空格)之间)appenders_config.appender_0.levels=[详细,调试,信息,警告,错误,致命]“; bq.log log = bq.log.create_log("my_first_log", config); // 使用配置创建日志对象 for (int i = 0; i < 1024; ++i) { log.info("这是一条信息测试日志,格式字符串为UTF-16,param int:{}, param bool :{}, param string:{}, param float:{}", i, true, "字符串文本”,4.3464f); } bq.log.force_flush_all_logs(); Console.ReadKey(); }}
public class demo_main { public static void main(String[] args) { // TODO 自动生成的方法存根 String config = """ # 此appender 的输出目标是控制台appenders_config.appender_0.type=console # 此appender 使用本地时间for timestamps appenders_config.appender_0.time_zone=default local time # 该appender输出这6个级别的日志(中间没有空格) appenders_config.appender_0.levels=[详细、调试、信息、警告、错误、致命] """; bq.log log = bq.log.create_log("my_first_log", config); // 使用配置创建一个日志对象 for (int i = 0; i < 1024; ++i) { log.info("这是一条信息测试日志,格式字符串为 UTF-16,param int:{}, param bool :{}, param string:{}, param float:{}", i, true, “字符串文本”,4.3464f); bq.log.force_flush_all_logs(); } }
上图清楚地说明了BqLog的基本结构。图的右侧是 BqLog 库的内部实现,左侧是您的程序和代码。您的程序可以使用提供的包装器(针对不同语言的面向对象的 API)调用 BqLog。在该图中,创建了两个日志:一个名为“Log A”,另一个名为“Log B”。每个日志都附加到一个或多个 Appender。 Appender可以理解为日志内容的输出目标。这可以是控制台(Android 的 ADB Logcat 日志)、文本文件,甚至是压缩日志文件或常规二进制日志格式文件等特殊格式。
在同一个进程中,不同语言的包装器可以访问同一个 Log 对象。例如,如果在 Java 中创建了名为 Log A 的 Log 对象,则也可以通过名称 Log A 从 C++ 端访问和使用它。
在极端情况下,例如在 Android 系统上运行的 Unity 开发的游戏,您可能会在同一个应用程序中涉及 Java、Kotlin、C# 和 C++ 语言。它们都可以共享同一个 Log 对象。您可以使用create_log在Java端创建Log,然后使用get_log_by_name在其他语言中访问它。
注意:以下 API 在 bq::log(或 bq.log)类中声明。为了节省空间,仅列出 C++ API。 Java和C#中的API是相同的,这里不再赘述。
在 C++ 中, bq::string
是 BqLog 库中的 UTF-8 字符串类型。您还可以传入 c 样式字符串,例如 char 或std::string
或std::string_view
,它们将自动隐式转换。
可以使用 create_log 静态函数创建日志对象。其声明如下:
//C++ API ////// 创建日志对象 /// /// 如果日志名称为空字符串,bqLog 会自动为您分配一个唯一的日志名称。如果日志名称已经存在,它将返回之前存在的日志对象,并用新的配置覆盖之前的配置。 /// 日志配置字符串 ///一个日志对象,如果创建失败,其 is_valid() 方法将返回 false static log create_log(const bq::string& log_name, const bq::string& config_content);
该代码通过传入日志对象的名称和配置字符串来创建日志对象。日志配置可以参考配置说明。以下是需要注意的几个关键点:
无论是C#还是Java,返回的日志对象永远不会为null。但是,由于配置错误或其他原因,可能会创建无效的日志对象。因此,您应该使用 is_valid() 函数来检查返回的对象。对无效对象执行操作可能会导致程序崩溃。
如果传递空字符串作为日志名称,bqLog 将自动生成唯一的日志名称,例如“AutoBqLog_1”。
对已存在的同名日志对象调用 create_log 不会创建新的日志对象,而是会用新的配置覆盖以前的配置。但此过程中有些参数无法修改;详细信息请参见配置说明。
除了在NDK中使用时(参考4.关于NDK和ANDROID_STL = none),其他情况下都可以使用该API直接在全局或静态变量中初始化日志对象。
如果已经在其他地方创建了日志对象,则可以直接使用 get_log_by_name 函数获取创建的日志对象。
//C++ API ////// 通过名称获取日志对象 /// /// 要查找的日志对象的名称 ///一个日志对象,如果没有找到指定名称的日志对象,则其 is_valid() 方法将返回 false static log get_log_by_name(const bq::string& log_name);
您还可以使用此函数来初始化全局变量或静态函数中的日志对象。但需要注意的是,必须确保指定名称的日志对象已经存在。否则,返回的日志对象将无法使用,其 is_valid() 方法将返回 false。
///核心日志功能,有6个日志级别: ///verbose, debug, info, warning, error, fatal templatebq::enable_if_t ::value, bool> verbose(const STR& log_content) const; 模板<类型名称 STR, 类型名称...参数> bq::enable_if_t ::value, bool> verbose(const STR& log_format_content, const Args&... args) const; 模板<类型名称 STR> bq::enable_if_t ::value, bool> debug(const STR& log_content) const; 模板<类型名称 STR, 类型名称...参数> bq::enable_if_t ::value, bool> debug(const STR& log_format_content, const Args&... args) const; 模板<类型名称 STR> bq::enable_if_t ::value, bool> info(const STR& log_content) const; 模板<类型名称 STR, 类型名称...参数> bq::enable_if_t ::value, bool> info(const STR& log_format_content, const Args&... args) const; 模板<类型名称 STR> bq::enable_if_t ::value, bool> warning(const STR& log_content) const; 模板<类型名称 STR, 类型名称...参数> bq::enable_if_t ::value, bool> 警告(const STR& log_format_content, const Args&... args) const; 模板<类型名称 STR> bq::enable_if_t ::value, bool> error(const STR& log_content) const; 模板<类型名称 STR, 类型名称...参数> bq::enable_if_t ::value, bool> error(const STR& log_format_content, const Args&... args) const; 模板<类型名称 STR> bq::enable_if_t ::value, bool> fatal(const STR& log_content) const; 模板<类型名称 STR, 类型名称...参数> bq::enable_if_t ::value, bool> fatal(const STR& log_format_content, const Args&... args) const;
记录消息时,要注意三个要点:
可以看到,我们的日志分为六个级别:verbose、debug、info、warning、error、fatal,与Android一致。它们的重要性依次增加。当输出到控制台时,它们会以不同的颜色显示。
STR参数与printf的第一个参数类似,可以是各种常见的字符串类型,包括:
Java 的 java.lang.String
C# 的字符串
C++ 的 C 风格字符串和std::string
的各种编码( char*
、 char16_t*
、 char32_t*
、 wchar_t*
、 std::string
、 std::u8string
、 std::u16string
、 std::u32string
、 std::wstring
、 std::string_view
、 std::u16string_view
、 std::u32string_view
、 std::wstring_view
甚至自定义字符串类型,可以参考自定义参数类型)
您可以在 STR 参数后添加各种参数。这些参数将被格式化为 STR 中的指定位置,遵循类似于 C++20 的 std::format 的规则(除了缺乏对位置参数和日期时间格式的支持)。例如,使用单个 {} 表示参数的默认格式,而 {:.2f} 指定格式化浮点数的精度。尽量使用格式化参数输出日志,而不是手动拼接字符串。此方法对于性能和压缩格式存储而言是最佳的。
目前支持的参数类型包括:
空指针(输出为空)
指针(以 0x 开头的十六进制地址输出)
布尔值
单字节字符(char)
双字节字符(char16_t、wchar_t、C# 的 char、Java 的 char)
四字节字符(char32_t 或 wchar_t)
8 位整数
8 位无符号整数
16 位整数
16 位无符号整数
32 位整数
32 位无符号整数
64 位整数
64 位无符号整数
32 位浮点数
64 位浮点数
C++ 中其他未知的 POD 类型(大小限制为 1、2、4 或 8 字节,分别视为 int8、int16、int32 和 int64)
字符串,包括STR参数中提到的所有字符串类型
C# 和 Java 中的任何类或对象(输出其 ToString() 字符串)
自定义参数类型,详见自定义参数类型
还有其他常用的 API 可以完成特定的任务。详细的API说明请参考bq_log/bq_log.h,以及Java和C#中的bq.log类。以下是一些需要强调的关键 API:
////// 取消初始化BqLog,请在程序存在之前调用此函数。 /// static void uninit();
建议在退出程序或卸载使用BqLog的自行实现的动态库之前执行uninit()
,否则在某些特定情况下退出时可能会卡住。
////// 如果bqLog是异步的,程序崩溃可能会导致缓冲区中的日志无法持久化到磁盘。 /// 如果启用此功能,bqLog 将在发生崩溃时尝试强制刷新缓冲区中的日志。但是, /// 此功能并不保证成功,并且仅支持 POSIX 系统。 /// 静态无效enable_auto_crash_handle();
详细介绍请参见程序异常退出数据保护
////// 同步刷新所有日志对象的缓冲区 /// 以确保调用后处理缓冲区中的所有数据。 /// 静态无效force_flush_all_logs(); ////// 同步刷新此日志对象的缓冲区 /// 以确保调用后处理缓冲区中的所有数据。 /// 无效force_flush();
由于 bqLog 默认使用异步日志记录,因此有时您可能希望立即同步并输出所有日志。在这种情况下,您需要强制调用force_flush()。
////// 注册一个回调,每当输出控制台日志消息时都会调用该回调。 /// 这可用于外部系统监控控制台日志输出。 /// /// static void register_console_callback(bq::type_func_ptr_console_callback 回调); ////// 取消注册控制台回调。 /// /// static void unregister_console_callback(bq::type_func_ptr_console_callback 回调);
ConsoleAppender 的输出会发送到 Android 上的控制台或 ADB Logcat 日志,但这可能无法涵盖所有情况。例如,在自定义游戏引擎或自定义 IDE 中,提供了一种机制来为每个控制台日志输出调用回调函数。这允许您在程序中的任何位置重新处理和输出控制台日志。
注意:不要在控制台回调中输出任何同步的 BQ 日志,因为这很容易导致死锁。
////// 启用或禁用控制台附加器缓冲区。 /// 由于我们的包装器可以在 C# 和 Java 虚拟机中运行,并且我们不想直接从本机线程调用回调, /// 我们可以启用此选项。这样,所有控制台输出都将保存在缓冲区中,直到我们获取它们为止。 /// /// ///static void set_console_buffer_enable(bool enable); /// /// 以线程安全的方式从控制台追加器缓冲区中获取和删除日志条目。 /// 如果控制台追加器缓冲区不为空,则将为此日志条目调用 on_console_callback 函数。 /// 请确保回调函数中不要输出同步的BQ日志。 /// /// 如果控制台追加器缓冲区不为空,则为获取的日志条目调用回调函数 ///如果控制台追加器缓冲区不为空并且已获取日志条目; static bool fetch_and_remove_console_buffer(bq::type_func_ptr_console_callback on_console_callback); 否则返回 False。
除了通过控制台回调拦截控制台输出之外,您还可以主动获取控制台日志输出。有时,我们可能不希望控制台日志输出通过回调来实现,因为您不知道回调将来自哪个线程(例如,在某些 C# 虚拟机或 JVM 中,当控制台日志输出时,虚拟机可能正在执行垃圾收集)调用回调,这可能会导致挂起或崩溃)。
这里使用的方法涉及通过set_console_buffer_enable
启用控制台缓冲区。这会导致每个控制台日志输出都存储在内存中,直到我们主动调用fetch_and_remove_console_buffer
来检索它。因此,如果您选择使用此方法,请记住及时获取并清除日志,以避免内存未释放。
注意:不要在控制台回调中输出任何同步的 BQ 日志,因为这很容易导致死锁。
其他注意事项:如果您在 IL2CPP 环境中使用此代码,请确保 on_console_callback 被标记为静态不安全,并使用 [MonoPInvokeCallback(typeof(type_console_callback))] 属性进行修饰。
////// 修改日志配置,但有些字段不能修改,如buffer_size。 /// /// ///bool reset_config(const bq::string& config_content);
有时您可能想要修改程序中日志的配置。除了重新创建日志对象来覆盖配置(参见创建日志对象),您还可以使用重置接口。但请注意,并非所有配置项都可以通过这种方式修改。详细信息请参见配置说明
////// 暂时禁用或启用特定的 Appender。 /// /// /// void set_appenders_enable(const bq::string&appender_name, bool enable) ;
默认情况下,配置中的 Appender 是活动的,但这里提供了一种机制来临时禁用和重新启用它们。
////// 仅在配置快照时有效。 /// 它将快照缓冲区解码为文本。 /// /// 每个日志的时间戳是GMT时间还是当地时间 ///解码后的快照缓冲区 bq::string take_snapshot(bool use_gmt_time) const;
有时,某些特殊功能需要输出日志的最后部分,这可以使用快照功能来完成。要启用此功能,您首先需要在日志配置中激活快照并设置最大缓冲区大小(以字节为单位)。此外,您需要指定要为快照过滤的日志级别和类别(可选)。详细配置请参见快照配置。当需要快照时,调用 take_snapshot() 将返回包含存储在快照缓冲区中的最新日志条目的格式化字符串。在 C++ 中,类型为bq::string
,可以隐式转换为std::string
。
命名空间bq{命名空间工具{ //这是一个用于解码二进制日志格式的实用程序类。 //使用时,首先创建一个log_decoder对象, //然后调用其decode函数进行解码。 //每次成功调用后, //您可以使用 get_last_decoded_log_entry() 检索解码结果。 //每次调用都会解码一个日志条目。 结构体log_decoder { 私人的: bq::字符串解码文本_; bq::appender_decode_result result_ = bq::appender_decode_result::成功; uint32_t句柄_ = 0; public: ////// 创建一个log_decoder对象,每个log_decoder对象对应一个二进制日志文件。 /// /// 二进制日志文件的路径,可以是相对路径或绝对路径 log_decoder(const bq::string& log_file_path); 〜log_decoder(); ////// 解码日志条目。每次调用此函数只会解码 1 个日志条目 /// ///解码结果,appender_decode_result::eof 表示整个日志文件已解码 bq::appender_decode_result 解码(); ////// 获取最后的解码结果 /// ///bq::appender_decode_result get_last_decode_result() const; /// /// 获取最后一次解码日志条目内容 /// ///const bq::string& get_last_decoded_log_entry() const; }; } }
这是一个实用程序类,可以在运行时解码二进制类型 Appender 输出的日志文件,例如 CompressedFileAppender 和 RawFileAppender。
要使用它,首先创建一个 log_decoder 对象。然后,每次调用decode()函数时,它都会按顺序解码一个日志条目。如果返回结果为bq::appender_decode_result::success,则可以调用get_last_decoded_log_entry()获取最后一条解码日志条目的格式化文本内容。如果结果是bq::appender_decode_result::eof,则表示所有日志都已读取完毕。
BqLog 允许您通过 thread_mode 设置来配置日志对象是同步还是异步。这两种模式的主要区别如下:
同步记录 | 异步日志记录 | |
---|---|---|
行为 | 调用logging函数后,日志立即写入对应的appender中。 | 调用日志函数后,日志并没有立即写入;相反,它被移交给工作线程进行定期处理。 |
表现 | 低,因为写入日志的线程需要阻塞并等待日志写入相应的appender,然后才能从日志记录函数返回。 | 高,因为写入日志的线程不需要等待实际输出,可以在记录后立即返回。 |
线程安全 | 高,但要求日志功能执行过程中不修改日志参数。 | 高,但要求日志功能执行过程中不修改日志参数。 |
关于异步日志记录的一个常见误解是它的线程安全性较低,用户担心在工作线程处理日志时参数可能会被回收。例如:
{ const char str_array[5] = {'T', 'E', 'S', 'T', '�'}; const char* str_ptr = str_array; log_obj.info("这是测试参数:{},{}",str_array,str_ptr); }
在上面的例子中, str_array
存储在堆栈上,一旦退出作用域,它的内存就不再有效。用户可能会担心,如果使用异步日志记录,当工作线程处理日志时, str_array
和str_ptr
将成为无效变量。
但不会出现这种情况,因为BqLog在执行info
函数的过程中将所有参数内容复制到其内部ring_buffer
中。一旦info
函数返回,就不再需要str_array
或str_ptr
等外部变量。此外, ring_buffer
不会存储const char*
指针地址,而是始终存储整个字符串。
真正的潜在问题出现在以下场景中:
静态 std::string global_str = "你好世界"; // 这是一个被多个线程修改的全局变量。void thread_a() { log_obj.info("这是测试参数:{}", global_str); }
如果在info
函数执行过程中global_str
的内容发生变化,可能会导致未定义的行为。 BqLog会尽力防止崩溃,但无法保证最终输出的正确性。
Appender代表日志输出目标。 bqLog 中 Appender 的概念与 Log4j 中基本相同。目前bqLog提供了以下几种Appender:
这个Appender的输出目标是控制台,包括Android的ADB和iOS上对应的控制台。文本编码为UTF-8。
该Appender直接以UTF-8文本格式输出日志文件。
此 Appender 以压缩格式输出日志文件,这是highly recommended format by bqLog
。它在所有 Appender 中具有最高的性能,并生成最小的输出文件。但是,最终文件需要解码。解码可以是运行时解码,也可以是离线解码。
该Appender将二进制日志内容从内存直接输出到文件。它的性能比TextFileAppender高,但是消耗更多的存储空间。最终文件需要解码。解码可以是运行时解码,也可以是离线解码。不建议使用此Appender。
下面对各种Appender进行综合比较:
姓名 | 输出目标 | 直接可读 | 输出性能 | 输出尺寸 |
---|---|---|---|---|
控制台附加程序 | 安慰 | ✔ | 低的 | - |
文本文件附加器 | 文件 | ✔ | 低的 | 大的 |
压缩文件附加器 | 文件 | ✘ | 高的 | 小的 |
原始文件附加器 | 文件 | ✘ | 中等的 | 大的 |
配置是指create_log和reset_config函数中的配置字符串。该字符串使用属性文件格式并支持 # 注释(但请记住以 # 开始新行作为注释)。
下面是一个完整的例子:
# 该配置设置了一个日志对象,总共有5个Appender,其中包括两个TextFileAppender,输出到两个不同的文件。 # 第一个Appender名为appender_0,类型为ConsoleAppenderappenders_config.appender_0.type=console#appender_0的时区为系统本地时间appenders_config.appender_0.time_zone=默认本地时间#appender_0会输出全部6个级别的日志(注意:应该有日志级别之间不能有空格,否则解析失败)appenders_config.appender_0.levels=[verbose,debug,info,warning,error,fatal]# 第二个Appender名为appender_1,类型为TextFileAppenderappenders_config.appender_1.type= text_file#appender_1的时区是GMT,即UTC+0appenders_config.appender_1.time_zone=gmt# appender_1 只输出 info 及以上级别的日志,其他都会被忽略appenders_config.appender_1.levels=[info,warning,error,fatal]#appender_1 的路径将在程序的相对 bqLog 目录中,文件名以 normal 开头,后跟日期和 .log 扩展名# 在 iOS 上,它将保存在 /var/mobile/Containers/Data/Application/[APP]/Library/Caches/bqLog# 上Android,会保存在 [android.content.Context.getExternalFilesDir()]/bqLogappenders_config.appender_1.file_name=bqLog/normal# 最大文件大小为 10,000,000 字节;如果超过,将创建一个新文件appenders_config.appender_1.max_file_size=10000000# 超过十天的文件将被清理appenders_config.appender_1.expire_time_days=10# 如果输出的总大小超过100,000,000字节,将从以下时间开始清理文件oldappenders_config.appender_1.capacity_limit=100000000# 第三个Appender名为appender_2,类型为TextFileAppenderappenders_config.appender_2.type=text_file#appender_2将输出所有级别的日志appenders_config.appender_2.levels=[all]#appender_2的路径将在程序的相对 bqLog 目录,文件名以new_normal,后跟日期和.log扩展名appenders_config.appender_2.file_name=bqLog/new_normal#该选项仅在Android上有效,将日志保存在内部存储目录中,即[android.content.Context.getFilesDir()]/bqLogappenders_config .appender_2.is_in_sandbox=true# 第四个Appender名为appender_3,类型为compressedFileAppenderappenders_config.appender_3.type=compressed_file#appender_3将输出所有级别的日志appenders_config.appender_3.levels=[all]#appender_3的路径将在程序的绝对路径~/bqLog目录下,文件名以compress_log开头,后面是日期和 .logcompr extensionappenders_config.appender_3.file_name=~/bqLog/compress_log# 第五个Appender名为appender_4,类型为RawFileAppenderappenders_config.appender_4.type=raw_file#appender_4默认禁用,稍后可以使用set_appenders_enable启用appenders_config.appender_4.enable=false#appender_4将输出所有级别的logsappenders_config.appender_4.levels=[all]#appender_4的路径将位于程序的相对bqLog目录中,文件名以raw_log开头,后跟日期和.lograw扩展名appenders_config.appender_4.file_name=bqLog/raw_log#日志将仅当其类别以 ModuleA、ModuleB.SystemC 开头时才被处理,否则全部将被忽略(类别的概念在高级使用主题稍后)appenders_config.appender_4.categories_mask=[ModuleA,ModuleB.SystemC]# 异步缓冲区总大小为 65535 字节;具体含义稍后解释log.buffer_size=65535#日志的可靠性级别为正常;具体含义稍后解释log.reliable_level=normal#日志只有其类别符合以下三个通配符才会被处理,否则全部被忽略(Category的概念在后面的高级使用主题中详细解释)log.categories_mask= [*default,ModuleA,ModuleB.SystemC]# 这是异步日志;异步日志是性能最高、推荐的日志类型log.thread_mode=async#如果日志级别为error或fatal,则在每个日志条目中包含调用堆栈信息log.print_stack_levels=[error,fatal]#启用快照功能,快照缓存大小为64Ksnapshot .buffer_size=65536# 快照中只会记录info和error级别的日志snapshot.levels=[info,error]# 只记录类别以ModuleA开头的日志, ModuleB.SystemC将被记录在快照中,否则将被忽略snapshot.categories_mask=[ModuleA.SystemA.ClassA,ModuleB]
appenders_config
是Appenders的一组配置。 appenders_config
后面的第一个参数是Appender的名称,所有同名的Appender共享相同的配置。
姓名 | 必需的 | 可配置值 | 默认 | 适用于ConsoleAppender | 适用于TextFileAppender | 适用于 CompressedFileAppender | 适用于RawFileAppender |
---|---|---|---|---|---|---|---|
类型 | ✔ | 控制台、文本文件、压缩文件、原始文件 | ✔ | ✔ | ✔ | ✔ | |
使能够 | ✘ | Appender默认是否开启 | 真的 | ✔ | ✔ | ✔ | ✔ |
级别 | ✘ | 日志级别数组 | [全部] | ✔ | ✔ | ✔ | ✔ |
时区 | ✘ | gmt 或任何其他字符串 | 当地时间 | ✔ | ✔ | ✔ | ✔ |
文件名 | ✔ | 相对或绝对路径 | ✘ | ✔ | ✔ | ✔ | |
位于沙箱中 | ✘ | 真,假 | 错误的 | ✘ | ✔ | ✔ | ✔ |
最大文件大小 | ✘ | 正整数或 0 | 0 | ✘ | ✔ | ✔ | ✔ |
过期时间天数 | ✘ | 正整数或 0 | 0 | ✘ | ✔ | ✔ | ✔ |
容量限制 | ✘ | 正整数或 0 | 0 | ✘ | ✔ | ✔ | ✔ |
类别_掩码 | ✘ | [] 中包含的字符串数组 | 空的 | ✔ | ✔ | ✔ | ✔ |
指定 Appender 的类型。
console
: 代表ConsoleAppender
text_file
:代表 TextFileAppender
compressed_file
:代表 CompressedFileAppender
raw_file
:代表RawFileAppender
默认为true
。如果设置为false
,Appender 将默认被禁用,稍后可以使用set_appenders_enable
启用。
包含在[]
中的数组,包含verbose
、 debug
、 info
、 warning
、 error
、 fatal
或[all]
的任意组合以接受所有级别。注意:级别之间不要包含空格,否则解析失败。
指定日志的时区。 gmt
表示格林威治标准时间 (UTC+0),任何其他字符串或留空将使用本地时区。时区影响两件事:
格式化文本日志的时间戳(适用于ConsoleAppender和TextFileAppender)
当超过指定时区的午夜时,将创建新的日志文件(适用于 TextFileAppender、CompressedFileAppender 和 RawFileAppender)。
保存文件的路径和文件名前缀。该路径可以是绝对路径(不推荐用于 Android 和 iOS)或相对路径。最终的输出文件名将是此路径和名称,后跟日期、文件号和 Appender 的扩展名。
仅在 Android 上有意义:
true
:文件存储在内部存储目录中(android.content.Context.getFilesDir())。如果不可用,它们将存储在外部存储目录中(android.content.Context.getExternalFilesDir())。如果这也不可用,它们将存储在缓存目录中(android.content.Context.getCacheDir())。
false
:文件默认存储在外部存储目录中。如果不可用,它们将存储在内部存储目录中。如果也不可用,它们将存储在 Cache 目录中。
最大文件大小(以字节为单位)。当保存的文件超过此大小时,将创建一个新的日志文件,文件编号按顺序递增。 0
禁用此功能。
文件保留的最大天数。早于此时间的文件将被自动删除。 0
禁用此功能。
此 Appender 在输出目录中输出的文件的最大总大小。如果超过此限制,将从最旧的文件开始删除,直到总大小在限制内。 0
禁用此功能。
如果日志对象是支持类别的 Log 对象,则可以使用它来过滤树状类别列表。当数组不为空时,此功能处于活动状态。例如, [*default,ModuleA,ModuleB.SystemC]
表示默认类别的日志