log_reader — 本地日志文件读取工具开发指南概述log_reader是 microLog 提供的本地日志文件读取工具用于读取tinySeqFile格式的日志文件。该模块采用Pimpl 模式封装内部实现对外提供简洁、稳定的 API 接口支持加密日志解密、多种输出方式以及跨平台运行。文中代码仅仅为展示开发逻辑并没有进行编译测试项目仓库https://gitee.com/galaxy_0/micro-log支持特性特性说明自动识别文件格式读取文件头自动获取max_count和page_size加密日志解密支持 AES128 / AES256 加密日志的实时解密多种读取方式一次性读取、回调逐条处理、输出到文件或终端索引访问支持按索引读取单条日志记录跨平台兼容 Windows 和 Linux 系统接口定义头文件#includelogDetail/log_reader.hpp核心类namespacemicroLog{classlog_reader{public:// 读取模式enumclassread_mode{TERMINAL,// 终端模式输出带索引前缀如 [123] log contentTEXT// 纯文本模式仅输出日志内容};// 加密类型enumclasscrypto_type{NONE,// 无加密AES128,// AES-128 加密AES256// AES-256 加密};// 配置选项structoptions{std::string log_file;// 日志文件路径std::string output_file;// 输出文件路径可选read_mode moderead_mode::TERMINAL;crypto_type cryptocrypto_type::NONE;std::string key;// 加密密钥128位需16字节256位需32字节std::string iv;// 初始化向量16字节};// 日志记录结构structrecord{uint64_tindex;// 记录索引即序号std::string content;// 日志内容已解密若有};// 回调函数类型返回 true 继续读取返回 false 停止usingread_callbackstd::functionbool(uint64_tindex,conststd::stringcontent);};}核心方法方法签名说明构造函数log_reader()创建读取器实例析构函数~log_reader()销毁实例自动关闭文件打开文件bool open(const std::string log_file)打开日志文件无加密打开文件带选项bool open(const options opts)打开日志文件并设置加密参数设置加密bool set_crypto(crypto_type type, const std::string key, const std::string iv)单独设置解密参数获取总记录数uint64_t get_total_count() const返回文件中的记录总数获取首条索引uint64_t get_first_index() const返回第一条记录的索引读取全部bool read_all(std::vectorrecord records)一次性将所有记录读入 vector回调读取bool read_with_callback(read_callback cb)通过回调函数逐条处理读取到文件bool read_to_file(const std::string file_path)将日志内容写入指定文件读取到终端bool read_to_stdout(read_mode mode read_mode::TERMINAL)输出到标准输出关闭文件void close()手动关闭日志文件检查有效性bool is_valid() const检查读取器是否处于有效状态使用示例基本使用无加密#includelogDetail/log_reader.hppintmain(){microLog::log_reader reader;if(!reader.open(./tinylog.bin)){std::cerr打开日志文件失败std::endl;return1;}std::cout总记录数: reader.get_total_count()std::endl;std::cout首条索引: reader.get_first_index()std::endl;// 回调方式逐条读取reader.read_with_callback([](uint64_tidx,conststd::stringcontent){std::cout[idx] content;returntrue;// 继续读取});reader.close();return0;}读取到文件microLog::log_reader reader;if(reader.open(./tinylog.bin)){reader.read_to_file(./output.txt);}读取加密日志microLog::log_reader reader;// 方式1通过 options 结构一次性设置microLog::log_reader::options opts;opts.log_file./tinylog_encrypted.bin;opts.cryptomicroLog::log_reader::crypto_type::AES256;opts.key0123456789abcdef0123456789abcdef;// 32 字节opts.iv0123456789abcdef;// 16 字节if(reader.open(opts)){reader.read_to_stdout();}// 方式2先打开再设置加密// reader.open(./tinylog_encrypted.bin);// reader.set_crypto(microLog::log_reader::crypto_type::AES256, key, iv);读取到 vectormicroLog::log_reader reader;if(reader.open(./tinylog.bin)){std::vectormicroLog::log_reader::recordrecords;if(reader.read_all(records)){for(constautorec:records){std::cout[rec.index] rec.content;}}}条件过滤读取microLog::log_reader reader;if(reader.open(./tinylog.bin)){// 只读取包含 [ERROR] 的日志reader.read_with_callback([](uint64_tidx,conststd::stringcontent){if(content.find([ERROR])!std::string::npos){std::cout[idx] content;}returntrue;});}高级用法进度显示microLog::log_reader reader;if(reader.open(./tinylog.bin)){uint64_ttotalreader.get_total_count();uint64_tcount0;reader.read_with_callback([](uint64_tidx,conststd::stringcontent){std::coutcontent;if(count%10000){std::cerr\r进度: (count*100/total)%;}returntrue;});std::cerr\r进度: 100%std::endl;}批量处理microLog::log_reader reader;if(reader.open(./tinylog.bin)){std::vectormicroLog::log_reader::recordbatch;constsize_t BATCH_SIZE100;reader.read_with_callback([](uint64_tidx,conststd::stringcontent){batch.push_back({idx,content});if(batch.size()BATCH_SIZE){process_batch(batch);// 自定义批量处理函数batch.clear();}returntrue;});if(!batch.empty()){process_batch(batch);}}工具程序编译cmake..-DBUILD_TOOLSONmakelog_reader_tool命令行参数参数说明示例-f指定日志文件路径必需-f ./tinylog.bin-t指定输出文件路径可选-t ./output.txt-m读取模式terminal或text-m text-kAES 密钥十六进制字符串-k 0123456789abcdef0123456789abcdef-i初始化向量十六进制字符串-i 0123456789abcdef使用示例# 读取到终端带索引./log_reader_tool-f./tinylog.bin# 读取到终端纯文本./log_reader_tool-f./tinylog.bin-mtext# 输出到文件./log_reader_tool-f./tinylog.bin-t./output.txt# 读取加密日志./log_reader_tool-f./tinylog.bin-k0123456789abcdef0123456789abcdef-i0123456789abcdef内部实现文件格式tinySeqFile日志文件采用定长头部 变长记录的结构具体布局如下数据区 (变长记录)记录 0: [长度:4字节] [内容]记录 1: [长度:4字节] [内容]...文件头 (stHead)m_magic[4]: 固定标识 TF\\0\\0m_ver[4]: 版本号 (1 或 2)m_max_count[8]: 最大记录数m_page_size[4]: 页面大小字节m_length[8]: 文件总长度字节m_first[8]: 第一条记录的索引m_last[8]: 最后一条记录的索引m_crypto[4]: 加密类型 (0NONE, 1AES128, 2AES256)文件头固定长度为sizeof(stHead)包含元信息。数据区由多条记录顺序排列每条记录由一个 4 字节的长度字段和对应的内容数据组成。记录内容为原始日志字符串若加密则为密文读取时会根据m_crypto自动解密。Pimpl 模式structlog_reader::impl{std::shared_ptrtinySeqFileseq_file;// 底层文件操作对象std::string log_file;// 文件路径boolopenedfalse;// 是否已打开boolcrypto_setfalse;// 是否已设置加密boolread_file_header(conststd::stringpath,uint64_tmax_count,uint32_tpage_size);};内部通过std::shared_ptrtinySeqFile管理文件句柄和内存映射确保资源安全释放。工作流程渲染错误:Mermaid 渲染失败: Parse error on line 2: ...art TD A[调用 open()] -- B[读取文件头----------------------^ Expecting SQE, DOUBLECIRCLEEND, PE, -), STADIUMEND, SUBROUTINEEND, PIPE, CYLINDEREND, DIAMOND_STOP, TAGEND, TRAPEND, INVTRAPEND, UNICODE_TEXT, TEXT, TAGSTART, got PS错误处理常见错误及原因错误场景返回值可能原因文件不存在open()返回false路径错误或无权限文件格式无效open()返回false不是有效的tinySeqFile文件加密密钥错误set_crypto()返回false密钥长度不符合要求未打开文件read_*()返回false未调用open()或打开失败错误检查示例microLog::log_reader reader;if(!reader.open(./nonexistent.bin)){std::cerr错误: 无法打开日志文件std::endl;return1;}if(!reader.is_valid()){std::cerr错误: 读取器状态无效std::endl;return1;}std::vectormicroLog::log_reader::recordrecords;if(!reader.read_all(records)){std::cerr错误: 读取数据失败std::endl;return1;}性能优化内存预分配std::vectormicroLog::log_reader::recordrecords;records.reserve(reader.get_total_count());// 提前预留空间reader.read_all(records);按需读取回调方式// 不一次性加载所有数据内存占用保持恒定reader.read_with_callback([](uint64_tidx,conststd::stringcontent){process_record(content);// 即时处理returntrue;});大文件建议对于超大日志文件GB 级别推荐使用read_with_callback()配合流式处理。避免使用read_all()将全部数据装入内存。集成到其他项目作为共享库使用# 在 CMakeLists.txt 中 find_package(microLog REQUIRED) target_link_libraries(your_app microLog::log_reader)#includemicroLog/log_reader.hppintmain(){microLog::log_reader reader;reader.open(/path/to/log.bin);reader.read_to_stdout();return0;}静态链接add_subdirectory(path/to/microLog) target_link_libraries(your_app microLog::log_reader_static)与日志写入配合使用// 写入日志本地环形文件autologmicroLog::createLogmicroLog::tinyLogType::LOCAL(4,./tinylog.bin,4096,1000);log-info(系统启动);log-debug(调试信息: %d,42);log-warn(警告: 资源不足);log-error(错误: %s,连接失败);// 读取日志microLog::log_reader reader;reader.open(./tinylog.bin);reader.read_to_stdout();常见问题Q1: 如何判断日志文件是否加密log_reader不会自动探测加密类型。你可以先尝试不带加密打开如果读取内容出现乱码则说明文件已加密需通过set_crypto()设置正确的密钥和 IV。Q2: 读取性能怎么样read_all()一次性读入内存适合小文件100MB速度快。read_with_callback()逐条处理内存占用恒定适合大文件但回调开销略高。Q3: 支持哪些平台支持 Windows 和 Linux。在 Linux 上使用mmap在 Windows 上使用CreateFileMapping均实现高效文件访问。Q4: 能否读取正在被写入的日志文件可以。tinySeqFile基于内存映射读操作不阻塞写操作。但可能读到尚未完整写入的记录部分内容建议在读取前确保写入完成或接受不完整的风险。Q5: 如何处理超大日志文件10GB建议使用回调方式逐条处理同时结合进度显示。避免使用read_all()并确保输出目标如文件支持流式写入。文档版本: 1.0最后更新: 2026-07-04作者: 宋炜
microLog 的本地日志读取接口 log_reader — 本地日志文件读取工具开发指南
log_reader — 本地日志文件读取工具开发指南概述log_reader是 microLog 提供的本地日志文件读取工具用于读取tinySeqFile格式的日志文件。该模块采用Pimpl 模式封装内部实现对外提供简洁、稳定的 API 接口支持加密日志解密、多种输出方式以及跨平台运行。文中代码仅仅为展示开发逻辑并没有进行编译测试项目仓库https://gitee.com/galaxy_0/micro-log支持特性特性说明自动识别文件格式读取文件头自动获取max_count和page_size加密日志解密支持 AES128 / AES256 加密日志的实时解密多种读取方式一次性读取、回调逐条处理、输出到文件或终端索引访问支持按索引读取单条日志记录跨平台兼容 Windows 和 Linux 系统接口定义头文件#includelogDetail/log_reader.hpp核心类namespacemicroLog{classlog_reader{public:// 读取模式enumclassread_mode{TERMINAL,// 终端模式输出带索引前缀如 [123] log contentTEXT// 纯文本模式仅输出日志内容};// 加密类型enumclasscrypto_type{NONE,// 无加密AES128,// AES-128 加密AES256// AES-256 加密};// 配置选项structoptions{std::string log_file;// 日志文件路径std::string output_file;// 输出文件路径可选read_mode moderead_mode::TERMINAL;crypto_type cryptocrypto_type::NONE;std::string key;// 加密密钥128位需16字节256位需32字节std::string iv;// 初始化向量16字节};// 日志记录结构structrecord{uint64_tindex;// 记录索引即序号std::string content;// 日志内容已解密若有};// 回调函数类型返回 true 继续读取返回 false 停止usingread_callbackstd::functionbool(uint64_tindex,conststd::stringcontent);};}核心方法方法签名说明构造函数log_reader()创建读取器实例析构函数~log_reader()销毁实例自动关闭文件打开文件bool open(const std::string log_file)打开日志文件无加密打开文件带选项bool open(const options opts)打开日志文件并设置加密参数设置加密bool set_crypto(crypto_type type, const std::string key, const std::string iv)单独设置解密参数获取总记录数uint64_t get_total_count() const返回文件中的记录总数获取首条索引uint64_t get_first_index() const返回第一条记录的索引读取全部bool read_all(std::vectorrecord records)一次性将所有记录读入 vector回调读取bool read_with_callback(read_callback cb)通过回调函数逐条处理读取到文件bool read_to_file(const std::string file_path)将日志内容写入指定文件读取到终端bool read_to_stdout(read_mode mode read_mode::TERMINAL)输出到标准输出关闭文件void close()手动关闭日志文件检查有效性bool is_valid() const检查读取器是否处于有效状态使用示例基本使用无加密#includelogDetail/log_reader.hppintmain(){microLog::log_reader reader;if(!reader.open(./tinylog.bin)){std::cerr打开日志文件失败std::endl;return1;}std::cout总记录数: reader.get_total_count()std::endl;std::cout首条索引: reader.get_first_index()std::endl;// 回调方式逐条读取reader.read_with_callback([](uint64_tidx,conststd::stringcontent){std::cout[idx] content;returntrue;// 继续读取});reader.close();return0;}读取到文件microLog::log_reader reader;if(reader.open(./tinylog.bin)){reader.read_to_file(./output.txt);}读取加密日志microLog::log_reader reader;// 方式1通过 options 结构一次性设置microLog::log_reader::options opts;opts.log_file./tinylog_encrypted.bin;opts.cryptomicroLog::log_reader::crypto_type::AES256;opts.key0123456789abcdef0123456789abcdef;// 32 字节opts.iv0123456789abcdef;// 16 字节if(reader.open(opts)){reader.read_to_stdout();}// 方式2先打开再设置加密// reader.open(./tinylog_encrypted.bin);// reader.set_crypto(microLog::log_reader::crypto_type::AES256, key, iv);读取到 vectormicroLog::log_reader reader;if(reader.open(./tinylog.bin)){std::vectormicroLog::log_reader::recordrecords;if(reader.read_all(records)){for(constautorec:records){std::cout[rec.index] rec.content;}}}条件过滤读取microLog::log_reader reader;if(reader.open(./tinylog.bin)){// 只读取包含 [ERROR] 的日志reader.read_with_callback([](uint64_tidx,conststd::stringcontent){if(content.find([ERROR])!std::string::npos){std::cout[idx] content;}returntrue;});}高级用法进度显示microLog::log_reader reader;if(reader.open(./tinylog.bin)){uint64_ttotalreader.get_total_count();uint64_tcount0;reader.read_with_callback([](uint64_tidx,conststd::stringcontent){std::coutcontent;if(count%10000){std::cerr\r进度: (count*100/total)%;}returntrue;});std::cerr\r进度: 100%std::endl;}批量处理microLog::log_reader reader;if(reader.open(./tinylog.bin)){std::vectormicroLog::log_reader::recordbatch;constsize_t BATCH_SIZE100;reader.read_with_callback([](uint64_tidx,conststd::stringcontent){batch.push_back({idx,content});if(batch.size()BATCH_SIZE){process_batch(batch);// 自定义批量处理函数batch.clear();}returntrue;});if(!batch.empty()){process_batch(batch);}}工具程序编译cmake..-DBUILD_TOOLSONmakelog_reader_tool命令行参数参数说明示例-f指定日志文件路径必需-f ./tinylog.bin-t指定输出文件路径可选-t ./output.txt-m读取模式terminal或text-m text-kAES 密钥十六进制字符串-k 0123456789abcdef0123456789abcdef-i初始化向量十六进制字符串-i 0123456789abcdef使用示例# 读取到终端带索引./log_reader_tool-f./tinylog.bin# 读取到终端纯文本./log_reader_tool-f./tinylog.bin-mtext# 输出到文件./log_reader_tool-f./tinylog.bin-t./output.txt# 读取加密日志./log_reader_tool-f./tinylog.bin-k0123456789abcdef0123456789abcdef-i0123456789abcdef内部实现文件格式tinySeqFile日志文件采用定长头部 变长记录的结构具体布局如下数据区 (变长记录)记录 0: [长度:4字节] [内容]记录 1: [长度:4字节] [内容]...文件头 (stHead)m_magic[4]: 固定标识 TF\\0\\0m_ver[4]: 版本号 (1 或 2)m_max_count[8]: 最大记录数m_page_size[4]: 页面大小字节m_length[8]: 文件总长度字节m_first[8]: 第一条记录的索引m_last[8]: 最后一条记录的索引m_crypto[4]: 加密类型 (0NONE, 1AES128, 2AES256)文件头固定长度为sizeof(stHead)包含元信息。数据区由多条记录顺序排列每条记录由一个 4 字节的长度字段和对应的内容数据组成。记录内容为原始日志字符串若加密则为密文读取时会根据m_crypto自动解密。Pimpl 模式structlog_reader::impl{std::shared_ptrtinySeqFileseq_file;// 底层文件操作对象std::string log_file;// 文件路径boolopenedfalse;// 是否已打开boolcrypto_setfalse;// 是否已设置加密boolread_file_header(conststd::stringpath,uint64_tmax_count,uint32_tpage_size);};内部通过std::shared_ptrtinySeqFile管理文件句柄和内存映射确保资源安全释放。工作流程渲染错误:Mermaid 渲染失败: Parse error on line 2: ...art TD A[调用 open()] -- B[读取文件头----------------------^ Expecting SQE, DOUBLECIRCLEEND, PE, -), STADIUMEND, SUBROUTINEEND, PIPE, CYLINDEREND, DIAMOND_STOP, TAGEND, TRAPEND, INVTRAPEND, UNICODE_TEXT, TEXT, TAGSTART, got PS错误处理常见错误及原因错误场景返回值可能原因文件不存在open()返回false路径错误或无权限文件格式无效open()返回false不是有效的tinySeqFile文件加密密钥错误set_crypto()返回false密钥长度不符合要求未打开文件read_*()返回false未调用open()或打开失败错误检查示例microLog::log_reader reader;if(!reader.open(./nonexistent.bin)){std::cerr错误: 无法打开日志文件std::endl;return1;}if(!reader.is_valid()){std::cerr错误: 读取器状态无效std::endl;return1;}std::vectormicroLog::log_reader::recordrecords;if(!reader.read_all(records)){std::cerr错误: 读取数据失败std::endl;return1;}性能优化内存预分配std::vectormicroLog::log_reader::recordrecords;records.reserve(reader.get_total_count());// 提前预留空间reader.read_all(records);按需读取回调方式// 不一次性加载所有数据内存占用保持恒定reader.read_with_callback([](uint64_tidx,conststd::stringcontent){process_record(content);// 即时处理returntrue;});大文件建议对于超大日志文件GB 级别推荐使用read_with_callback()配合流式处理。避免使用read_all()将全部数据装入内存。集成到其他项目作为共享库使用# 在 CMakeLists.txt 中 find_package(microLog REQUIRED) target_link_libraries(your_app microLog::log_reader)#includemicroLog/log_reader.hppintmain(){microLog::log_reader reader;reader.open(/path/to/log.bin);reader.read_to_stdout();return0;}静态链接add_subdirectory(path/to/microLog) target_link_libraries(your_app microLog::log_reader_static)与日志写入配合使用// 写入日志本地环形文件autologmicroLog::createLogmicroLog::tinyLogType::LOCAL(4,./tinylog.bin,4096,1000);log-info(系统启动);log-debug(调试信息: %d,42);log-warn(警告: 资源不足);log-error(错误: %s,连接失败);// 读取日志microLog::log_reader reader;reader.open(./tinylog.bin);reader.read_to_stdout();常见问题Q1: 如何判断日志文件是否加密log_reader不会自动探测加密类型。你可以先尝试不带加密打开如果读取内容出现乱码则说明文件已加密需通过set_crypto()设置正确的密钥和 IV。Q2: 读取性能怎么样read_all()一次性读入内存适合小文件100MB速度快。read_with_callback()逐条处理内存占用恒定适合大文件但回调开销略高。Q3: 支持哪些平台支持 Windows 和 Linux。在 Linux 上使用mmap在 Windows 上使用CreateFileMapping均实现高效文件访问。Q4: 能否读取正在被写入的日志文件可以。tinySeqFile基于内存映射读操作不阻塞写操作。但可能读到尚未完整写入的记录部分内容建议在读取前确保写入完成或接受不完整的风险。Q5: 如何处理超大日志文件10GB建议使用回调方式逐条处理同时结合进度显示。避免使用read_all()并确保输出目标如文件支持流式写入。文档版本: 1.0最后更新: 2026-07-04作者: 宋炜