# Observability
rs-zero 通过 `observability` feature 提供统一 Prometheus registry、自动指标记录和 tracing helper;真实 OTLP trace exporter 通过 `otlp` feature 启用。
## Metrics
`MetricsRegistry` 是 rs-zero 内置的 in-process Prometheus text registry。推荐每个服务创建一个 registry,并传入 REST、RPC、SQL、Redis、cache、resilience adapter。它适合默认 feature 和本地开发;极高并发或大量 label churn 场景应运行 `tests/metrics_stress.rs`,并评估是否启用 `observability-prometheus-client`。
```rust
use axum::{Router, routing::get};
use rs_zero::observability::{MetricsRegistry, metrics_router};
use rs_zero::rest::{ApiResponse, RestConfig, RestMetricsConfig, RestMiddlewareConfig, RestServer};
let metrics = MetricsRegistry::new();
let router = Router::new()
.route("/ready", get(|| async { ApiResponse::success("ok") }))
.merge(metrics_router(metrics.clone()));
let config = RestConfig {
metrics_registry: Some(metrics),
middlewares: RestMiddlewareConfig {
metrics: RestMetricsConfig { enabled: true },
..RestMiddlewareConfig::default()
},
..RestConfig::default()
};
let app = RestServer::new(config, router).into_router();
```
`metrics_router` 暴露 Prometheus text at `/metrics`。当前 registry 覆盖:
- HTTP request count、duration、in-flight。
- gRPC unary count、duration。
- SQL query count、duration、error count。
- Redis command count、duration、error count。
- cache hit/miss/set/delete/loader/backfill events。
- resilience breaker/shedder/concurrency/timeout events。
标签只使用低基数字段,禁止 raw path、SQL 文本、Redis key、cache key、请求体或用户 id。
### 成熟 Prometheus client adapter
`observability-prometheus-client` feature 提供 `PrometheusClientMetricsRegistry`,底层使用 `prometheus-client` crate,默认不启用:
```toml
rs-zero = { version = "0.1", features = ["observability-prometheus-client"] }
```
该 adapter 适合需要对接成熟 OpenMetrics/Prometheus client 生态的服务。当前它覆盖 HTTP、RPC、SQL、Redis 的核心 counter 与 duration histogram;cache/resilience 仍由内置 registry 覆盖。两种 registry 不应在同一条请求路径重复记录同一指标。
### 自动覆盖边界
- REST metrics middleware 自动记录 matched route pattern。
- Redis cache adapter 内部通过 `RedisCommandRecorder` 记录 pool、command、degradation、breaker 事件,不记录 Redis key 或 URL。
- SQL 生成 repository 和 `health_check_with_metrics` 会调用 `observe_sql_query`;手写 SQL 仍应通过 repository 封装或显式 helper 接入。
- RPC `RpcServerLayerStack`、`RpcResilienceLayer` 和生成 skeleton 默认记录 unary/streaming 边界;手写 tonic stack 未挂 layer 时不会自动记录。
## Tracing 与日志关联
REST 使用 `x-request-id` header,gRPC 使用同名 metadata。HTTP/RPC span 会带上统一 `CorrelationContext` 字段:`request_id`、合法入站 `traceparent`、`trace_id/span_id`、service、transport、route/method、status/code。REST 只记录 matched route pattern;缺少 pattern 时写 `unknown`,不会把 raw path、query、用户 id 或 token 写入日志关联字段。
`core::init_tracing` 会输出 span close event,便于从日志关联到 request id 与 span 字段。`LogConfig` 默认在 subscriber 最终输出前脱敏,覆盖 text/JSON、span fields、event fields 和错误文本;JSON 输出脱敏后仍保持可解析。`RollingFile` 支持运行期按 `max_bytes` 大小轮转并通过 `max_files` 控制保留数量;`max_age` 仅作为平台日志策略边界,按时间清理应交给 logrotate、journald、容器日志驱动或托管日志平台。
## OpenTelemetry
`OpenTelemetryConfig` models three exporter modes:
- `Disabled`: no global subscriber is installed.
- `Stdout`: installs a local `tracing-subscriber` pipeline for span inspection.
- `Otlp { endpoint }`: installs a real OTLP tracing pipeline when the `otlp` feature is enabled.
Use `init_opentelemetry_tracing_with_handle` when the application needs to flush or shut down exporters explicitly.
## OTLP traces
`OtlpTraceConfig` supports gRPC/HTTP protobuf protocol selection, headers, resource attributes, sampling ratio, timeout and `TraceShutdownHandle`. Default tests do not require a collector; external collector checks stay ignored/gated.