add-diag-instrumentation
Skill2 starsChanged 6 months agoApache-2.0View on GitHub
为 .NET 代码(weldone 项目优先)添加 EventSource 结构化诊断事件源 + dotnet-monitor 崩溃自动 dump 配置。是 add-diag-logs(改源码加 ILogger 文本日志)的升级版:埋点一次性完成、平时零开销、运行时按需动态开启、不用为加日志重新发版。触发场景:(1) 用户要求"加事件源""加 EventSource""埋诊断点""加 instrumentation""配置崩溃 dump""加动态诊断";(2) 调查需要长期反复收集数据的偶发问题(加 ILogger 成本太高);(3) 实施飞书文档「源码保护设计方案」第九章 .NET 动态诊断工具链;(4) 用户要求把某个方法/流程"可追踪""可观测"。仅添加诊断代码,不修改业务逻辑。
In this repository60 other files it gives its agents.
- .claude/CLAUDE.mdCLAUDE.md
- add-diag-logsSkill
- archive-importSkill
- archive-sessionSkill
- archiveSkill
- ask-mattSkill
- build-publish-runSkill
- coarse-compensation-fitSkill
- codebase-designSkill
- code-simplifySkill
- commitSkill
- create-weld-docSkill
- DDD-reviewSkill
- diagnosing-bugsSkill
- domain-modelingSkill
- feishu-webhookSkill
- git-branch-mergeSkill
- gitlab-issueSkill
- gitlab-merge-requestSkill
- gitlab-opsSkill
- grillingSkill
- grill-meSkill
- grill-with-docsSkill
- handoffSkill
- implementSkill
- improve-codebase-architectureSkill
- knowledge-reorgSkill
- modelbase-fsmSkill
- modelbase-fsm-updateSkill
- opsx-reindexSkill
- opsx-searchSkill
- parallel-featureSkill
- periodic-reviewSkill
- prototypeSkill
- read-diag-capturesSkill
- robim-data-explorerSkill
- robimweld-release-checkSkill
- robimweld-source-debugSkill
- robot-to-worldSkill
- setup-matt-pocock-skillsSkill
- skill-creatorSkill
- superpowersSkill
- tddSkill
- teachSkill
- three-blazor-devSkill
- to-issuesSkill
- to-prdSkill
- triageSkill
- weldone-animationSkill
- weldone-current-urdfSkill
- weldone-db-migrationSkill
- weldone-hybrid-seam-replay-debugSkill
- weldone-mapmatrix-domain-knowledgeSkill
- weldone-project-logsSkill
- weldone-transition-line-domain-knowledgeSkill
- weldone-wsg-merge-domain-knowledgeSkill
- weld-plan-debugSkill
- weld-seam-normal-vectorsSkill
- world-to-robotSkill
- writing-great-skillsSkill
The file
Files
诊断埋点(EventSource + dotnet-monitor)
为 .NET 代码添加运行时动态诊断能力。与 add-diag-logs(注入 ILogger 文本日志,每次要改源码发版)互补:本 skill 埋的是 EventSource 结构化事件,编译期一次性完成,运行时默认零开销,出问题时用 dotnet-trace/dotnet-monitor 远程动态开启抓取,无需重新发版。
详细的事件设计原则、参数约束、weldone 已有 EventSource 清单,见 references/instrumentation-guide.md。埋点前必读。
核心判断:先决定用哪种诊断
收到埋点请求后,先判断问题形态,决定工具,不要无脑加 EventSource:
| 问题形态 | 工具 | 本 skill 是否适用 |
| 一次性 bug,加几条日志就能定位 | add-diag-logs(ILogger) | ❌ 用 add-diag-logs,本 skill 杀鸡用牛刀 |
| 偶发问题,需长期反复收集数据 | EventSource(本 skill) | ✅ 正是为此设计 |
| 需要全流程性能剖析(哪一步慢) | dotnet-trace + EventSource | ✅ 两者配合 |
| 需要看某个对象全部字段值(含未埋点的) | dotnet-dump | ⚠️ 不需要埋点,直接抓 dump |
| 崩溃后需自动留现场 | dotnet-monitor Collection Rule | ✅ 用本 skill 的 dump 配置流程 |
决策原则:能用 ILogger 解决的别上 EventSource;偶发/难复现/需长期观测的才上 EventSource;要看未埋点对象的字段值用 dump。
工作流程
步骤一:分析埋点目标
- 读取用户指定的方法/流程源码,理解:输入参数、输出、内部关键分支、外部调用、循环
- 识别"出问题时最想知道什么"——这是事件参数的设计依据(见下文"参数设计")
- 检查目标类是否已有 EventSource 引用(grep
EventSourcein 目标文件及同目录)
步骤二:选择或创建 EventSource
判断目标代码所属业务域,匹配现有 EventSource 或新建:
- 读
references/instrumentation-guide.md的「weldone EventSource 清单」章节,看目标域是否已有 EventSource - 已有 → 在其中追加
[Event(id)]方法,id 接续现有最大值 +1 - 没有 → 新建 EventSource 文件,命名用业务域(
Robim-WeldPlanning),不用类名/方法名- 放在目标代码所在工程下的
Diagnostics/或根目录 [EventSource(Name = "Robim-{业务域}")]
- 放在目标代码所在工程下的
命名约束(混淆兼容):EventSource 的 Name 是字符串常量,不受代码混淆影响。务必用业务语义命名(Robim-WeldPlanning、Robim-RobotControl、Robim-VisionPositioning),这样混淆后照样能 dotnet-trace --providers Robim-WeldPlanning 开启。
步骤三:设计事件参数(最关键)
EventSource 的价值在于带变量值,不是只发"进入/离开"信号。光有调用关系无法定位——必须带上问题定位所需的输入输出值。详细规则见 references/instrumentation-guide.md 的「参数设计」章节,核心要点:
- WriteEvent 参数类型硬限制:只接受
string/int/long/float/double/bool/byte+ 这些类型的一维数组。不能传自定义类、struct(含 Matrix4x4)、接口、字典。复杂对象必须拆解为基础类型。 - 位姿/矩阵拆解:weldone 大量用
Matrix4x4、Pose。埋点时拆成posX,posY,posZ+ 旋转矩阵 9 个分量(或四元数 4 个分量),别整体传。 - 集合取摘要:
List<T>传Count+ 前几个关键元素(如前 3 个焊缝的 seamIndex),别传整个集合。 - 每类事件至少带:业务 ID(workpieceId/seamIndex,用于关联同一流程)、success/durationMs(用于判断是否异常)。
步骤四:埋点(改业务代码)
在目标方法的关键位置插入 EventSource 调用。不修改任何业务逻辑,只添加事件触发语句。
埋点位置(按优先级):
- 方法入口 —
XxxStart(businessId, keyInputParams...) - 方法返回前 —
XxxEnd(businessId, success, durationMs, keyOutputValues...) - 慢操作阈值 — 超过阈值时发
XxxSlow(businessId, durationMs, context)(warning 级别) - 关键分支 — 走了哪个分支 + 判断条件值
- 外部调用(P/Invoke、设备通信、DB)前后 — 入参 + 返回值 + 耗时
耗时测量用 Stopwatch,必须用 System.Diagnostics.Stopwatch,不要用 DateTime.Now 相减(精度差且有夏令时问题)。
// 标准埋点模式
public bool TryCalculateWeldToolPoses(WsWeldPosParam param, PoseCalculationMode mode, ...)
{
var sw = Stopwatch.StartNew();
WeldPlanningEventSource.Log.PoseCalcStart(param.WorkpieceId, param.SeamIndex, param.TotalSeams, mode.ToString());
// ... 原有业务逻辑完全不变 ...
bool success = calSuc >= 0;
WeldPlanningEventSource.Log.PoseCalcEnd(
param.SeamIndex, success, sw.Elapsed.TotalMilliseconds, resultPoints.Count);
if (sw.Elapsed.TotalMilliseconds > 3000)
WeldPlanningEventSource.Log.PoseCalcSlow(param.SeamIndex, sw.Elapsed.TotalMilliseconds, resultPoints.Count);
return success;
}步骤五:dotnet-monitor 配置(仅崩溃 dump 任务)
若用户要求配置崩溃自动 dump / 性能自动 trace,走此步骤:
- 确认目标机器已安装 dotnet-monitor(作为 Windows 服务,不随主程序启动)
- 生成或更新
settings.json的CollectionRules段 - 必须配置 FSM 状态门控:weldone 涉及机器人运动,抓 dump 会冻结进程(STW)几百 ms~数秒。焊接进行中(FSM.State == Welding 相关态)禁止触发重型诊断,否则可能撞机。门控逻辑见
references/instrumentation-guide.md的「FSM 状态门控」章节 - 鉴权:诊断 API 等于进程控制权,必须配 API Key,禁止裸暴露端口
- 配置 dump 滚动保留(最近 3-5 个,旧的自动删,避免磁盘爆满)
执行约束
- 不修改任何业务逻辑,只添加诊断代码(EventSource 调用、Stopwatch、EventSource 类定义)
- EventSource 类本身和
[Event]方法是纯增量,不影响现有逻辑 WriteEvent在未被监听时开销纳秒级(直接 return),生产环境零负担——但不要在每秒执行上万次的热循环里埋点,累积开销不可忽略- 复杂对象拆解为基础类型时,避免在拆解过程中做昂贵的序列化/计算——EventSource 参数应该是廉价取值(属性访问、字段读取)
- Stopwatch 创建在方法栈上,无分配压力,可放心使用
输出格式
完成后输出埋点报告:
已添加诊断埋点:
- EventSource: Robim-WeldPlanning(src/Robim.Algorithm.Weld/Diagnostics/WeldPlanningEventSource.cs)
- 新增事件:PoseCalcStart(8)/PoseCalcEnd(9)/PoseCalcSlow(10)
- 埋点位置:
- src/Robim.Algorithm.Weld/Solver/WeldPoseSolver.cs::TryCalculateWeldToolPoses — 入口+出口+慢阈值 (3s)
- src/Weldone.Domain/PostProcessing/CoarsePostProcessGenerator.cs::Generate — 入口+出口
验证方式:
1. 编译:dotnet build src/Robim.Algorithm.Weld/...
2. 运行程序后另开终端:dotnet-trace collect -p <PID> --providers Robim-WeldPlanning --duration 00:00:30
3. 复现问题,查看 .speedscope.json 或 nettrace 中的事件流与 add-diag-logs 的关系
| 维度 | add-diag-logs (ILogger) | 本 skill (EventSource) |
| 触发方式 | 一直在记 | 默认关,运行时动态开 |
| 开销 | 有 IO 开销 | 未启用≈0 |
| 内容 | 文本日志 | 结构化事件,带类型化参数 |
| 修改成本 | 每次改源码+发版 | 一次性编译期,之后不再改 |
| 适用 | 日常审计、粗粒度流程、一次性定位 | 偶发问题、深度诊断、性能剖析 |
两者并存:ILogger 做日常厚日志,EventSource 做深度诊断探针。一个流程可以同时有两者的埋点。
配套读取器:read-diag-captures
本 skill 负责埋点和采集(写 EventSource、跑 dotnet-trace/dump 抓数据),产物落点约定在 <项目目录>/Diagnostics/。解读这些产物用配套 skill read-diag-captures:它定位 Diagnostics 目录、把事件 ID 翻译成事件名+参数含义(见 references/instrumentation-guide.md 与 read-diag-captures/references/eventsource-catalog.md,两份保持同步)、按文件类型(.nettrace/.dmp/.csv/.speedscope.json)给出解读方法。
| 阶段 | 文本日志线 | 结构化诊断线 |
| 埋点/注入 | add-diag-logs | 本 skill(add-diag-instrumentation) |
| 读取/解读 | weldone-project-logs | read-diag-captures |
一个偶发问题的完整排查路径:先用本 skill 埋 EventSource → 复现时 dotnet-trace 抓取 → 用 read-diag-captures 解读事件流定位。
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

