关于 log-coverage-analyzer
log-coverage-analyzer 是用于代码仓库的日志覆盖分析技能,面向需要检查日志完整性与性能风险的开发者。它沿调用链检查分支和错误返回路径,并识别高频函数中的日志风险,生成 Markdown 报告。
主要功能
- 01按调用链检查分支日志覆盖
- 02检查错误返回路径的 LOGE
- 03识别高频函数中的日志风险
- 04按优先级分类日志缺陷
- 05生成含修复建议的 Markdown 报告
适用场景
- 01审查代码中的错误路径日志
- 02排查网络回调中的高频日志
- 03检查多步骤操作的成功日志
- 04生成日志审计报告
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ openharmonyinsight/ openharmony-skills --skill log-coverage-analyzer安装后在 Claude Code 中输入/log-coverage-analyzer确认已加载。
详细介绍
此技能可对代码仓库进行全面的日志覆盖率分析,识别调用链中的日志缺失,并检测可能影响性能的高频日志风险。
分析原则
日志级别定义
| 日志级别 | 行为 | 使用场景 |
|---|---|---|
| LOGE | 始终打印,不会丢失 | 严重 - 所有错误返回路径都必须有此日志 |
| LOGI | 始终打印;若同一位置触发频率过高,日志可能丢失 | 重要 - 成功路径、关键操作 |
| LOGD | 仅在启用调试开关时打印 | 可选 - 仅用于调试信息 |
| LOGW | 仅在启用调试开关时打印 | 可选 - 仅用于警告信息 |
核心分析规则
- 日志覆盖规则:函数调用链中的每个分支都必须包含 LOGE 或 LOGI 级别的日志
- 高频风险规则:可能频繁调用(循环、定时器、回调、事件处理器)的函数中若包含 LOGE/LOGI 日志,则存在性能风险
- 错误路径规则:所有错误返回路径都必须包含 LOGE 日志
- 上下文规则:所有日志都必须包含足够的上下文信息(ID、状态、参数)
执行工作流
步骤 00:创建分析计划
说明:开始前创建详细的分析计划
操作:
- 使用
TodoWrite工具创建任务列表 - 规划分析范围:
- 查找并筛选源文件
- 提取函数调用链
- 分析各分支的日志覆盖情况
- 检测高频风险
- 生成报告
输出:通过 TodoWrite 工具创建分析计划
步骤 01:发现源文件
说明:查找仓库中所有相关源文件
操作:
- 使用
Glob工具,根据语言模式查找源文件:- C/C++:
**/*.cpp、**/*.cc、**/*.cxx、**/*.h、**/*.hpp - Java:
**/*.java - Python:
**/*.py - JavaScript/TypeScript:
**/*.js、**/*.ts - Go:
**/*.go - Rust:
**/*.rs
- C/C++:
- 如有指定,则排除测试文件(模式:
**/test/**、**/tests/**、**/*_test.*) - 排除构建目录(模式:
**/build/**、**/out/**、**/target/**)
输出:待分析的源文件列表
步骤 02:扫描日志模式
说明:扫描所有源文件中的日志宏/函数
操作:
- 使用
Grep工具,按以下模式查找日志语句:- 不区分大小写搜索:
LOG[DEIW]、HILOG[DEIW]、ALOG[DEIW] - 同时搜索:
\.log[deiw]\(、Log\.[deiw]、LOG\.
- 不区分大小写搜索:
- 统计每个文件中的出现次数
- 确定日志级别分布
输出:各文件的日志统计信息
步骤 03:提取函数和调用链
说明:解析源文件,提取函数定义和调用关系
操作:
- 对每个源文件:
- 识别函数定义(各语言的不同模式)
- 提取包含所有分支的函数体
- 识别各函数中的函数调用
- 构建调用链图
- 映射分支条件(if/else、switch/case、try/catch、提前返回)
输出:包含调用关系的函数列表
步骤 04:分析各分支的日志覆盖情况
说明:检查调用链中的各个分支是否包含所需日志
操作:
- 对调用链中的每个函数:
- 识别所有分支:
- 提前返回
- if/else 分支
- switch/case 分支
- try/catch 块
- 带错误条件的循环退出
- 检查每个分支是否包含 LOGE 或 LOGI
- 将缺少所需日志的分支标记为 日志缺失
- 专门检查错误返回路径是否包含 LOGE
- 识别所有分支:
缺失分类:
- 高优先级:错误返回路径缺少 LOGE
- 中优先级:多步骤操作的成功路径缺少 LOGI
- 低优先级:分支完全没有日志(非关键)
输出:包含位置的日志缺失列表
步骤 05:检测高频日志风险
描述:识别包含 LOGE/LOGI 且可能被频繁调用的函数
操作:
- 识别高频函数模式:
- 网络数据回调(
OnDataReceived、OnPacketReceived、OnMessage) - 定时器回调(
OnTimer、Tick、Update) - 事件处理程序(
HandleEvent、ProcessEvent、OnEvent) - 循环操作(
ProcessItem、HandlePacket、SendData) - 流处理(
ProcessStream、HandleFrame、EncodeFrame) - 消息队列处理程序(
OnMessage、Dispatch)
- 网络数据回调(
- 对于这些模式中包含 LOGE/LOGI 的函数:
- 分析潜在调用频率
- 划分风险等级:高/中/低
- 标记为高频风险
风险分类:
- 高风险:数据路径中按数据包/帧记录 LOGE/LOGI
- 中风险:消息路径中按消息记录 LOGI
- 低风险:记录日志的低频回调
输出:列出高频风险及其位置
步骤 06:生成分析报告
描述:根据所有发现创建全面的分析报告
操作:
- 生成 Markdown 报告,包含:
- 汇总统计信息
- 日志缺失项及修复建议
- 高频风险及修复建议
- 调用链分析
- 详细代码示例
- 使用
Write工具将报告保存到log-coverage-report-YYYYMMDD-HHmmss.md
输出:完整的分析报告
特定语言模式
C/C++
函数定义模式:
[return_type] [class::]function_name([parameters]) {
[\w\s:*,]*\{
日志模式:
LOG[DEIW]\(、HILOG[DEIW]\(、ALOG[DEIW]\(__android_log_printOHOS::HiviewDFX::HiLog::[Error|Warn|Info|Debug]
Java
函数定义模式:
(public|private|protected)?(\s+static)?\s+\w+\s+\w+\s*\(.*\)\s*(throws\s+[\w\s,]+)?\s*\{
日志模式:
Log\.[deiw]\(Logger\.(error|warn|info|debug)\(Timber\.[deiw]\(
Python
函数定义模式:
def\s+\w+\s*\(.*\)\s*->?\s*.*:
日志模式:
logger\.(error|warning|info|debug)\(logging\.(error|warning|info|debug)\(print\(
JavaScript/TypeScript
函数定义模式:
function\s+\w+\s*\(.*\)\s*\{
|\w+\s*\([^)]*\)\s*(=>|\{)
日志模式:
console\.(error|warn|info|log)\(logger\.(error|warn|info|debug)\(
修复建议
针对日志缺失项
错误返回路径(必须修复):
// BEFORE:
if (remote == nullptr) {
return ERR_NULL_OBJECT; // ❌ No LOGE
}
// AFTER:
if (remote == nullptr) {
HILOGE("FunctionName: remote is null, context=%{public}d", context);
return ERR_NULL_OBJECT;
}
成功路径(应该修复):
// BEFORE:
int32_t CreateSession(...) {
// ... initialization code
return ERR_OK; // ❌ No LOGI on success
}
// AFTER:
int32_t CreateSession(...) {
// ... initialization code
HILOGI("CreateSession: success, sessionId=%{public}d, name=%{public}s", id, name);
return ERR_OK;
}
针对高频风险
移除高频 LOGI:
// BEFORE:
void OnPacketReceived(int socketId, const void* data, uint32_t len) {
HILOGI("packet received: socket=%{public}d, len=%{public}u", socketId, len); // ⚠️ Per-packet
// ... process packet
}
// AFTER:
void OnPacketReceived(int socketId, const void* data, uint32_t len) {
// Removed per-packet LOGI
static std::atomic<uint64_t> packetCount{0};
if (++packetCount % 1000 == 1) {
HILOGI("Packet stats: count=%{public}llu, socket=%{public}d",
packetCount.load(), socketId);
}
// ... process packet
}
对错误使用限流 LOGE:
// BEFORE:
void ProcessPacket(const Packet* pkt) {
if (pkt == nullptr) {
HILOGE("packet is null"); // ⚠️ Per-packet error
return;
}
}
// AFTER:
void ProcessPacket(const Packet* pkt) {
if (pkt == nullptr) {
static std::atomic<uint32_t> errorCount{0};
if (++errorCount % 100 == 1) {
HILOGE("ProcessPacket: null packet, count=%{public}u", errorCount.load());
}
return;
}
}
输出格式
================================================================================
Log Coverage Analysis Report
================================================================================
Repository: <repository_path>
Analysis Date: <timestamp>
Files Analyzed: <count>
## Summary Statistics
| Metric | Count |
|--------|-------|
| Total Source Files | <number> |
| Total Functions | <number> |
| Functions Analyzed | <number> |
| Log Deficiencies | <number> |
| High-Frequency Risks | <number> |
## Log Deficiencies
### [High/Medium/Low] Priority
**File**: `<file_path>`
**Function**: `<function_name>`
**Lines**: `<line_range>`
**Issue**: `<description>`
**Evidence**:
```cpp
<code snippet>
影响: <说明对调试/故障排查的影响>
修复:
<fixed code>
高频风险
[高/中/低] 风险
文件:<file_path>
函数:<function_name>
行号:<line_range>
风险:
证据:
<code snippet>
分析: <说明为何属于高频>
修复:
<fixed code with throttling/statistics>
调用链分析
调用链:<chain_name>
<function_1>()
↓ [✓/✗/⚠️] <log_status>
<function_2>()
↓ [✓/✗/⚠️] <log_status>
<function_3>()
├─ [✓/✗/⚠️] branch_1
├─ [✓/✗/⚠️] branch_2
└─ [✓/✗/⚠️] branch_3
图例:
- ✓:包含所需的 LOGE/LOGI
- ✗:缺少所需日志
- ⚠️:存在高频日志风险
建议
立即采取的措施(P0)
<关键事项列表>
后续措施(P1)
<重要事项列表>
长期改进(P2)
<改进建议列表>
================================================================================
## Parameters
| Parameter | Required | Description |
|-----------|----------|-------------|
| `--path` | No | Repository path (default: current directory) |
| `--exclude-tests` | No | Exclude test files (default: true) |
| `--lang` | No | Language filter (cpp, java, python, js, all) |
| `--output` | No | Output report path |
## Usage Examples
分析当前目录
/log-coverage-analyzer
分析指定仓库
/log-coverage-analyzer --path /path/to/repo
仅分析 C++ 代码
/log-coverage-analyzer --lang cpp --path /path/to/repo
在分析中包含测试文件
/log-coverage-analyzer --exclude-tests false
自定义输出位置
/log-coverage-analyzer --output /path/to/report.md
## Tips
- Use `Grep` with `output_mode: content` and `-B/-C` flags for context
- Use `Read` tool with `offset` and `limit` for large files
- For large repositories, focus on critical directories first
- High-frequency risks should be prioritized over minor log deficiencies
- Always include context (IDs, states, parameters) in LOGE messages