Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

可观测性指南

本章介绍 Thurgio 的三类可观测入口如何配合使用:Prometheus 指标(GET /metrics)、订阅健康度聚合(GET /app/read/health)与结构化日志。


概述

入口路径认证用途适合告警
指标GET /metrics无需令牌(公开端点,见 API 参考机器可读的时序数据:请求、构建管线、缓存、熔断器、渲染线程池、内存
健康度GET /app/read/health需 Read/Admin 令牌面向订阅的业务健康度:按 provider/snippet 汇总熔断器状态与最后成功时间否(适合 Dashboard/人工巡检)
日志stdout/stderr(journald)请求追踪、错误链、事件总线与熔断器状态切换否(适合排障)

三者在 部署指南 的监控检查清单中均有对应项。


Prometheus 接入

认证说明

GET /metrics 归类为公开端点,与 GET /healthGET /ready 一致,无需 ?token=Authorization: Bearer 头。反向代理层应对其做网络级访问控制,禁止公网直接暴露。详见 部署指南 的 Nginx/Caddy 示例——allow 10.0.0.0/8 / deny allremote_ip 匹配。

scrape_config 示例

以下配置可直接放入 prometheus.ymlscrape_configs

scrape_configs:
  - job_name: "thurgio"
    metrics_path: /metrics
    scrape_interval: 15s
    scrape_timeout: 10s
    static_configs:
      - targets: ["127.0.0.1:10100"]
        labels:
          instance: "thurgio-prod-01"

若 Prometheus 与 Thurgio 不在同一内网,经反向代理抓取时改用域名并按需添加 TLS 配置:

scrape_configs:
  - job_name: "thurgio"
    metrics_path: /metrics
    scheme: https
    static_configs:
      - targets: ["thurgio.example.com"]
    # 若反向代理对 /metrics 做了 IP 白名单,Prometheus 需部署在白名单网段内

验证抓取是否生效:

curl -fsS http://127.0.0.1:10100/metrics | head -n 40
# 应返回 Prometheus 文本暴露格式,首行为 # HELP http_requests_total

GET /metrics 的响应为纯文本 Prometheus 暴露格式,非 JSON;每次请求实时计算 process_memory_usage_mbVmRSS)与熔断器快照并追加渲染线程池块(见 crates/thurgio-server/src/routes/public.rs:metricscrates/thurgio-server/src/metrics.rs:render/render_renderer_metrics)。

OTLP 可选链路

thurgio-infra/src/metrics.rs 定义的 MetricsRecorder 在启用 otlp feature 时经 OtelMetrics 写入全局 OpenTelemetry Meter Provider(OTEL_EXPORTER_OTLP_ENDPOINT,默认 http://localhost:4317,gRPC)。MetricsCollector 对未映射的指标名会转发至 fallback recorder(set_fallback),未启用 otlp 时直接丢弃。因此下表标注为 OTLP 的指标仅在 cargo run -p thurgio-cli --features otlp 或对应 release 构建下可见;Prometheus 标注的指标无论是否启用 OTLP 均出现在 /metrics


指标参考

名称与类型以源码为准。来源文件:

  • crates/thurgio-infra/src/metrics.rsnames 模块,规范名称单一来源)
  • crates/thurgio-server/src/metrics.rsMetricsCollector::renderrender_renderer_metrics 的 Prometheus 渲染)

1. HTTP 请求(MetricsCollector 直接渲染)

