logo
1
0
WeChat Login

feat(perf): 添加 TypeScript 层性能埋点#8

Closed
NPC
created 3 weeks ago
main
feat/issue-6-ts-perf
Edit
OverviewCommits
1
Files changed
4
AttachmentsTAPD

关联 Issue

变更摘要

本次提交为 TypeScript 代码层面添加了完整的性能埋点能力,支持微秒级耗时统计和结构化日志输出。


新增文件

src/utils/performance.ts - 性能埋点工具模块

核心功能:

  • 微秒级耗时统计:使用 process.hrtime.bigint() 实现高精度计时
  • 结构化日志输出:支持 textjson 两种格式
  • 多阶段标记追踪:createPerformanceTracker() API
  • 异步计时器:measureTimeAsync() 便捷函数
  • 性能统计收集器:performanceCollector 汇总多次测量

API 示例:

const perf = createPerformanceTracker("配置加载");
perf.start();
// ... 执行代码
perf.mark("解析JSON");
perf.mark("验证配置");
perf.end(); // 自动输出结构化日志

修改文件

src/app.ts - 关键路径埋点

埋点标识描述
env_parse环境变量解析
image_extract图片链接提取
vision_call视觉模型调用
prompt_buildAgent Prompt 构建
openclaw_callOpenClaw CLI 调用
comment_post评论发布

src/tools/cnb.ts - API 调用埋点

埋点标识描述
cnb_issue_commentIssue 评论发布耗时
cnb_pull_commentPull Request 评论发布耗时

tsconfig.json - 编译目标升级

  • targetes2018 升级到 ES2020,以支持 BigInt 字面量语法

日志格式

[perf] {stage} | total={duration}μs ({duration}ms) | {marks} | metadata={json}

示例输出:

[perf] image_extract | total=15234μs (15.23ms) | extract=5230μs,convert=8920μs
[perf] openclaw_call | total=5234567μs (5234.57ms)

[perf] ===== 性能统计汇总 =====
[perf] 总阶段数: 6
[perf] 总耗时: 5345678μs (5345.68ms)
[perf] 各阶段耗时:
  - env_parse: 123μs (0%)
  - image_extract: 15234μs (0%)
  - vision_call: 1234567μs (23%)
  - prompt_build: 4567μs (0%)
  - openclaw_call: 5234567μs (98%)
  - comment_post: 34567μs (1%)
[perf] ==========================

测试

  • TypeScript 编译通过
  • 类型检查通过

下一步

  • 等待资中工程师完成 Shell 层面埋点
  • 合并后可结合压测数据建立性能基线

NPC
reviewed

NPC
referenced pull request

OpenClaw

NPC
referenced pull request
NPC
reviewed
src/app.ts

问题: 性能追踪器未正确结束

userQuestion 为空时,函数提前 return,但 mainPerf.end() 没有被调用。这会导致性能追踪数据不完整。

建议: 在提前返回前调用 mainPerf.end()

if (!userQuestion.trim()) {
  console.log("[main] 用户输入为空,跳过");
  mainPerf.end();
  return;
}
src/tools/cnb.ts

问题: 异常分支下性能追踪器未结束

在抛出异常之前没有调用 perf.end(),导致性能数据不完整。同样的问题存在于第 76-77 行的 !CNB_TOKEN 检查。

建议: 使用 try-finally 模式确保追踪器总是被结束:

export async function postCNBComment(options: PostCommentOptions): Promise<CommentResponse> {
    const perf = createPerformanceTracker("cnb_issue_comment", { silent: true });
    perf.start();
    try {
        // ... 业务逻辑
        return result;
    } catch (error) {
        throw error;
    } finally {
        perf.end();
    }
}
src/utils/performance.ts

问题: 使用非空断言操作符 ! 存在运行时风险

durationFromStartdurationFromPrevious 在接口中定义为可选属性,但此处直接使用 ! 断言非空。虽然在 end() 方法中这些值理论上总是存在,但使用非空断言绕过了类型检查,如果逻辑变更可能引入运行时错误。

建议:

  1. 将接口中这两个字段改为必填,或在 end() 方法中添加默认值处理:
marks: marks.map((m) => ({
  name: m.name,
  durationUs: formatDuration(m.durationFromStart ?? 0n),
  durationFromPreviousUs: formatDuration(m.durationFromPrevious ?? 0n),
  percentage: m.durationFromStart 
    ? Number((m.durationFromStart * 100n) / totalDurationNs) 
    : 0
})),

评审结果: 通过

代码质量良好,未发现明显问题。

优点

  1. 性能追踪器设计合理,支持多种输出格式(text/json/both)
  2. 提供了完整的类型定义和接口
  3. 全局收集器支持多阶段性能汇总
  4. cnb.ts 中使用 silent 模式避免不必要的日志输出

建议(可选):

  • 可以考虑添加性能阈值告警功能
  • 可以将 PerformanceCollector 改为单例模式,方便全局访问
closed the pull request
Pull request has conflict
Reviewer
(小桂子)
Assignee
None yet
Label
None yet
Participant