Observability Guide

July 28, 2026 · View on GitHub

面向企业运维团队的 HotPlex Gateway 可观测性指南。涵盖结构化日志、OTel 原生指标与追踪、健康检查端点及告警最佳实践。


1. 结构化日志

HotPlex 使用 log/slog JSON Handler 输出结构化日志,兼容 OTel Log Data Model。

必填字段

字段说明
timestampISO 8601 / Unix ms(slog 自动生成)
levelDEBUG / INFO / WARN / ERROR
message人类可读事件描述
service.name固定 hotplex-gateway
session_id会话标识
agent_idAgent 身份标识(#848 AgentIdentity 派生,跨 session/event/audit/trace 按 agent 关联)
user_id用户标识
bot_idBot 实例标识
trace_id分布式追踪上下文(若存在)
span_idOTel span 标识(#850 Hub.SendToSession 注入,关联事件到精确 span)

示例

{
  "time": "2026-05-10T22:00:00.000Z",
  "level": "INFO",
  "msg": "session created",
  "service.name": "hotplex-gateway",
  "session_id": "01234567-89ab-cdef",
  "agent_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "user_id": "U_ABC123",
  "bot_id": "B_XYZ789",
  "trace_id": "abc123def456",
  "span_id": "1234567890abcdef"
}

日志级别规范

  • ERROR:全量记录,不采样,触发告警评估
  • WARN:降级或非致命异常,需关注但无需立即介入
  • INFO:正常业务事件(session 创建/销毁、worker 启动等)
  • DEBUG:开发调试信息,生产环境默认关闭

2. OTel 原生指标体系

HotPlex 使用统一的 internal/observability/ 包,通过 OTel Meter API 注册 60+ 个指标,前缀为 hotplex.。应用代码零直接依赖 prometheus/client_golang

指标通过 OTel Prometheus Exporter 以标准 Prometheus 格式暴露于 GET /admin/metrics,同时支持通过 OTLP gRPC 导出到 OTel Collector。

2.1 Session 指标

指标类型标签说明
hotplex.session.createdCounterworker_type累计创建会话数
hotplex.session.terminatedCounterreason会话终止原因
hotplex.session.deletedCounterGC 保留清理数
hotplex.session.start.attemptsCounterworker_type启动尝试次数
hotplex.session.start.errorsCounter启动错误数
hotplex.session.start.durationHistogram启动耗时

2.2 Worker 指标

指标类型标签说明
hotplex.worker.startsCounterworker_type, resultWorker 启动尝试
hotplex.worker.execution.durationHistogramworker_type执行耗时
hotplex.worker.crashesCounterworker_type, exit_codeWorker 崩溃计数
hotplex.worker.memory.bytesObservableGaugeworker_type预估内存
hotplex.worker.creation.durationHistogram进程创建耗时

2.3 Gateway 指标

指标类型标签说明
hotplex.gateway.connectionsObservableGauge当前 WebSocket 连接数
hotplex.gateway.webchat.session_owner_connectionsObservableGauge当前拥有直接 WebSocket owner 的 session 数
hotplex.gateway.messagesCounterdirection, event_typeWS 消息收发
hotplex.gateway.eventsCounterevent_type, directionAEP 事件透传
hotplex.gateway.init.handshake.durationHistogramWS 握手耗时
hotplex.gateway.deltas.droppedCounter背压丢弃的 delta 事件
hotplex.gateway.platform.droppedCounterevent_type平台连接缓冲区溢出丢弃
hotplex.gateway.no_subscribers.droppedCounterevent_type无订阅者丢弃
hotplex.gateway.delta.coalescedCounterDelta 合并数
hotplex.gateway.delta.flushCounter合并 delta 刷新数
hotplex.gateway.errorsCountererror_code错误分类计数
hotplex.gateway.webchat.duplicate_connection_rejectedCounter因已有 session owner 被拒绝的 init 数
hotplex.gateway.webchat.non_owner_ingress_rejectedCounter非 owner 发起受保护入站事件的拒绝数
hotplex.gateway.webchat.owner_release_not_currentCounter非当前 owner 尝试释放 owner 的次数

2.4 Pool 指标

指标类型标签说明
hotplex.pool.acquireCounterresult配额获取结果
hotplex.pool.release.errorsCounter双重释放错误(代码 Bug 指标)

2.5 Cron 指标

指标类型标签说明
hotplex.cron.firesCounterjob_name任务触发次数
hotplex.cron.errorsCounterjob_name, error_type执行错误分类
hotplex.cron.durationHistogramjob_name执行耗时
hotplex.cron.attachedCounterSession-attached 投递次数

2.6 Streaming 指标

指标类型标签说明
hotplex.streaming.card.rotationsCounterTTL 触发的卡片轮转
hotplex.streaming.card.rotation_failuresCounterphase轮转失败
hotplex.streaming.card.flush_fallbacksCounterCardKit 降级到 IM Patch

2.7 ACP 指标

指标类型标签说明
hotplex.acp.prompt_tokensCounterACP Worker prompt token 数
hotplex.acp.tool_callsCounter工具调用次数
hotplex.acp.permission_requestsCounter权限请求次数
hotplex.acp.handshake.durationHistogramJSON-RPC 握手耗时

2.8 LLM 重试指标

指标类型标签说明
hotplex.retry.attemptsCounterLLM 重试尝试次数
hotplex.retry.exhaustionCounter重试耗尽(最终失败)次数

2.9 Execution & Lease-Repair 指标

Durable ingress 的输入账本、owner lease 续约与终态修复子系统。

指标类型标签说明
hotplex.execution.acceptCounter新输入被持久化接受
hotplex.execution.duplicateCounter幂等去重(相同 ID + payload)
hotplex.execution.conflictCounterPayload 冲突(相同 ID,不同 hash)
hotplex.execution.session_busyCounterActive gate 拒绝(session 忙于此前 execution),转入 mid-turn 透传或暂存兜底
hotplex.execution.mid_turn_injectedCounterbusy 时追问被透传注入当前 turn(worker 支持 mid-turn,如 claude_code/codex_cli)
hotplex.execution.supplement_bufferedCounterbusy 时追问被暂存,待 turn 完成后重投(worker 不支持 mid-turn 的兜底)
hotplex.execution.delivery_outcomeCounterdelivery_statusWorker 投递结果(delivered/unknown/failed)
hotplex.execution.runtime_outcomeCounterruntime_statusWorker 运行终态(completed/failed/unknown)
hotplex.execution.delivery_latencyHistogramaccept 到 delivery outcome 耗时
hotplex.execution.runtime_durationHistogramWorker turn 执行耗时
hotplex.lease.renew_failureCounterOwner lease 续约失败
hotplex.lease.expired_recoveryCounterLease 过期恢复(runtime 置 unknown + fence)
hotplex.repair.attemptsCounter终态修复尝试
hotplex.repair.successCounter终态修复成功
hotplex.repair.timeoutCounter终态修复超时(超过 MaxLifetime 放弃)
hotplex.repair.droppedCounter终态修复入队失败(回退 lease recovery)

2.10 Turn TTFT 指标

Gateway 收到输入到首个可见 Worker 输出的耗时分段。TTFT 仅使用 Gateway 侧时间戳; 浏览器绘制时间属于独立客户端遥测,不能与本指标混合。

指标类型标签说明
hotplex.turn.ttftHistogramworker_type, first_output(reasoning/text)输入到首个可见输出的耗时
hotplex.turn.first_text_latencyHistogramworker_type输入到首个文本 delta 的耗时
hotplex.turn.stage_durationHistogramworker_type, stage(admission/dispatch/first_output)三阶段耗时拆分
hotplex.turn.without_outputCounterworker_type, terminal_status无可见输出即终止的 turn
hotplex.worker.empty_success_totalCounterworker_type, platform成功但无显示内容和工具调用的 turn(Turn-Integrity)

2.11 Forwarder & Turn-Integrity 诊断指标

指标类型标签说明
hotplex.gateway.forwarder.panicsCounterworker_typeWorker 事件转发 goroutine 已恢复的 panic
hotplex.gateway.stale_forwarder_event_totalCounter/reset 后旧 forwarder 观察到的事件(应永不为零)
hotplex.worker.assistant_snapshot_drift_totalCounterFull snapshot 非前缀漂移被重新下发
hotplex.messaging.platform_terminal_fallback_totalCounter平台因空内容发出合成终态回退

3. OpenTelemetry 分布式追踪

架构

HotPlex 使用统一的 OTel SDK 进行追踪初始化,支持:

  • OTLP gRPC 导出:直接发送到 OTel Collector(gzip 压缩)
  • W3C TraceContext + Baggage 传播:标准跨服务链路格式
  • trace_id 注入 AEP:自动写入 Envelope Metadata,实现消息链路关联
  • ParentBased 采样:根 span 按 SampleRate(默认 10%)采样,子 span 跟随父决策

配置

通过环境变量控制,无需修改代码:

# OTel Collector gRPC endpoint(设置即激活追踪)
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317

# 显式禁用(默认禁用)
OTEL_SDK_DISABLED=true

# 服务名(可选,默认 hotplex-gateway)
OTEL_SERVICE_NAME=hotplex-gateway

# 追踪采样率(可选,默认 0.1 即 10%)
# 仅影响根 span,子 span 跟随父决策

Span 命名规范

Span 名称触发时机
aep.initWS 握手初始化
aep.input用户输入
aep.message.delta流式输出片段
aep.doneTurn 完成
aep.error错误事件

上下文传播

  • Span 的 trace_idspan_idHub.SendToSession 注入 AEP Envelope 的 metadata 字段(#850:span_id 使下游能把事件关联到产出它的精确 span,而不止于 trace)
  • HTTP 端点通过 otelhttp 中间件自动注入/提取 W3C TraceContext
  • Gateway ↔ Worker 间通过 AEP Metadata 传递 trace_id
  • 所有语义键(trace_idspan_idagent_iduser_idworkspace_idsession_idexecution_id 等)统一在 internal/observability/keys.go 定义,禁止散落字面量。高基数键(agent_id/user_id/workspace_id/execution_id/session_id)仅作 span 属性/slog 字段/AEP 元数据,严禁用作 metric label(防止 label 集爆炸)

采样策略

  • ParentBased(TraceIDRatioBased(0.1)):根 span 10% 采样,子 span 跟随父决策
  • ERROR trace:建议在 Collector 层通过 Tail Sampling 100% 保留
  • 高延迟 trace:建议通过 Collector 层按 duration 过滤保留

4. 健康检查端点

所有端点位于 Admin API(默认 localhost:9999)。

端点认证用途适用场景
GET /admin/health无需认证Gateway 整体状态(含 DB、Workers)负载均衡探针
GET /admin/health/workershealth:read按 Worker 类型主动探活运维排障
GET /admin/health/ready无需认证就绪检查K8s readinessProbe / Docker HEALTHCHECK

使用示例

# 负载均衡健康检查
curl http://localhost:9999/admin/health

# Worker 状态探查(需 Token)
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:9999/admin/health/workers

# K8s readinessProbe / Docker HEALTHCHECK
curl -sf http://localhost:9999/admin/health/ready

Docker HEALTHCHECK 配置

Dockerfile 已内置:

HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
    CMD curl -f http://localhost:9999/admin/health/ready || exit 1

5. Grafana Dashboard 建议

核心面板

面板PromQL类型用途
Session 创建速率rate(hotplex_session_created_total[5m])Stat容量规划
WS 连接数hotplex_gateway_connectionsTime series连接趋势
Worker 崩溃率rate(hotplex_worker_crashes_total[5m])Time series稳定性
Worker 执行 P99histogram_quantile(0.99, rate(hotplex_worker_execution_duration_bucket[5m]))Time series性能
TTFT P95histogram_quantile(0.95, sum by (le, worker_type) (rate(hotplex_turn_ttft_bucket[15m])))Time series首输出延迟
TTFT 阶段拆分histogram_quantile(0.95, sum by (le, stage) (rate(hotplex_turn_stage_duration_bucket[15m])))Time series延迟归因
投递成功率sum(rate(hotplex_execution_delivery_outcome_total{delivery_status="delivered"}[5m])) / sum(rate(hotplex_execution_delivery_outcome_total[5m]))Stat输入可靠性
Delta 背压丢弃rate(hotplex_gateway_deltas_dropped_total[5m])Time series流量压力
Cron 错误率rate(hotplex_cron_errors_total[5m])Time series定时任务健康
错误分类hotplex_gateway_errors_totalStacked bar错误归因
重复 WS 连接拒绝rate(hotplex_gateway_webchat_duplicate_connection_rejected_total[5m])Time series发现同一 session 的并发连接或重连竞争
重试耗尽rate(hotplex_retry_exhaustion_total[5m])Time seriesLLM 稳定性

布局建议

  1. 顶栏:Session 创建速率 / WS 连接 / LLM 重试耗尽 / Uptime(4 个 Stat 面板)
  2. 中间行:Session 生命周期 + Worker 执行耗时趋势
  3. 底部行:错误分类 + 背压指标 + Cron 健康

6. 告警最佳实践

原则

  • 症状告警(Symptom-based):告警用户可见的故障,而非根因指标
  • 持续阈值:连续 5 分钟超过阈值才触发,避免瞬时毛刺
  • 分级响应:P0(立即介入)→ P1(当日处理)→ P2(纳入迭代)

推荐告警规则

告警名PromQL阈值级别说明
HighWorkerCrashRaterate(hotplex_worker_crashes_total[5m]) / rate(hotplex_worker_starts_total[5m])> 1%P0Worker 崩溃率
HighSessionFailureRaterate(hotplex_session_terminated_total{reason=~"crash|zombie"}[5m])> 0P0异常终止
HighDeltaDropRaterate(hotplex_gateway_deltas_dropped_total[5m])> 10/sP1严重背压
HighWorkerLatencyP99histogram_quantile(0.99, rate(hotplex_worker_execution_duration_bucket[5m]))> 300sP1Worker 执行卡顿
CronJobFailuresrate(hotplex_cron_errors_total[10m])> 0P2定时任务异常
PoolDoubleReleaseincrease(hotplex_pool_release_errors_total[1h])> 0P2代码 Bug 信号
LLMRetryExhaustionrate(hotplex_retry_exhaustion_total[5m])> 0P1LLM 调用不可用
RepeatedSessionConnectionConflictrate(hotplex_gateway_webchat_duplicate_connection_rejected_total[10m])持续 > 0P2客户端并发重连或连接切换未排空
HighDeliveryFailureRaterate(hotplex_execution_delivery_outcome_total{delivery_status!="delivered"}[5m]) / rate(hotplex_execution_delivery_outcome_total[5m])> 5%P1Worker 投递失败率过高
HighEmptySuccessTurnrate(hotplex_worker_empty_success_total_total[5m]) / rate(hotplex_worker_starts_total[5m])> 1%P2空 success turn 占比异常
HighLeaseRenewFailurerate(hotplex_lease_renew_failure_total[5m])持续 > 0P1Owner lease 续约持续失败
HighTTFTP99histogram_quantile(0.99, sum by (le) (rate(hotplex_turn_ttft_bucket[15m])))> 30sP1TTFT P99 超过阈值

SLO 参考

SLO指标目标
Session 创建成功率session.start.attempts vs session.start.errors>= 99.5%
Worker 可用性1 - crashes/starts>= 99%
Worker 执行 P99worker.execution.duration< 300s
输入投递成功率execution.delivery_outcome{delivery_status="delivered"}>= 99%
Lease 续约成功率lease.renew_failure 持续为 0== 100%
TTFT P95turn.ttft P95< 10s