Skip to main content
GoModel 会为入站 HTTP 请求(运维类端点除外,见下文)以及每一次出站模型提供商调用导出 OpenTelemetry Trace 和指标。提供商调用遵循 GenAI 语义约定,因此 Jaeger、Grafana Tempo、Honeycomb、Datadog 或任何其他兼容 OTLP 的后端都能显示调用了哪个模型、经由哪个提供商、耗时多久以及是否失败。 凭据和错误消息永远不会被导出。只有在您开启内容捕获时,才会导出提示词和补全内容。关于 Prometheus 抓取,请参阅 Prometheus 指标;两者可以同时运行。

快速开始

导出功能默认关闭。设置 OTEL_ENABLED=true,并将导出器指向您的 Collector:
GoModel 会在启动时记录 opentelemetry enabled 以及所选的导出器。导出器是异步的:即使 Collector 不可用,网关也会正常启动,并在后台重试。
未设置 OTEL_EXPORTER_OTLP_ENDPOINT 时,SDK 会发送到 http://localhost:4318(http/protobuf)或 localhost:4317(grpc)。

配置

OTEL_ENABLED 是唯一一个 GoModel 特有的开关。其他所有设置都遵循标准的 OpenTelemetry 环境变量,因此 GoModel 的配置方式与其他任何已接入观测的服务完全相同。常用设置也可以在 config.yaml 的 opentelemetry: 下配置;环境变量中设置的值优先于 YAML 中的值。 典型的生产环境配置:
采样只影响 Trace,指标始终是完整的。
authorization 等导出 Header 会随每次导出请求一起发送。只要 Header 中携带凭据,就请使用 https:// 端点(或启用 TLS 的 gRPC 端点);仅当 Collector 位于同一主机上时,才可以接受明文传输。如果配置了 Header,而实际生效的端点是明文(http://,或设置了 OTEL_EXPORTER_OTLP_INSECURE=true 的 gRPC)且不是环回地址,GoModel 会在启动时记录一条警告。

导出的内容

HTTP 服务端 Span 和指标

每个请求都会生成一个以其路由命名的 SERVER Span(例如 POST /v1/chat/completions),带有标准的 http.request.method、http.route、http.response.status_code 和 url.scheme 属性,并附带 http.server.request.duration 直方图以及请求体和响应体大小直方图。 GoModel 会遵循调用方传入的 Trace 上下文:只要客户端发送了 traceparent(或 OTEL_PROPAGATORS 所选的任何 Header),网关 Span 就会显示为调用方应用 Span 的子 Span。 /health、/health/ready、Prometheus 端点(METRICS_ENDPOINT)和 /debug/pprof 被排除在外:它们会被频繁轮询,否则会占据 Trace 的绝大部分。

提供商调用 Span 和 GenAI 指标

每一次对模型提供商的逻辑调用都会带有以下观测数据: 对于 Chat Completions、Responses API 以及经过转换的 /v1/messages 调用,无论是缓冲还是流式,网关在解码响应后都会设置响应属性和用量属性。当提供商报告了用量时,才会出现用量属性。对于流式响应,只有在启用用量追踪(默认启用)时,GoModel 才会要求提供商返回用量数据块。GoModel 以原生方式转发给 Anthropic 提供商的 /v1/messages 请求,以及其他透传调用,只携带请求属性。 指标为以秒为单位的直方图,携带相同的属性: gomodel.client.empty_responses 统计返回 200 但没有 choices、没有输出或没有 Token 用量的缓冲 Chat 和 Responses API 调用。这些调用在上述直方图中看起来是成功的,因此请改为基于这个计数器设置告警。其 error.type 为 no_choices、no_output(已完成但没有输出项的 Responses API 调用)或 no_usage(有内容但 Token 用量为零)。 缓冲调用会生成一个名为 <operation> <model> 的 CLIENT Span(例如 chat gpt-5),嵌套在 HTTP 服务端 Span 之下。重试和故障转移到其他提供商都是独立的调用,因此也是独立的 Span;发生故障转移的请求会清楚地显示哪个提供商失败、哪个提供商做出了响应。 流式的 Chat Completion、Responses API 或经过转换的 /v1/messages 调用会获得一个在流结束时才结束的客户端 Span,因此其时长涵盖整个生成过程。其他流(例如透传调用)不会获得客户端 Span:网关只知道它们何时建立,而一个在响应头处结束的 Span 会错误地反映延迟。它们的 HTTP 服务端 Span 仍然涵盖客户端视角下的完整流生命周期。未能建立的流,或在交付第一个数据块之前就结束的流,始终会生成一个失败 Span,因此错误都会被追踪到。

提示词与补全内容捕获

内容捕获默认关闭。开启后,您可以在链路追踪后端中查看交换的消息,例如在 Langfuse 中显示为生成(generation)的输入和输出:
之后,Chat Completions、Responses API 和经过转换的 /v1/messages 调用的提供商调用 Span 会以 JSON 形式携带 GenAI 消息属性: 超过 64 KiB 的文本部分会被截断并标记,每个属性最多保留 512 KiB 文本:较长的对话会优先丢弃最早消息的文本。图片、音频和文件只保留其部分类型:二进制数据和 data URL 永远不会被导出。被 Trace 采样器丢弃的请求完全不会被捕获。 该变量还接受 SPAN_ONLY 和 SPAN_AND_EVENT,即较新版 OpenTelemetry 观测库使用的模式名称。
开启捕获后,每个被采样的提示词和补全内容都会随其 Trace 离开网关。请仅在允许存储此类数据的后端上启用,并考虑使用采样(OTEL_TRACES_SAMPLER)来限制数据量。审计日志则会将内容保存在您自己的存储中。

隐私

导出器的设计目标是:遥测数据可以发送到第三方后端,而不会泄露流经网关的内容:
  • 只有在开启内容捕获时,提示词、补全内容和工具调用才会附加到 Span 上,并且永远不会附加到指标上。请求体和响应体永远不会被原样导出。
  • 凭据和上游错误消息永远不会被导出;失败只携带状态码或错误类别。
  • HTTP Span 中会移除 client.address、network.peer.*、server.address、server.port 和 user_agent.original,HTTP 指标中也会排除基于主机的维度,以防客户端通过 Host Header 抬高指标基数。

重新加载

gomodel --reload(SIGHUP)会使用当前环境重建 OpenTelemetry 管道,因此导出器、采样和传播方面的更改无需重启即可生效。旧管道在丢弃之前会先完成刷写。

本地 Collector 示例

一个在 Jaeger 中显示 Trace 的最小 docker-compose.yml:
通过网关发送一个请求,然后打开 http://localhost:16686。
最后修改于 2026年10月24日