追踪系统
可观测性对任何 LLM 网关都至关重要。GodeX 的追踪系统捕获整个请求生命周期中的每个请求、token 使用量事件、流式事件和错误,将它们持久化到 SQLite 用于离线分析。系统专为生产吞吐量设计:AsyncTraceRecorder 在队列中批量处理事件,并定期或在批量大小阈值达到时刷新,使热路径免于磁盘 I/O。当追踪被禁用时,NoopTraceRecorder 以零开销替代真实的记录器。
追踪系统通过 TraceRecordingContext 附加到 ResponsesContext,因此任何有权访问上下文的代码都可以发出追踪记录,而无需了解存储后端。
概览
| 组件 | 文件 | 用途 |
|---|---|---|
TraceRecorder | recorder.ts:5-8 | 核心接口(record、close) |
AsyncTraceRecorder | recorder.ts:30-110 | 基于队列的批量记录器 |
NoopTraceRecorder | recorder.ts:25-28 | 追踪禁用时的零操作记录器 |
SQLiteTraceStore | sqlite.ts:69-297 | 具有四张表的 SQLite 存储 |
TraceRecordEvent | types.ts:70-74 | 所有记录类型的联合类型 |
mapTraceRecordToRow | row-mapper.ts:16-98 | 将事件转换为存储行 |
summarizePayload | payload.ts:10-35 | SHA-256 哈希、字节数、可选 JSON 捕获 |
TraceRecordingContext | context.ts:4-12 | 附加到每个请求的上下文 |
createTraceServices | trace-services.ts:15-34 | 基于配置的工厂函数 |
架构概览
TraceRecorder 接口
TraceRecorder 接口(recorder.ts:5-8)设计上保持最小化:
| 方法 | 描述 |
|---|---|
record(event) | 将追踪事件入队等待持久化 |
close() | 刷新剩余事件并释放资源 |
AsyncTraceRecorder
生产环境记录器(recorder.ts:30-110)使用内存队列,具有两个刷新触发器:
配置选项
| 选项 | 类型 | 描述 |
|---|---|---|
maxQueueSize | number | 队列中的最大事件数;溢出时丢弃 |
batchSize | number | 每次刷新的事件数量 |
flushIntervalMs | number | 自动刷新的定时器间隔 |
store | TraceStoreWriter | 存储后端(通常是 SQLiteTraceStore) |
logger | TraceRecorderLogger | 用于记录丢弃和错误警告 |
capturePayload | boolean | 是否存储完整的 JSON 负载 |
payloadMaxBytes | number | 存储负载的字节限制 |
SQLiteTraceStore
SQLite 存储(sqlite.ts:69-297)在构造时自动迁移四张表:
数据库 Schema
批量插入包装在事务中(sqlite.ts:90-95)以确保原子性。在 request_id、response_id、event_name 和 code 上创建索引以优化常见查询模式。
追踪记录类型
TraceRecordEvent 联合类型(types.ts:70-74)有四种变体:
| 类型 | 接口 | 关键字段 |
|---|---|---|
request | TraceRequestRecordEvent | stream、requested_prompt_cache_key、payload |
usage | TraceUsageRecordEvent | usage(input_tokens、output_tokens、total_tokens、cached_tokens、reasoning_tokens、cache_hit_ratio) |
event | TraceEventRecordEvent | event_name、sequence、payload |
error | TraceErrorRecordEvent | event_name、error_type、domain、code、message、status、payload |
所有变体共享 TraceRecordBase(types.ts:19-25),包含 request_id、response_id、provider、model 和 created_at。
事件名称
TraceEventRecordEvent 将 event_name 限制为(types.ts:50-54):
| 事件名称 | 记录时机 |
|---|---|
provider.request.prepared | 最终 provider 请求已经完成 patch,即将进入 provider client;该事件不存储请求体 |
provider.response.body | 从上游接收的同步响应体 |
upstream.stream.event.raw | 来自上游的原始 SSE 数据块 |
upstream.stream.event.transformed | 桥接层转换后的事件 |
Provider 请求 payload 存储在 trace_requests,不会在 trace_events 中重复保存。把 request 行和 provider.request.prepared 事件关联起来,就能同时看到最终 patched 请求摘要以及进入 provider client 前的生命周期点。prepared 事件在 provider patchRequest hook 执行之后、request() 或 stream() 调用 provider client 的 HTTP 操作之前记录;它不表示网络发送一定已经成功。
负载捕获
summarizePayload(payload.ts:10-35)控制存储多少数据:
| 模式 | capturePayload | payload_json | payload_hash |
|---|---|---|---|
| 仅摘要 | false | null | 完整 JSON 的 SHA-256 十六进制值 |
| 完整捕获 | true | 完整 JSON 字符串(不超过 payloadMaxBytes) | SHA-256 十六进制值 |
| 截断捕获 | true | 截断的 JSON 字符串 | SHA-256 十六进制值 |
payload_bytes 字段始终记录原始字节长度,无论是否截断(payload.ts:23-24)。哈希使用 Bun.CryptoHasher("sha256") 计算(payload.ts:6-8)。
行映射
mapTraceRecordToRow(row-mapper.ts:16-98)根据 event.kind 分派:
| 类型 | 目标表 | 负载处理 |
|---|---|---|
request | trace_requests | 通过 summarizePayload 摘要 |
usage | trace_usage | 直接从 TraceUsageSnapshot 提取字段 |
event | trace_events | 通过 summarizePayload 摘要 |
error | trace_errors | 通过 summarizePayload 摘要 |
如果任何事件的序列化失败,映射器返回 null 并记录警告,而不是导致刷新崩溃(row-mapper.ts:91-97)。
记录辅助函数
四个辅助函数附加到 TraceRecordingContext,提供便捷的记录方式:
recordTraceRequest
request-recorder.ts:4-22 在 provider hooks 执行之后记录最终 patched provider 请求,包括是否为流式请求、可选的 prompt_cache_key,以及 provider 请求体的可选 payload 摘要。配套的 provider.request.prepared trace event 只标记生命周期点,不再次携带请求体。
recordTraceUsage
usage-recorder.ts:6-22 通过 traceUsageFromResponseUsage(usage.ts:4-23)将 ResponseUsage 转换为 TraceUsageSnapshot,同时在两者都可用时计算 cache_hit_ratio 为 cached_tokens / input_tokens。
recordTraceEvent
event-recorder.ts:5-25 记录一个命名事件,带有可选的负载和用于流内排序的序列号。
recordTraceError
error-recorder.ts:5-27 从 GodeXError 或通用错误中提取错误元数据(类型、领域、错误码、消息、状态码),并以完整的错误上下文作为负载进行记录。
服务装配
createTraceServices(trace-services.ts:15-34)读取 TraceConfig 并创建由 SQLiteTraceStore 支持的 AsyncTraceRecorder(当 config.enabled 为 true 时)或 NoopTraceRecorder(当为 false 时):
交叉引用
- 会话存储 -- 会话存储系统使用类似的 SQLite 持久化模式
- ProviderSpec 契约 -- 追踪记录中的 provider 和 model 字段来自解析后的 spec
参考文献
- src/trace/recorder.ts --
TraceRecorder、AsyncTraceRecorder、NoopTraceRecorder - src/trace/sqlite.ts --
SQLiteTraceStore、Schema 迁移 - src/trace/types.ts -- 所有追踪记录事件类型
- src/trace/context.ts --
TraceRecordingContext - src/trace/request-recorder.ts --
recordTraceRequest - src/trace/usage-recorder.ts --
recordTraceUsage - src/trace/event-recorder.ts --
recordTraceEvent - src/trace/error-recorder.ts --
recordTraceError - src/trace/row-mapper.ts --
mapTraceRecordToRow - src/trace/payload.ts --
summarizePayload、sha256Hex - src/trace/usage.ts --
traceUsageFromResponseUsage - src/trace/time.ts --
nowTraceMillis - src/context/trace-services.ts --
createTraceServices