Files
Bruno GaoandQwen-Coder 43d1229bd7 M1: Add complete documentation structure and contract specifications
- 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]>
2026-02-11 23:41:04 +08:00

4.8 KiB
Raw Permalink Blame History

可观测性契约 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();