名称类型含义
http_requests_totalcounter累计 HTTP 请求数(record_request 每次 +1)
http_errors_totalcounter累计 status >= 400 的请求数
active_connectionsgauge当前在途请求数(RequestTimer::new +1 / finish -1)
http_request_duration_msgauge平均请求耗时(毫秒,request_duration_sum / count
http_request_duration_histogramhistogram请求耗时直方图;桶边界 [1, 5, 10, 50, 100, 500, 1000, 5000, 10000] 毫秒,另含 +Inf 桶、_sum_count
`http_status_codes{category=“1xx2xx3xx
http_rate_limited_totalcounter因并发或速率限制被拒绝并返回 429 的请求数(RATELIMIT = http_rate_limited_total

2. 构建与更新管线

名称类型含义暴露
config_updates_totalcounterprovider/snippet 更新总次数(record_config_updatePrometheus
config_updates_failed_totalcounter更新失败次数(CONFIG_UPDATES_FAILED,经 MetricsRecorder 映射)Prometheus
config_renders_totalcounter模板渲染总次数(record_config_render,含 provider 主输出、具名输出与 snippet)Prometheus
config_builds_totalcounter完整构建(build)总次数Prometheus
build.completedcounterbuild 管线成功完成计数(BUILD_COMPLETEDPrometheus
build.update.failurecounterbuild 更新阶段失败计数(BUILD_UPDATE_FAILUREPrometheus
build.provider.success{name="<provider>"}counter单个 provider 拉取成功计数(ITEM_PROVIDER.success,label namePrometheus
build.provider.failure{name="<provider>"}counter单个 provider 拉取失败计数(ITEM_PROVIDER.failurePrometheus
build.snippet.success{name="<snippet>"}counter单个 snippet 拉取成功计数(ITEM_SNIPPET.successPrometheus
build.snippet.failure{name="<snippet>"}counter单个 snippet 拉取失败计数(ITEM_SNIPPET.failurePrometheus
renderer.reloadcounter渲染器重载次数(RENDERER_RELOAD,dev 模式或 GET /app/admin/reload 触发)Prometheus
config_reload_failed_totalcounter配置热重载重解析失败次数(CONFIG_RELOAD_FAILED,失败时保留旧配置,不发事件)Prometheus
proxy_countgauge当前代理总数(PROXY_COUNTgauge_set,可增可减)Prometheus
build.durationhistogram完整 build 耗时(秒,BUILD_DURATIONOTLP
`build.update.duration{status=“successfailure“}`histogrambuild 更新阶段耗时(秒,label status
build.render.durationhistogrambuild 渲染阶段耗时(秒,BUILD_RENDER_DURATIONOTLP
build.update.successcounterbuild 更新阶段成功计数(BUILD_UPDATE_SUCCESSOTLP
autobuild.successcounterAutoBuildHandler 自动重建成功计数OTLP
autobuild.failurecounterAutoBuildHandler 自动重建失败计数OTLP
proxy_parse_failed_total{name="<provider>"}counter单 provider 解析阶段丢弃的坏条目数(label nameOTLP
ruleset_fetch_failed_total{name="<ruleset>"}counter远程规则集拉取失败次数(回退旧文本,不传播错误;label nameOTLP

3. 缓存

名称类型含义暴露
cache_hits_totalcounterTTL 缓存命中次数(CACHE_HIT,label `kind=providersnippet
cache_misses_totalcounterTTL 缓存未命中次数(CACHE_MISS,实际发起抓取时 +1)Prometheus

4. 熔断器(Circuit Breaker)

名称类型含义
circuit_breaker_state{name="<provider|snippet>"}gauge熔断器状态:0 = Closed(正常)、1 = Open(拒绝抓取)、2 = HalfOpen(试探)
circuit_breaker_fail_count{name="<provider|snippet>"}counter熔断器累计失败次数(CircuitBreakerSnapshot::failure_count

快照来源为 CircuitBreakerPool::snapshots(),与 GET /app/read/healthfailure_count 同源;键格式 circuit_breaker:{identity}thurgio-infra::circuit_breaker::SNAPSHOT_KEY_PREFIX 单一拥有。

5. 资源与内存

名称类型含义暴露
process_memory_usage_mbgauge当前 RSS 内存(MB,get_memory_usage 读取 /proc/self/statusVmRSS;非 Linux 置 0)Prometheus
process_memory_baseline_mbgauge空闲驱逐后的引擎基线 RSS(MB,PROCESS_MEMORY_BASELINEPrometheus
data_cache_memory_mbgauge空闲驱逐释放的数据缓存内存(MB,DATA_CACHE_MEMORYrss_before - rss_afterPrometheus

6. 渲染线程池(render_renderer_metrics

AppState::renderer().pool_metrics()/metrics 末尾追加,HELP/TYPE/value 三行一组:

名称类型含义
renderer_active_threadsgauge当前活跃渲染线程数
renderer_backlog_smoothedgaugeEMA 平滑后的待渲染积压深度(浮点,保留两位小数)
renderer_threads_spawned_totalcounter累计创建的渲染线程数
renderer_threads_exited_totalcounter累计退出的渲染线程数
renderer_slots_totalgauge渲染线程池总槽位数

池参数由环境变量 THURGIO_RENDERER_MIN_THREADS / THURGIO_RENDERER_MAX_THREADS 调整(默认 min 1 / max 64),见 部署指南


告警建议

下列规则为 Prometheus groups YAML 片段,可直接加入 prometheus.ymlrule_files 或 Alertmanager 规则文件。阈值按需调整。

groups:
  - name: thurgio
    interval: 30s
    rules:
      # 1. 熔断器 Open 超过 10 分钟
      - alert: ThurgioBreakerOpen
        expr: circuit_breaker_state == 1
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "订阅 {{ $labels.name }} 熔断器持续 Open"
          description: "该 provider/snippet 已连续 10 分钟拒绝抓取,检查上游可用性与网络。"

      # 2. 任意订阅拉取失败率升高(5 分钟内失败 > 0)
      - alert: ThurgioProviderFailure
        expr: increase(build.provider.failure[5m]) > 0
        labels:
          severity: warning
        annotations:
          summary: "provider {{ $labels.name }} 拉取失败"
          description: "5 分钟内出现拉取失败,对照日志 trace_id 排查上游与解析错误。"

      # 3. 渲染线程池积压过高
      - alert: ThurgioRendererBacklogHigh
        expr: renderer_backlog_smoothed > 20
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "渲染线程池积压过高"
          description: "平滑积压 {{ $value }} 超过 20,考虑调大 THURGIO_RENDERER_MAX_THREADS 或降低并发渲染压力。"

      # 4. 限流误伤(正常流量下不应出现 429)
      - alert: ThurgioRateLimited
        expr: increase(http_rate_limited_total[5m]) > 0
        labels:
          severity: warning
        annotations:
          summary: "请求被限流"
          description: "5 分钟内出现 429,检查是否误伤正常客户端,必要时调整 THURGIO_RATE_LIMIT_* 或反向代理限流配置。"

      # 5. 配置热重载持续失败
      - alert: ThurgioConfigReloadFailed
        expr: increase(config_reload_failed_total[10m]) > 0
        labels:
          severity: critical
        annotations:
          summary: "配置热重载失败"
          description: "10 分钟内出现重解析失败,旧配置仍生效但新配置未生效,检查 YAML 语法与模板存在性。"

可选补充(按需启用):

      # 6. 内存基线异常增长(按实例规格调整阈值)
      - alert: ThurgioMemoryHigh
        expr: process_memory_usage_mb > 800
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "内存占用过高"
          description: "RSS {{ $value }} MB 超过 800 MB,检查是否存在订阅膨胀或渲染泄漏。"

GET /app/read/health 的分工

维度GET /metricsGET /app/read/health
定位面向监控系统的时序指标面向人的订阅健康度聚合
数据计数器/直方图/gauge,带时间序列当前快照:overallhealthy/degraded/unhealthy)、summary{total,closed,open,half_open}items[] 明细
熔断器circuit_breaker_state(数值 0/1/2)与 circuit_breaker_fail_countbreakerclosed/open/half-open)、failure_countlast_failure_at(Unix 秒,null 表示从未失败)
时间仅计数,不含时间戳last_update_at(RFC 3339,取 DB time 列;未抓取过为 null;epoch 哨兵已过滤)
排序按 Prometheus 文本顺序provider 在前(配置声明顺序)、snippet 在后
触发不触发更新不触发更新(仅读熔断器池与 DB)
认证公开需 Read/Admin 令牌(见 API 参考

使用建议:

  • 告警/metrics(Prometheus 规则见上节)。
  • 巡检/排障/app/read/healthoverall == degraded 时检查 itemsbreaker == open 的条目,结合 failure_countlast_failure_at 判断故障时长;last_update_at == null 表示该订阅从未成功抓取。
  • Dashboard 可同时消费两者:时序图用 /metrics,订阅列表用 /app/read/health(与内置 UI 的数据源一致,见 docs/src/dashboard.md)。

日志

Thurgio 经 tracing + tracing-subscriber 输出日志到 stdout/stderr,由 systemd 的 journald 或容器日志驱动收集。日志级别由 RUST_LOG 控制,格式由 RUST_LOG_FORMAT 控制(见 部署指南thurgio-infra::init_logger)。

环境变量默认说明
RUST_LOGinfoEnvFilter 语法,如 info,thurgio_app_update=debugjust 默认 info,opentelemetry=off
RUST_LOG_FORMAT文本设为 json 输出结构化日志,便于 jq 过滤
RUST_LOG_ANSI自动检测(TTY 时启用)是否输出 ANSI 颜色,同时影响 CLI 彩色输出

常用排障命令:

# 跟随日志
journalctl -u thurgio -f

# 仅看熔断器状态切换
journalctl -u thurgio | grep "circuit breaker"

# 仅看失败请求(结构化日志)
RUST_LOG_FORMAT=json thurgio serve | jq 'select(.fields.trace_id != null)'

# 提升更新管线的日志级别
RUST_LOG="thurgio_app_update=debug,thurgio_request=debug" thurgio serve

关键日志信号:

  • 熔断器:circuit breaker opened after N failurescircuit breaker reopened after half-open failurecircuit breaker open for <name>
  • 配置热重载失败:config_reload_failed_total 递增时伴随 error! 日志,旧配置保持生效。
  • 事件总线:domain event: provider '<name>' update failed 等(thurgio-app-build/src/event_handlers.rs)。

延伸阅读

  • 部署指南 — 生产检查清单、反向代理与 systemd 配置
  • API 参考GET /metricsGET /app/read/health 的完整响应契约
  • 架构 — 统一错误类型(ErrorKind)与熔断器设计
  • design/debugging.mdRUST_LOG 过滤速查表
  • design/specs/spec-circuit-breaker.md — 熔断器键格式与持久化契约