第36篇:日志系统——Logger 封装与 hilog 实践

在这里插入图片描述

一、引言

日志是应用开发中最重要的调试工具之一。在鸿蒙系统中,hilog 提供了高性能的日志输出能力。DriverLicenseExam 项目通过 Logger 工具类对 hilog 进行了二次封装,提供了统一的日志接口,并支持日志分级、标签管理、脱敏处理等功能。本文将深入解析日志系统的设计与实现。

二、hilog 基础

2.1 hilog 是什么

hilog 是鸿蒙系统提供的高性能日志系统,具有以下特点:

  • 高性能:异步日志写入,不影响主线程性能
  • 分级输出:debug/info/warn/error 四级日志
  • 隐私保护:内置 %{public}s / %{private}s 脱敏机制
  • 领域隔离:通过 domain 区分不同模块的日志

2.2 hilog 的基本用法

import { hilog } from '@kit.PerformanceAnalysisKit';

// hilog 的完整签名
hilog.info(domain, tag, format, args);

// 示例
hilog.info(0xff00, 'MyApp', 'Hello, %{public}s', 'World');

三、Logger 封装

3.1 封装设计

项目中封装了 Logger 工具类,统一管理日志输出:

// commons/commonLib/src/main/ets/utils/Logger.ets
import { hilog } from '@kit.PerformanceAnalysisKit';

export class Logger {
  private static _domain: number = 0xff00;
  private static _prefix: string = 'EmptyTemplate';
  private static _format: string = '%{public}s, %{public}s';

  public static debug(...args: string[]): void {
    hilog.debug(Logger._domain, Logger._prefix, Logger._format, args);
  }

  public static info(...args: string[]): void {
    hilog.info(Logger._domain, Logger._prefix, Logger._format, args);
  }

  public static warn(...args: string[]): void {
    hilog.warn(Logger._domain, Logger._prefix, Logger._format, args);
  }

  public static error(...args: string[]): void {
    hilog.error(Logger._domain, Logger._prefix, Logger._format, args);
  }
}

3.2 封装的好处

  1. 统一配置:domain、prefix、format 等参数集中管理
  2. 简化调用:调用方不需要关心 hilog 的细节参数
  3. 便于扩展:可以添加日志文件输出、日志上传等扩展功能
  4. 切换灵活:未来可以替换底层的日志实现而不影响调用方

四、日志标签规范

4.1 标签定义

项目中每个模块定义自己的日志标签:

// EntryAbility.ets
const TAG: string = '[EntryAbility]';

// HomeView.ets
const TAG: string = '[HomeView]';

// ExamService.ets
const TAG: string = '[ExamService]';

// MineView.ets
logTag: string = 'PrepareLoginPage';
domainId: number = 0x0000;

4.2 日志使用示例

// 信息日志
Logger.info(TAG, 'Ability onWindowStageCreate');

// 错误日志
Logger.error(TAG, 'Failed to load content: %{public}s', JSON.stringify(err) ?? '');

// 调试日志
Logger.debug(TAG, 'currentIndex: %{public}d', this.currentIndex);

// 警告日志
Logger.warn(TAG, 'Network request timeout: %{public}s', url);

4.3 日志输出格式

Logger 输出的日志格式为:

[domain] [prefix] [level] message

例如:

[0xff00] [EmptyTemplate] [INFO] [EntryAbility] Ability onWindowStageCreate
[0xff00] [EmptyTemplate] [ERROR] [ExamService] Failed to load exam data
[0xff00] [EmptyTemplate] [DEBUG] [HomeView] currentIndex: 2

五、日志脱敏

5.1 隐私保护机制

鸿蒙的 hilog 内置了隐私保护机制,通过格式化占位符控制:

// %{public}s - 公开信息,正常输出
Logger.info(TAG, 'Succeeded in loading the content.');

// %{private}s - 敏感信息,在 release 版本中自动脱敏
Logger.info(TAG, 'User phone: %{private}s', userPhone);
Logger.info(TAG, 'User token: %{private}s', accessToken);

// %{public}d - 公开数字
Logger.info(TAG, 'Question index: %{public}d', currentIndex);

5.2 项目中全面使用脱敏日志

// Logger 的 format 预设为 %{public}s, %{public}s
private static _format: string = '%{public}s, %{public}s';

// 默认所有参数以 %{public}s 输出
Logger.info(TAG, 'User info updated');

对于需要输出私有信息的场景,直接调用 hilog:

// 敏感信息使用 %{private}s
hilog.info(0x0000, 'QuickLoginPage',
  'User phone: %{private}s', userPhone);

六、日志最佳实践

6.1 日志级别选择

级别 使用场景 示例
debug 开发调试,不保留到生产环境 Logger.debug(TAG, 'Detail data: ' + JSON.stringify(data))
info 正常流程的关键节点 Logger.info(TAG, 'Exam started, total: ' + count)
warn 非预期的但可恢复的情况 Logger.warn(TAG, 'Network timeout, retrying...')
error 不可恢复的错误 Logger.error(TAG, 'Failed to load: ' + err.message)

6.2 日志内容规范

// 好的日志 - 包含上下文信息
Logger.error(TAG, 'Failed to load exam data. userId: %{public}s, examId: %{public}s',
  userId, examId);

// 不好的日志 - 缺乏上下文
Logger.error(TAG, 'Error occurred');

6.3 避免过度日志

// 避免:循环中频繁输出日志
for (let i = 0; i < 1000; i++) {
  Logger.debug(TAG, 'Processing item: ' + i);  // 不要这样做!
}

// 推荐:输出概要信息
Logger.info(TAG, 'Processing 1000 items started');
// 处理逻辑
Logger.info(TAG, 'Processing 1000 items completed');

6.4 日志文件管理

虽然 Logger 目前只输出到控制台,但可以扩展为支持文件输出:

// 扩展:支持日志文件输出(可选)
export class Logger {
  private static enableFileLog: boolean = false;

  static enableFileLogging() {
    Logger.enableFileLog = true;
  }

  private static writeToFile(level: string, tag: string, message: string) {
    if (!Logger.enableFileLog) return;
    // 写入文件逻辑
    // 可以使用 FileIo 写入沙箱目录
  }
}

七、日志在项目中的实际应用

7.1 生命周期日志

// EntryAbility 的生命周期日志
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
  Logger.info(TAG, 'Ability onCreate');
}

onWindowStageCreate(windowStage: window.WindowStage): void {
  Logger.info(TAG, 'Ability onWindowStageCreate');
  // ...
}

7.2 网络请求日志

// 网络请求错误日志
request(config) {
  return new Promise((resolve, reject) => {
    this._instance.request(config)
      .then(res => resolve(res))
      .catch(err => {
        Logger.error('Network request failed: ' + config.url, err.message);
        reject(err);
      });
  });
}

7.3 用户操作日志

// 用户操作日志
Logger.info(TAG, 'User clicked start exam button');
Logger.info(TAG, 'User selected city: ' + city);
Logger.info(TAG, 'User completed mock exam, score: ' + score);

7.4 数据分析日志

除了调试用途,日志还可以用于数据分析:

// 记录用户行为用于分析(注意脱敏)
Logger.info(TAG, 'User action: exam_start, type: ' + examType);
Logger.info(TAG, 'User action: exam_complete, score: ' + score + ', time: ' + duration);
Logger.info(TAG, 'User action: video_watch, videoId: ' + videoId);

八、日志与性能监控

8.1 性能日志

// 记录操作耗时
const startTime = performance.now();
// 执行操作
const endTime = performance.now();
Logger.info(TAG, 'Operation completed in ' + (endTime - startTime) + 'ms');

8.2 异常日志

// 捕获并记录异常
try {
  // 可能出错的代码
} catch (error) {
  Logger.error(TAG, 'Exception caught: ' + error.message);
  Logger.error(TAG, 'Stack trace: ' + error.stack);
}

九、总结

日志系统是应用开发中不可或缺的基础设施。DriverLicenseExam 项目通过 Logger 封装实现了:

  1. 统一接口:通过 Logger 静态方法简化日志调用
  2. 分级输出:支持 debug/info/warn/error 四级日志
  3. 标签管理:每个模块使用独立的 TAG,便于日志过滤
  4. 隐私保护:通过 %{public}s / %{private}s 实现日志脱敏
  5. 可扩展性:未来可以添加文件输出、日志上传等功能

关键源码文件:

  • commons/commonLib/src/main/ets/utils/Logger.ets — 日志封装
  • products/entry/src/main/ets/entryability/EntryAbility.ets — 生命周期日志
  • commons/network/src/main/ets/models/AxiosHttpModel.ets — 网络请求日志
  • products/entry/src/main/ets/pages/mine/QuickLoginPage.ets — 用户操作日志
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