shell
#
# file: 20250406.log
# logger.info('Test logger.info...')
# logger.warn(new Map([['name', '这是一个 Map 对象']]))
#
┌────────────────────────────────────────────────────────────────────────────────
│ Info | 2025-04-06 14:58:59.810 (+00:00:25.276)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ Test logger.info...
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ #0 at print (library/src/main/ets/service/printer.ets:235:45)
│ #1 at print (library/src/main/ets/service/printer.ets:269:12)
│ #2 at log (library/src/main/ets/abstract/logger.ets:114:22)
└────────────────────────────────────────────────────────────────────────────────
┌────────────────────────────────────────────────────────────────────────────────
│ Warn | 2025-04-06 14:59:01.820 (+00:00:27.286)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ {
│ "__type__": "Map",
│ "__value__": {
│ "name": "这是一个 Map 对象"
│ }
│ }
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ #0 at print (library/src/main/ets/service/printer.ets:268:45)
│ #1 at print (library/src/main/ets/service/printer.ets:302:12)
│ #2 at log (library/src/main/ets/abstract/logger.ets:154:22)
└────────────────────────────────────────────────────────────────────────────────
前言
在 HarmonyOS 应用开发过程中,高效的日志系统 对开发调试和问题排查至关重要。传统的 hilog 原生接口虽然功能完备,但在实际开发中仍存在诸多不便:
- 复杂数据:需要手动序列化对象和集合类型
- 日志过滤:缺乏运行时动态调整日志级别的能力
- 本地缓存:没有内置的日志文件管理和轮转机制
- 日志上报:缺少开箱即用的日志上报云端的方案
之前在开发 Flutter App 时,使用过 Flutter logger 日志库,其优雅的设计给我留下了深刻印象。受此启发,我决定开发 HarmonyOS 类似的日志解决方案 (logger)
- 支持 多种数据类型,如基本数据类型、对象、Class、Map、Set 等支持 JSON 序列化数据
- 支持 自定义日志行为,如日志动态过滤、本地文件读写(定期自动清理)、云端日志上报等
- 支持 HarmonyOS Next API12+
- 支持 堆栈信息输出
准备
-
前往鸿蒙三方库中心仓,注册 ohpm 账号 (openharmony)
-
前往【个人中心 / 认证管理】,新增 OHPM 公钥
shell# ssh-keygen 创建公私密钥,需要注意的是 passphrase 不可省略!!! # -------------------------------------------------------------- ssh-keygen -m PEM -t RSA -b 4096 -f ~/.ssh_ohpm/id_rsa_publish Generating public/private RSA key pair. Enter passphrase (empty for no passphrase): -
前往【个人中心】复制发布码,本地设备配置 publish_id
shell# your_publish_id: 你复制的发布码 # ---------------------------------------------- ohpm config set publish_id your_publish_id
日志库
-
梳理基本功能,定义抽象类 API
API 作用 详细描述 Filter 日志过滤 控制哪些日志需要被记录,支持日志级别过滤 (DEBUG/INFO/WARN/ERROR) 等 Output 日志输出流管理 定义日志最终输出位置和行为, 如控制台、本地文件、网络上报、多输出源组合 Printer 日志内容格式化 负责日志视觉呈现, 如文本格式化(颜色/缩进/边框)、结构化输出、堆栈跟踪 Logger 日志触发执行入口 提供开发者调用日志接口, 多级别日志方法 (debug、info、warn、error等) -
基于上述 抽象类 API,实现核心功能
API 继承 作用 详细描述 SafeFilter Filter基础日志过滤 基于日志级别的基础过滤 (DEBUG、INFO、WARN、ERROR) SafeWriteFileOutput Output文件系统日志输出 支持自动创建日志目录(按天)、日志文件轮转存储、异常恢复机制, 同时定义了 异步锁 AsyncMutex 优化极短时间内的同时写入和读取 SafeConsoleOutput Output控制台日志输出 适配 DevEco Studio 控制台,支持颜色区分和高亮 SafeMultiOutput Output多目标组合输出 适配多端输出源,支持输出权重配置 SafeSimplePrinter Printer简约日志格式 单行文本输出,无额外装饰(无时间戳/无边框),适合高频调试日志 SafePrettyPrinter Printer美观格式化输出 带边框的多行格式化,自动对齐键值对,支持显示堆栈跟踪记录,支持复杂对象树形展示 SafeHybridPrinter Printer混合策略打印机 不同日志级别使用不同打印策略,支持自定义级别映射 SafeLogger Logger开发者调用入口 提供开发者调用日志接口, 多级别日志方法 (debug、info、warn、error 等) -
预设了默认选项,以便开发者快速入手使用
typescript// 默认预设 import { SafeLogger } from 'logger' import { SafeFilter } from 'logger' import { SafeMultiOutput } from 'logger' import { SafeConsoleOutput } from 'logger' import { SafeWriteFileOutput } from 'logger' import { SafePrettyPrinter } from 'logger' import { SafeSimplePrinter } from 'logger' import { SafeHybridPrinter } from 'logger' export const logger = new SafeLogger({ printer: new SafeHybridPrinter(new SafePrettyPrinter(), { debug: new SafeSimplePrinter() }), output: new SafeMultiOutput([new SafeConsoleOutput(), new SafeWriteFileOutput()]), filter: new SafeFilter(), }) // 当然,也支持开发者自定义,例如: logger.reset({ printer: new SafeHybridPrinter(new SafePrettyPrinter({ lineLength: 120 }), { debug: new SafeSimplePrinter() }), output: new SafeMultiOutput([ new SafeWriteFileOutput({ storage: 'example/logger/cache', fileFormatter: 'harmony.[yyyyMMdd]' }), new SafeConsoleOutput() ]), })typescript// 开发者使用示范 /** * logger 写入 */ logger.info('Test logger.info...') logger.warn(new Map([['name', '这是一个 Map 对象']])) /** * logger 读取文件 */ await logger.info('Test logger.info...') const string = await logger.readAsString() // 返回 { filename: 文件名; content: 文本内容; type: 类型; } -
其他高级功能,云端日志上报示范
typescriptlet bytes = 0 const limit = 10 * 1024 * 1024; // 限制 10M 大小 const bufs = await logger.readAsArrayBuffers() const formData = new FormData() for (const buf of bufs) { if (bytes > limit) { break } formData.append('file', buf.buffer, { filename: buf.filename, type: buf.type }) bytes = bytes + buf.buffer.byteLength } axios.post('/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } });
仓库
OpenHarmony logger
Github logger
欢迎给个 Star 👍