- Add comprehensive docs/ directory with standardized structure - Include architecture specification and contract documents - Add prompt templates for development workflows - Establish M1 deliverables as frozen specifications Co-authored-by: Qwen-Coder <[email protected]>
4.8 KiB
可观测性契约 v1.0
1. 结构化日志字段(必须写入 MDC)
| 字段 | 来源 | 必填 | 说明 |
|---|---|---|---|
| traceId | TraceIdFilter | 是 | 全链路追踪 ID |
| spanId | 预留(OTel 接入后自动填充) | 否 | 当前跨度 ID |
| requestId | Header: X-Request-Id | 否 | 网关生成的请求唯一 ID |
| customerId | SecurityContextFilter | 是 | 租户 |
| orgId | SecurityContextFilter | 是 | 组织 |
| userId | SecurityContextFilter | 是 | 操作人 |
| requestMethod | Filter | 是 | HTTP Method |
| requestUri | Filter | 是 | 请求路径 |
2. 日志格式
dev profile:明文(人读友好)
2026-02-11 10:30:45.123 INFO [traceId=abc-123] [userId=u001] c.e.o.a.u.CreateOrderUseCase : 订单创建成功 orderId=12345 costMs=45
prod profile:JSON(Loki 采集解析)
{ "timestamp": "2026-02-11T10:30:45.123Z", "level": "INFO", "logger": "c.e.o.a.u.CreateOrderUseCase", "message": "订单创建成功", "traceId": "abc-123", "spanId": "", "requestId": "req-456", "customerId": "cust-001", "orgId": "org-001", "userId": "u001", "orderId": "12345", "costMs": 45 }
3. 日志级别规范
| 场景 | 级别 | 模板 |
|---|---|---|
| HTTP 请求进入/完成 | INFO | {method} {uri} {status} costMs={ms} |
| 业务异常 | WARN | {errorCode}: {message} + 关键业务字段 |
| 系统异常 | ERROR | {errorCode}: {message} + 完整堆栈 |
| 外部 HTTP 调用成功 | DEBUG | HTTP {method} {service} {status} costMs={ms} |
| 外部 HTTP 调用失败 | WARN | HTTP {method} {service} {status} costMs={ms} |
| SQL 慢查询 | WARN | slowQuery costMs={ms} rows={n} |
| UseCase 入口 | DEBUG | execute() 开始 + 关键入参摘要 |
| UseCase 完成 | INFO | execute() 完成 + 关键出参摘要 + costMs |
4. 慢查询阈值(可配置)
app: observability: slow-query-threshold-ms: 200 # 默认 200ms slow-http-call-threshold-ms: 3000 # 默认 3s
超过阈值时输出 WARN 日志,包含:costMs, sql 摘要(或 HTTP 目标地址)
5. Actuator 端点配置
| 端点 | 用途 | 暴露策略 |
|---|---|---|
| /actuator/health | K8s 探针 | 公开(无需认证) |
| /actuator/health/liveness | K8s liveness 探针 | 公开 |
| /actuator/health/readiness | K8s readiness 探针 | 公开 |
| /actuator/prometheus | Prometheus 指标采集 | 仅内网(通过 K8s Service 暴露给 Prometheus) |
| /actuator/info | 版本/构建/Git 信息 | 仅内网 |
| 其他端点 | 默认关闭 | - |
6. Metrics 命名规范
格式:{service}{module}{type}_{name} 类型后缀:_total(Counter), _seconds(Timer/Histogram), _active(Gauge)
示例:
- order_api_http_requests_total
- order_usecase_create_order_seconds
- order_infra_db_pool_active
- order_infra_redis_commands_seconds
自定义业务指标使用 Micrometer API(Counter/Timer/Gauge), 禁止直接使用 Prometheus Client 库。
7. 健康检查与优雅停机
K8s 探针配置
livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 15 periodSeconds: 10
readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 10 periodSeconds: 5
startupProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 5 periodSeconds: 5 failureThreshold: 30 # 最多等 150 秒启动
优雅停机配置
Spring 侧: server.shutdown=graceful spring.lifecycle.timeout-per-shutdown-phase=30s
K8s 侧: terminationGracePeriodSeconds: 45(> Spring 的 30s) preStop hook: sleep 5(等待 Service 摘除 endpoint 后再开始停机)
时序: K8s 发 SIGTERM → preStop sleep 5s → Spring 停止接收新请求 → 等待已有请求完成(最长 30s) → 进程退出 → K8s 确认 Pod 终止
✅ 可自动检查项
| 规则 | 检查方式 |
|---|---|
| TraceIdFilter 存在 | ArchUnit: 至少一个类在 ..api.filter.. 包下实现 Filter 并操作 MDC |
| logback-spring.xml 存在且包含 JSON 格式 | CI 脚本检查文件存在性 |
| actuator 端点配置正确 | 集成测试:启动后 GET /actuator/health 返回 200 |
| 优雅停机配置 | application.yml 检查 server.shutdown=graceful 存在 |
❌ 典型违规示例
违规 1:日志不带 traceId
// 错误!直接 System.out 或未经 MDC 的 logger System.out.println("订单创建成功: " + orderId);
// 正确:使用 SLF4J,traceId 通过 MDC 自动注入 log.info("订单创建成功 orderId={} costMs={}", orderId, costMs);
违规 2:直接使用 Prometheus Client
// 错误! import io.prometheus.client.Counter; Counter orderCounter = Counter.build().name("orders").help("xxx").register();
// 正确:使用 Micrometer 抽象 import io.micrometer.core.instrument.MeterRegistry; meterRegistry.counter("order_usecase_create_order_total").increment();