)
在鸿蒙HarmonyOS原生应用开发中日志是监控运行状态、追踪业务流程和排查线上问题的核心工具。直接使用原生的console打印存在诸多痛点如高频打印阻塞主线程、敏感信息泄露、日志顺序混乱以及崩溃后无法本地留存等。为此开发者通常会基于鸿蒙官方的HiLog或console进行二次封装打造支持分级、格式化、隐私脱敏及异步写入的日志框架。一、 官方核心基础HiLog 系统鸿蒙官方提供了HiLog和FaultLog两套日志系统。其中HiLog支持按类型、级别和格式化字符串输出日志是构建自定义日志框架的底层基石。五级日志模型官方定义了DEBUG调试、INFO正常业务信息、WARN非致命异常、ERROR普通错误和FATAL致命崩溃五个级别便于开发者精细化管理日志输出。隐私合规标识在格式化字符串中参数必须明确指定{public}或{private}默认。被标记为{private}的敏感数据如手机号、密码在日志中会自动显示为private从系统底层保障隐私安全。全局级别控制支持通过setMinLogLevel动态设置应用打印的最低日志级别例如在生产环境直接屏蔽DEBUG和INFO级别减少性能开销。二、 进阶封装方案LogUtil 统一日志工具针对原生HiLog调用繁琐的问题社区广泛采用LogUtil等单例封装方案提供一站式的日志管理能力。统一入口与格式化对外暴露debug、info、warn、error等语义化方法。内部自动拼接时间戳、日志级别标签如[INFO]和自定义 Tag解决多页面日志输出混乱的问题。自动脱敏处理内置正则表达式在日志输出前自动过滤并替换敏感字段如将tokenxxx替换为token******将手机号替换为1*********防止核心数据明文打印。异步文件写入与滚动分割采用异步缓冲机制将日志写入本地文件避免高频打印阻塞 UI 渲染线程。同时支持文件按大小如 2MB自动分割与清空重建防止撑爆设备存储。针对您提到的进阶封装方案与跨平台生态日志库以下是结合具体业务场景的 ArkTS 及跨平台实战代码1. 进阶封装实战LogUtil 统一入口与自动脱敏场景构建全局单例日志工具在打印前自动对手机号、Token 等敏感信息进行正则脱敏同时统一拼接时间戳与日志级别标签解决控制台日志混乱的问题。import { hilog } from kit.PerformanceAnalysisKit; export class LogUtil { private static readonly DOMAIN 0x0001; private static readonly TAG HarmonyApp; // 核心脱敏正则匹配手机号与 Token private static desensitize(msg: string): string { return msg.replace(/1[3-9]\d{9}/g, 1*********) .replace(/token[:]\s*[a-zA-Z0-9_\-.]/gi, token******); } // 统一格式化并输出 INFO 级别日志 static info(msg: string, ...args: Object[]): void { const timestamp new Date().toLocaleTimeString(); const content args.length ? ${msg} ${JSON.stringify(args)} : msg; const safeContent LogUtil.desensitize(content); // 自动拼接 [时间] [级别] [消息] hilog.info(LogUtil.DOMAIN, LogUtil.TAG, [%{public}s] [INFO] %{public}s, timestamp, safeContent); } }2. 异步文件写入与滚动分割机制场景在后台将高频日志写入本地文件避免阻塞 UI 线程。当文件达到 2MB 时自动重命名备份并创建新文件防止撑爆设备存储。import { fileIo } from kit.CoreFileKit; export class FileLogger { private static readonly MAX_FILE_SIZE 2 * 1024 * 1024; // 2MB private static logPath: string /data/storage/el2/base/app_log.txt; static async writeLogAsync(logLine: string): Promisevoid { // 放入 TaskPool 或 Worker 中异步执行避免阻塞主线程 try { const file fileIo.openSync(FileLogger.logPath, fileIo.OpenMode.APPEND); const stat fileIo.statSync(file.fd); // 检查文件大小超限则触发滚动分割 if (stat.size FileLogger.MAX_FILE_SIZE) { fileIo.closeSync(file.fd); fileIo.moveFileSync(FileLogger.logPath, FileLogger.logPath .bak); } else { fileIo.writeSync(file.fd, logLine \n); fileIo.closeSync(file.fd); } } catch (err) { console.error(日志写入失败:, err); } } }三、 跨平台与第三方生态日志库对于采用跨平台技术栈的鸿蒙应用也有成熟的第三方日志库可供选择Flutter for OpenHarmony (simple_logger)专为鸿蒙 Flutter 开发打造的极简日志库。纯 Dart 实现不依赖原生 C 接口资源占用极低。支持全局级别过滤如生产环境仅打印WARNING及以上并完美兼容鸿蒙 DevEco Studio 控制台的 ANSI 彩色编码通过色彩快速区分错误与警告缓解视觉疲劳。鸿蒙 PC 端 Rust 框架 (tracing)针对鸿蒙 PC 端的 Rust 开发推荐使用tracingtracing-subscriber结构化日志框架。它支持trace debug info warn error分级天然支持链路追踪记录函数执行区间与嵌套耗时并可输出 JSON 结构化日志对接 ELK 平台非常适合 Web 服务和后台脚本的复杂调试。1. Flutter for OpenHarmonysimple_logger 极简配置场景在鸿蒙 Flutter 项目中引入simple_logger配置生产环境仅打印 WARNING 及以上级别并开启控制台彩色编码。import package:simple_logger/simple_logger.dart; void initHarmonyLogger() { final logger SimpleLogger(); // 生产环境过滤掉 DEBUG 和 INFO logger.setMode(LogMode.debug); logger.setLevel(Level.WARNING); // 开启 DevEco Studio 控制台的 ANSI 彩色输出 logger.formatter (message, level, time) { return \x1B[33m[$level]\x1B[0m $time: $message; // 黄色高亮警告 }; logger.info(应用启动完成); // 生产环境不会输出 logger.warning(网络请求超时); // 生产环境正常输出 }2. 鸿蒙 PC 端 Rusttracing 结构化链路追踪场景在鸿蒙 PC 端的 Rust 模块中使用tracing输出 JSON 格式的链路日志记录函数执行耗时方便对接 ELK 平台进行性能分析。use tracing::{info, instrument}; use tracing_subscriber::{fmt, EnvFilter}; // 初始化 JSON 结构化日志 pub fn init_tracing() { fmt() .with_env_filter(EnvFilter::from_default_env()) .json() // 输出标准 JSON 格式 .init(); } // 自动记录函数进入、退出及耗时 #[instrument(level info, name db_query, skip(user_id))] pub async fn query_user_data(user_id: u64) - String { info!(user_id user_id, 开始查询用户数据); // 模拟数据库查询耗时 tokio::time::sleep(std::time::Duration::from_millis(150)).await; User Data.to_string() }四、官方 HiLog 原生封装隐私合规与长文本分段场景在使用鸿蒙原生hilog时确保敏感数据不被明文打印同时解决单条日志超过 4096 字节被系统截断的问题。import { hilog } from kit.PerformanceAnalysisKit; export class SafeHiLog { private static readonly DOMAIN 0x0001; private static readonly MAX_LEN 3500; // 预留冗余防止截断 static info(tag: string, msg: string, ...args: Object[]): void { // 使用 %{private}s 确保敏感参数在真机日志中默认被隐藏 const format %{private}s; const fullMsg args.length ? ${msg} ${JSON.stringify(args)} : msg; // 自动分段打印规避 4096 字节限制 let remaining fullMsg; while (remaining.length 0) { const segment remaining.slice(0, SafeHiLog.MAX_LEN); remaining remaining.slice(SafeHiLog.MAX_LEN); hilog.info(SafeHiLog.DOMAIN, tag, format, segment); } } }五、统一日志工具实战LogUtil 全局分级与脱敏场景构建单例日志工具支持全局级别控制生产环境屏蔽 DEBUG并在输出前自动对 Token 和手机号进行正则脱敏。import { hilog } from kit.PerformanceAnalysisKit; enum LogLevel { DEBUG 0, INFO 1, WARN 2, ERROR 3 } class LogUtil { private static instance: LogUtil; private globalLevel: LogLevel LogLevel.DEBUG; // 上线前改为 INFO static getInstance(): LogUtil { if (!LogUtil.instance) LogUtil.instance new LogUtil(); return LogUtil.instance; } setLevel(level: LogLevel) { this.globalLevel level; } // 核心脱敏逻辑 private desensitize(msg: string): string { return msg.replace(/1[3-9]\d{9}/g, 1*********) .replace(/token[:]\s*[a-zA-Z0-9_\-.]/gi, token******); } info(tag: string, ...args: Object[]): void { if (this.globalLevel LogLevel.INFO) return; const content this.desensitize(args.map(a typeof a object ? JSON.stringify(a) : String(a)).join( )); hilog.info(0x0001, tag, [INFO] %{public}s, content); } } // 业务调用自动脱敏并受全局级别控制 LogUtil.getInstance().info(AuthModule, User login, tokenabc123xyz, phone13800138000);六、应用内可视化日志AppLog 悬浮窗调试场景在没有连接 DevEco Studio 的真机测试环境中通过应用内悬浮按钮实时查看日志流快速定位现场问题。import { AppLog } from abner/app_log; // 1. 在 EntryAbility 中初始化 AppLog.getAppLog().init({ globalTag: MyApp, isHiLog: true, // 同时输出到系统 HiLog showLogLocation: true // 显示代码打印位置 }); // 2. 在任意页面开启悬浮日志入口 Component struct DebugPage { aboutToAppear() { AppLog.getAppLog().showLog(() { // 点击关闭时的回调例如返回上一页 console.info(关闭悬浮日志); }); } build() { Button(触发业务日志).onClick(() { AppLog.info(这是一条会在悬浮窗显示的日志); AppLog.error({ code: 500, msg: Server Error }); // 支持对象直接打印 }) } }七、跨平台结构化追踪Rust Tracing 异步日志场景在鸿蒙 PC 端或底层 Rust 模块中使用tracing框架输出带时间戳的结构化 JSON 日志方便对接 ELK 平台进行链路追踪。use tracing::{info, warn, error}; use tracing_subscriber::{fmt, EnvFilter}; pub fn init_tracing() { fmt() .with_env_filter(EnvFilter::from_default_env()) // 支持通过环境变量动态过滤级别 .with_timer(fmt::time::LocalTime::rfc_3339()) // 精确到毫秒的 RFC3339 时间戳 .json() // 输出 JSON 格式 .init(); } // 业务代码中结构化打印 info!(user_id 1001, action login, User logged in successfully); warn!(cache_ttl 0, Cache expired, fetching from network);