Skip to content

可观测性

dcc-mcp-core 提供四种互补的可观测性接口,适用于生产环境部署。

1. OTLP 分布式追踪(#768)

将 span 数据发送到任何兼容 OpenTelemetry 的后端(Jaeger、Grafana Tempo、DataDog、New Relic 等)。

激活方式

设置标准 OTEL_* 环境变量——无需修改代码:

bash
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
OTEL_SERVICE_NAME=dcc-mcp-gateway \
  dcc-mcp-server ...

环境变量

变量说明
OTEL_EXPORTER_OTLP_ENDPOINTCollector 端点——设置此变量后自动启用 OTLP
OTEL_SERVICE_NAME覆盖追踪中的服务名
OTEL_RESOURCE_ATTRIBUTES额外资源属性(key=val,key2=val2
OTEL_EXPORTER_OTLP_HEADERSSaaS 后端的认证 Header(如 api-key=...
OTEL_TRACES_SAMPLER采样器类型(always_onalways_offtraceidratio
OTEL_TRACES_SAMPLER_ARG采样器参数(如 0.1 表示 10% 采样率)

DCC Span 属性

每次 tools/call 追踪均包含:

属性示例说明
dcc.type"maya"DCC 应用类型
dcc.instance_id"a1b2c3d4-..."DCC 实例唯一 UUID
dcc.scene"/projects/shot01.ma"当前场景路径(已知时)
dcc.job_id"job-..."作业 ID(被 JobHandle 包装时)
mcp.method"tools/call"MCP 方法名
mcp.tool_slug"maya__open_scene"完整工具名
mcp.affinity"main"线程亲和性要求
mcp.session_id"sess-..."MCP 会话 ID
mcp.request_id"req-..."每次请求的唯一 ID

Gateway Agent Workflow Spans(#1180)

当 agent 通过 REST 或 MCP 进行动态能力发现与调用时,网关会额外发送有界工作流 span:

Span含义
gateway.searchAgent 搜索工具或技能。
gateway.describeAgent 查看选中工具的 schema/说明。
gateway.load_skillAgent 加载搜索得到的技能。
gateway.callAgent 调用一个后端工具。
gateway.call_batchAgent 执行有序批量调用。

这些 span 使用 openinference.span.kind(search 为 CHAIN,describe/load/call 为 TOOL),并用 dcc_mcp.* 命名空间记录网关语义字段:

属性说明
dcc_mcp.workflow.operation上表中的 span 名称。
dcc_mcp.transportrestmcp
dcc_mcp.trace_iddcc_mcp.request_iddcc_mcp.parent_request_iddcc_mcp.session_id与 Admin trace/debug bundle 对齐的关联 ID。
dcc_mcp.actor.id.name.email_hash有界的人类或服务账号 actor 归因。
dcc_mcp.agent.id.name.kind.version.model.model_provider.model_version.reasoning_effort.turn_id.task.tags有界的 agent runtime 元数据。
dcc_mcp.client.platform.os.hostdcc_mcp.auth.subject有界的客户端入口与认证主体元数据。
dcc_mcp.source.ipdcc_mcp.forwarded_for应用 proxy trust policy 后由服务端派生的网络来源字段。
dcc_mcp.agent.user_intent_summary.reply_summary.user_input_hash.reply_hash.user_input_chars.reply_chars用于评估关联的低敏 turn 摘要、哈希和长度。
dcc_mcp.dcc.typedcc_mcp.instance.iddcc_mcp.skill.namedcc_mcp.tool.slug选中的 DCC 路由与技能/工具身份。
dcc_mcp.search.id.ranker_version.selected_rank.score.match_reasons.total.zero_results/v1/search 或 gateway search 继承的搜索质量上下文。
dcc_mcp.policy.outcome.reason网关策略是否允许、拒绝或限流,以及原因。
dcc_mcp.successdcc_mcp.error.kinddcc_mcp.batch.size执行结果字段。

网关不会导出隐藏推理、原始 prompt、原始 agent 回复、无界请求体、secret 或任意 agent_context metadata。Agent 从搜索结果继续调用 describeload_skillcallcall_batch 时,应保留 REST meta.search_id 或 MCP _meta.search_id,这样 OTLP trace 才能把 selected rank/score 和真实工具结果关联起来。评估需要关联单个 agent turn 时,在 agent_context 中加入 turn_id 与模型身份字段。

Rust 编程式配置

rust
use dcc_mcp_telemetry::{TelemetryConfig, ExporterBackend};

TelemetryConfig::default()
    .with_otlp_exporter("http://localhost:4317")
    .init()?;

需要启用 otlp-exporter Cargo feature:

toml
dcc-mcp-telemetry = { features = ["otlp-exporter"] }

快速启动:Jaeger All-in-One

bash
docker run -d --name jaeger \
  -p 4317:4317 \   # OTLP gRPC
  -p 16686:16686 \ # Jaeger UI
  jaegertracing/all-in-one:latest

OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
OTEL_SERVICE_NAME=dcc-mcp-gateway \
  dcc-mcp-server ...

打开 http://localhost:16686 查看追踪数据。

快速启动:Grafana Tempo

bash
# docker-compose.yml
services:
  tempo:
    image: grafana/tempo:latest
    ports: ["4317:4317", "3200:3200"]
bash
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 dcc-mcp-server ...

快速启动:通过 OTLP Collector 写入 Phoenix

Phoenix 可在 /v1/traces 接收 OTLP/HTTP traces。当前 Rust 网关 exporter 使用 OTLP/gRPC,因此建议用 OpenTelemetry Collector 做 gRPC 到 HTTP 的桥接:

yaml
# otel-collector.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

exporters:
  otlphttp/phoenix:
    traces_endpoint: http://phoenix:6006/v1/traces

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [otlphttp/phoenix]
bash
docker run -d --name phoenix -p 6006:6006 arizephoenix/phoenix:latest
docker run --rm -p 4317:4317 \
  -v "$PWD/otel-collector.yaml:/etc/otelcol-contrib/config.yaml" \
  otel/opentelemetry-collector-contrib:latest

OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
OTEL_SERVICE_NAME=dcc-mcp-gateway \
  dcc-mcp-server ...

2. 网关竞争事件(#766)

网关选举、驱逐和探针事件可通过有界 MCP 资源获取。

MCP 资源

python
# 读取最近 N 条竞争事件
result = resources.read("resources://gateway/events")

返回 JSONL 格式(每行一个 JSON 对象):

json
{"timestamp":"2026-05-05T10:00:00Z","event":"election_won","dcc_type":"maya","instance_id":"a1b2c3d4","reason":null}
{"timestamp":"2026-05-05T10:01:00Z","event":"ghost_reaped","dcc_type":"blender","instance_id":"b2c3d4e5","reason":"pid_dead"}

事件类型

事件含义
election_won本实例成为活跃网关
voluntary_yield本实例主动让位给更新的候选者
ghost_reaped清理了一条过期注册记录
probe_booting后端正在启动中
probe_unreachable健康探针失败
auto_deregister实例在干净关闭时自注销

环形缓冲区保留最近 1000 条事件


3. Admin 调用审计与 Dispatch Traces

获选网关在 GET /admin 提供只读 HTML 仪表盘,并向运维与 AI agent 暴露机器可读 JSON 端点:

端点使用场景
GET /admin/api/callsrequest_id、工具 slug、DCC 类型、实例、错误摘要和耗时关联最近调用。
GET /admin/api/traces?limit=200查看最近 dispatch waterfall、有界输入 payload(16 KiB)和有界输出 payload(64 KiB)。
GET /admin/api/traces/{request_id}不扫描整个 trace ring,直接下钻某一次调用。
GET /admin/api/workflows?limit=200将 retained searches、describes、skill loads、calls、traces 和 audits 聚合为 agent session/workflow 链。
GET /admin/api/stats?range=1h|24h|7d基于 trace log 计算成功率、延迟分位数和 top tools/instances。
GET /admin/api/governance?limit=300 / GET /v1/debug/governance查看当前 policy、read-only 状态、traffic capture guardrail、redaction paths、中间件 quota 状态,以及最近 allowed/denied/throttled 决策。
GET /admin/api/workers查看 live registry 中每个实例的卡片。

默认情况下这些缓冲区只保存在内存中。设置 DCC_MCP_GATEWAY_AUDIT_DIR 后会追加有界 JSONL 文件:

  • audit.jsonl —— 支撑 /admin/api/calls 的调用行。
  • traces.jsonl —— 支撑 /admin/api/traces 和 stats 的 trace 行。

DCC_MCP_GATEWAY_AUDIT_MAX_ROWS(默认 5000)限制每个文件保留行数。网关重启时会用这些文件回填内存中的 admin 缓冲区。持久化的 trace payload 使用与实时 API 相同的有界/已脱敏 TracePayload,不会保存无界原始请求体。

/admin/api/workflows/v1/debug/workflows 复用相同存储,按 session、显式 workflow id、trace id 或 request chain 展示 workflow 行;每行包含有界 agent metadata、selected search rank、zero-result search、time-to-first-success,并把步骤链接回 trace detail、debug bundle、issue report、OpenAPI 与 docs。


4. Prometheus 指标(#766)

prometheus Cargo feature 下,网关竞争计数器通过 /metrics 端点暴露:

toml
dcc-mcp-gateway = { features = ["prometheus"] }

计数器

# 网关端口选举结果
dcc_mcp_gateway_elections_total{outcome="won"}     12
dcc_mcp_gateway_elections_total{outcome="yielded"}  3
dcc_mcp_gateway_elections_total{outcome="lost"}     1

# 注册表驱逐事件
dcc_mcp_gateway_evictions_total{reason="stale"}    1
dcc_mcp_gateway_evictions_total{reason="ghost"}    0
dcc_mcp_gateway_evictions_total{reason="probe_fail"} 2

# 后端就绪探针结果
dcc_mcp_gateway_probes_total{outcome="ready"}      45
dcc_mcp_gateway_probes_total{outcome="booting"}     3
dcc_mcp_gateway_probes_total{outcome="unreachable"} 2

# Gateway governance 结果
dcc_mcp_gateway_governance_events_total{category="policy",outcome="denied"} 4
dcc_mcp_gateway_governance_events_total{category="rate-limit",outcome="throttled"} 3

标签基数有界——不含自由形式的 instance_id 标签。

Grafana 示例查询

promql
# 选举速率随时间变化
rate(dcc_mcp_gateway_elections_total[5m])

# 驱逐速率
rate(dcc_mcp_gateway_evictions_total[5m])

# 探针成功率
rate(dcc_mcp_gateway_probes_total{outcome="ready"}[5m])
  / rate(dcc_mcp_gateway_probes_total[5m])

参见

Released under the MIT License.