agentsdk-go 采用双层 trace 体系,在不同抽象层面捕获可观测性数据:
- HTTP Layer Trace:位于最外层 HTTP server,零侵入记录完整的请求/响应循环(含 SSE 流),主要服务 API 集成与网络疑难排查。
- Middleware Layer Trace:挂载在 agent/middleware 链的 6 个拦截点上,输出模型与工具调用的全部上下文与性能指标,用于深入理解 Agent 执行路径。 两条链路可单独启用,也可以并行开启实现端到端追踪。
- 捕获 HTTP 请求的 method、URL、headers(统一小写)以及 JSON/二进制请求体,必要时自动解析 body 为结构化 JSON。
- 捕获完整响应:status_code、headers、body_raw;若响应为 SSE,
body_raw保留原始 event: 行,便于重放。 - 自动脱敏敏感头(
authorization、x-api-key等),仅保留首尾 5 个字符或用*填充短 token。 - 支持 streaming:自定义
responseRecorder透传http.Flusher/http.Hijacker,既不影响实时推送也能收集片段并标记...(truncated)。 - 可配置 Body 捕获上限(默认 1 MiB),避免日志放大;limit=0 可禁用 body,limit<0 则捕获完整负载。
HTTP trace 写到 .http-trace/log-YYYY-MM-DD-HH-MM-SS.jsonl,每行一个完整事件。下面示例参考 .http-trace/log-2025-11-19-08-46-48.jsonl:
{
"request": {
"timestamp": 1763542011.267,
"method": "POST",
"url": "http://localhost:23000/v1/messages?beta=true",
"headers": {
"accept": "application/json",
"anthropic-version": "2023-06-01",
"content-type": "application/json",
"user-agent": "claude-cli/2.0.34 (external, cli)",
"x-api-key": "sk-bf68d...419e"
},
"body": {
"model": "claude-haiku-4-5-20251001",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "Please write a 5-10 word title for the following conversation:..."
}
]
}
],
"system": [
{"type": "text", "text": "You are Claude Code, Anthropic's official CLI for Claude."},
{"type": "text", "text": "Summarize this coding conversation in under 50 characters."}
],
"tools": [],
"metadata": {
"user_id": "user_9a40d06fc56208d37837a869f78d4328467bc633cdaf025ca626316642e2fea8_account__session_6ef651a3-6819-4bda-ac34-59ba978b80a6"
},
"max_tokens": 32000,
"stream": true
}
},
"response": {
"timestamp": 1763542013.862,
"status_code": 200,
"headers": {
"content-type": "text/event-stream",
"cache-control": "no-cache",
"connection": "keep-alive",
"date": "Wed, 19 Nov 2025 08:46:53 GMT"
},
"body_raw": "event: message_start\ndata: {\"type\":\"message_start\",...}"
},
"logged_at": "2025-11-19T08:46:54.078Z"
}提示:示例 body_raw 仅展示前几帧 SSE 文本,实际文件保留完整 event stream。
在自定义 HTTP server 中包裹最外层 mux:
httpTraceDir := filepath.Join(projectRoot, ".http-trace")
writer, err := middleware.NewFileHTTPTraceWriter(httpTraceDir)
if err != nil {
log.Printf("HTTP trace disabled: %v", err)
} else {
httpTrace := middleware.NewHTTPTraceMiddleware(
writer,
middleware.WithHTTPTraceMaxBodyBytes(2<<20),
)
handler := httpTrace.Wrap(mux) // mux 为业务 handler
server := &http.Server{Addr: ":8080", Handler: handler}
log.Printf("HTTP trace writing to %s", writer.Path())
go server.ListenAndServe()
}该中间件与现有 router/otel 链兼容,不要求应用代码感知 trace。
- 输出目录:
NewFileHTTPTraceWriter(dir)默认.http-trace;可指定绝对/相对路径或接入共享卷。 - Body 大小限制:通过
WithHTTPTraceMaxBodyBytes(limit)控制;limit=0 不抓取正文,limit<0 表示无限制。 - 自定义 writer:实现
HTTPTraceWriter接口即可落地到对象存储、队列或第三方 SIEM。 - 测试友好:
WithHTTPTraceClock支持注入假时钟,便于比对 deterministic 日志。
- 六个拦截点:
before_agent → before_model → after_model → before_tool → after_tool → after_agent全覆盖 agent 生命周期。 - 模型输入/输出快照:
model_request保存 messages/system/tools/max_tokens,model_response保存 content/tool_calls/usage/stop_reason/stream 元数据。 - 工具链路:记录
tool_call(id/name/input/path)与tool_result(content/error/is_error),方便重放。 - 性能指标:自动打点
duration_ms(模型、工具、agent 三类时长),并统计iteration、session_id、错误信息。 - 汇总统计:累积 total tokens、total duration,并写入 HTML Viewer 的指标卡与徽章。
- JSONL:
.trace/log-2025-11-19T14:26:28Z.jsonl等文件存储机器可读事件:所有字段均在单行 JSON 中,方便{"timestamp":"2025-11-19T22:26:28.109153+08:00","stage":"before_agent","iteration":0,"session_id":"web-chat-session","input":{"Iteration":0,"Values":{}},"duration_ms":0} {"timestamp":"2025-11-19T22:26:35.606617+08:00","stage":"after_model","iteration":0,"session_id":"web-chat-session","output":{"Content":"你好!...","Done":true},"model_response":{"content":"你好!...","usage":{"input_tokens":2870,"output_tokens":214,"total_tokens":3084}},"duration_ms":7494}jq/rg/SIEM 消化。 - HTML Viewer:同名
.html由traceHTMLTemplate渲染。核心能力:- 顶部仪表盘展示 Total Tokens / Total Duration / Events。
- Timeline 以
<details>展示事件,附带 stage badge、duration/token/error 徽章。 - JSON 高亮 + 折叠(Model Request/Response 默认折叠,可展开查看 messages/system/tool_calls)。
- 底部 footer 标注生成时间及对应 JSONL 文件,便于跳转日志。
将 TraceMiddleware 注入 agent middleware 链(pkg/agent/agent.go):
traceMW := middleware.NewTraceMiddleware(filepath.Join(projectRoot, ".trace"))
chain := middleware.NewChain([]middleware.Middleware{traceMW})
agent, err := agent.New(modelProvider, toolExec, agent.Options{Middleware: chain})
if err != nil { log.Fatal(err) }
result, err := agent.Run(ctx, agentCtx)若已有其它 middleware,可传入切片初始化或使用 chain.Use(traceMW) 追加。
| 特性 | HTTP Trace | Middleware Trace |
|---|---|---|
| 目的 | 调试 HTTP 交互、验证签名、排查网络/篮筐 | 调试 Agent 执行流程、prompt 质量、工具编排 |
| 输出目录 | .http-trace/ |
.trace/ |
| 格式 | JSONL(原始 HTTP 事件) | JSONL + HTML Viewer |
| 粒度 | 每次 HTTP request/response(含 streaming 片段) | 每个 middleware stage(可跨多次模型/工具) |
| 捕获数据 | method/url/headers/body_raw + 脱敏密钥 | messages/system/tools/usage、tool call/result、metrics |
| Streaming 支持 | 原样写入 SSE/Chunked,保留事件顺序 | 通过 model_response.stream 字段引用上游流事件 |
| 可视化 | 需外部工具(jq、tail、SIEM) | 内建交互式 HTML,含统计面板与 JSON 高亮 |
| 典型消费者 | API/平台团队、网络层 SRE | Prompt 工程、Agent/Tool 开发者、应用层 SRE |
- 开发/测试环境默认开启两种 trace,配合
tail -f+ HTML 查看器快速定位问题。 - 生产环境应按需开启:HTTP trace 只在疑难票据阶段打开,Middleware trace 可在少量会话上采样,以免写 I/O 过大。
- 通过 logrotate/cron 定期清理
.http-trace/与.trace/(建议保留最近 7 天或 <5 GB)。 - 统一将 trace 目录加入
.gitignore,防止意外提交。 - 在下游分析前再次脱敏(尤其是 request.body 和 tool 参数),或为敏感字段提供自定义
HTTPTraceWriter/sanitizePayloadwrapper。
- 没有生成
.http-trace文件:确认 HTTP middleware 包裹在最外层 mux;若 server 提前返回错误,日志会写在 stderr。 - SSE/长响应被截断:检查
WithHTTPTraceMaxBodyBytes是否足够,必要时设置为负数并监控磁盘。 - HTML Viewer 不更新:TraceMiddleware 每次事件会 rewrite HTML;若看到旧时间戳,检查
.trace目录写权限或磁盘满。 - JSONL 体积过大:结合
limit=0关闭 HTTP body,或在 Middleware trace 中仅对关键 session 设置trace.session_id,避免长跑任务写入所有事件。 - 工具结果缺失:确保工具执行后将结果写入
State.ToolResult(SDK 默认已写);如有自定义 middleware 修改State,请勿覆盖ToolResult。