mirror of
https://github.com/iflytek/skillhub.git
synced 2026-09-24 00:55:35 +00:00
* feat(observability): establish request correlation boundary Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * feat(observability): add selectable tracing modes Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * feat(observability): propagate async trace context Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * docs(observability): document tracing deployment modes Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * fix(observability): tighten tracing integration boundaries Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * fix(observability): harden operational log privacy Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * feat(observability): propagate message trace context Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * fix(observability): document message propagation semantics Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * test(auth): isolate security context between tests Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * fix(observability): skip otlp exporter without endpoint Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> --------- Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
533 lines
21 KiB
Markdown
533 lines
21 KiB
Markdown
# SkillHub 日志关联与链路追踪建设方案
|
||
|
||
> 日期:2026-07-31
|
||
>
|
||
> 状态:Accepted(2026-07-31,按本文分阶段实施和验证)
|
||
>
|
||
> 关联:GitHub Issue #597
|
||
> 适用基线:Spring Boot 3.2.3、Java 21、Logback、Micrometer Actuator
|
||
|
||
## 1. 背景
|
||
|
||
SkillHub 已经使用 `X-Request-Id` 关联 API 响应、业务日志和审计记录,但目前仍存在以下问题:
|
||
|
||
- 部分应用服务和 DTO 直接读取 SLF4J MDC,可观测性实现泄漏到了业务代码。
|
||
- `X-Request-Id` 接受任意客户端输入,没有统一的长度和字符约束。
|
||
- `@Async` 线程池没有显式传播请求和 Trace 上下文,异步日志可能丢失关联信息。
|
||
- 当前没有标准分布式 Trace,无法通过一个 ID 串联 SkillHub、Scanner 等服务调用。
|
||
- 日志字段尚未形成适合 Elasticsearch/Kibana 查询的稳定结构。
|
||
|
||
本方案用最小建设成本建立通用日志关联与链路追踪基础设施。它不负责建设完整的企业
|
||
可观测性平台,也不把日志、Trace 或 Metrics 逻辑写入业务处理器。
|
||
|
||
Issue #597 中“搜索索引可靠异步交付”应作为独立问题处理,不属于本文范围。
|
||
|
||
## 2. 建设目标
|
||
|
||
一期需要实现:
|
||
|
||
1. 每个 HTTP 请求都有合法的 `request.id`。
|
||
2. 启用 Tracing 时,日志包含标准 `trace.id` 和 `span.id`。
|
||
3. `otel-sdk` 模式使用 W3C `traceparent` / `tracestate` 传播 Trace Context。
|
||
4. 业务代码不直接读写 MDC,也不直接依赖 OpenTelemetry 或 SkyWalking API。
|
||
5. 现有 Spring `@Async` 执行器能够正确传播并清理上下文。
|
||
6. 日志以结构化 JSON 输出到 stdout,可由 Filebeat/Fluent Bit 采集到
|
||
Elasticsearch/Kibana。
|
||
7. Trace 可以选择通过 OTLP Collector 接入 SkyWalking。
|
||
8. Collector、SkyWalking、Elasticsearch 或日志采集器不可用时,SkillHub 业务继续运行。
|
||
9. SkillHub 应用配置只能启用一个应用内 Tracer;`external-agent` 模式下唯一外部
|
||
Agent 由部署参数和发布检查保证。
|
||
|
||
本方案按多个小阶段、小提交实施和验证,全部通过后再统一创建一个替代 PR。
|
||
|
||
## 3. 非目标
|
||
|
||
一期不建设:
|
||
|
||
- 搜索索引可靠队列、重试、死信和重放。
|
||
- 多租户差异化采样和运行时动态采样。
|
||
- Spring Cloud Config、Nacos 或可写 Actuator 配置端点。
|
||
- 应用内 OTLP 熔断器或自定义重试框架。
|
||
- 审计日志归档、物理隔离和 WORM 存储。
|
||
- 通用 PII/DLP 检测平台。
|
||
- Prometheus/Grafana/Kibana 告警模板和容量规划平台。
|
||
- Spring Boot 2.x 或 Java 17 兼容。
|
||
- 在业务类上增加 Trace 注解或要求业务开发者操作 Span。
|
||
|
||
## 4. 总体架构
|
||
|
||
```text
|
||
HTTP request
|
||
│
|
||
├─ RequestIdFilter
|
||
│ └─ request.id
|
||
│
|
||
└─ Micrometer Observation / Tracing
|
||
├─ MDC correlation
|
||
│ └─ JSON stdout
|
||
│ └─ Filebeat / Fluent Bit
|
||
│ └─ Elasticsearch / Kibana
|
||
│
|
||
└─ OpenTelemetry Bridge
|
||
└─ OTLP
|
||
└─ OpenTelemetry Collector
|
||
└─ SkyWalking OAP
|
||
```
|
||
|
||
稳定边界是:
|
||
|
||
- 应用内使用 Micrometer Observation/Tracing。
|
||
- `otel-sdk` 模式跨进程使用 W3C Trace Context。
|
||
- Trace 导出使用 OTLP。
|
||
- 日志使用 ECS 风格字段。
|
||
- SkyWalking、Elasticsearch 和 Kibana 都是部署适配器,不进入业务模型。
|
||
|
||
## 5. 运行模式
|
||
|
||
通过一个启动期配置选择运行模式:
|
||
|
||
```yaml
|
||
skillhub:
|
||
observability:
|
||
tracing-mode: ${SKILLHUB_TRACING_MODE:none}
|
||
```
|
||
|
||
允许值和确定行为:
|
||
|
||
| 模式 | Micrometer Tracer | OTLP Exporter | 外部 Agent | 无 Agent/endpoint 时 |
|
||
|------|-------------------|---------------|------------|---------------------|
|
||
| `none` | NOOP | 无 | 不支持 | 只有 `request.id` |
|
||
| `otel-sdk` | OTel Bridge | 配置 endpoint 时创建 | 不支持 | 仍建立进程内 Trace,但不导出 |
|
||
| `external-agent` | NOOP | 无 | 可选 | 记录警告并退化为只有 `request.id` |
|
||
|
||
运行模式是启动期不变量,不支持热切换。
|
||
|
||
必须保证:
|
||
|
||
- `none` 和 `external-agent` 不创建应用内 OTel Span。
|
||
- `otel-sdk` 不支持同时启用 SkyWalking、OTel 或其他外部 Tracing Agent;应用只能校验
|
||
自身 endpoint/mode 冲突,不能可靠识别任意 JVM Agent。
|
||
- `external-agent` 不创建 OTLP Exporter。
|
||
- SkillHub 配置能够识别的冲突应在启动时失败;任意 Java Agent 无法被应用可靠识别,因此
|
||
部署检查和原型测试还必须验证实际 JVM 参数中只有一个 Tracer。
|
||
|
||
一期实现并验证三种模式的应用上下文互斥边界和日志关联。`external-agent` 只验证
|
||
SkyWalking Agent 接管 Trace 时应用内 OTel Tracer/Exporter 不工作;“只挂载一个外部
|
||
Agent”属于部署验收项。SkyWalking 特有高级能力不进入 SkillHub 核心代码。
|
||
|
||
## 6. 关联字段契约
|
||
|
||
### 6.1 对外日志字段
|
||
|
||
日志输出统一使用:
|
||
|
||
| 字段 | 必需性 | 含义 |
|
||
|------|--------|------|
|
||
| `request.id` | HTTP 请求或显式任务上下文中存在 | SkillHub API、响应和审计关联 ID |
|
||
| `trace.id` | 当前存在有效 Trace 时 | 分布式 Trace ID |
|
||
| `span.id` | 当前 Tracer 能提供时 | 当前调用节点 ID |
|
||
| `service.name` | 始终存在 | 固定为 `skillhub` |
|
||
| `service.version` | 部署时提供 | 发布版本或镜像对应 Commit |
|
||
| `service.environment` | 部署时提供 | 当前部署环境 |
|
||
|
||
`request.id` 与 `trace.id` 不能合并:
|
||
|
||
- `request.id` 属于 SkillHub API 契约,可出现在响应和审计记录中。
|
||
- `trace.id` 属于可选的分布式追踪上下文,可能被采样或关闭。
|
||
|
||
启动日志以及没有显式任务上下文的后台维护日志允许不包含 `request.id`。
|
||
|
||
### 6.2 内部字段映射
|
||
|
||
日志基础设施负责字段映射,业务代码不感知具体 MDC 键:
|
||
|
||
| 来源 | 内部字段 | 输出字段 |
|
||
|------|----------|----------|
|
||
| SkillHub Request Context | `requestId` | `request.id` |
|
||
| Micrometer OTel Bridge | `traceId` | `trace.id` |
|
||
| Micrometer OTel Bridge | `spanId` | `span.id` |
|
||
| SkyWalking Logback Toolkit 事件转换器 | `tid` | `trace.id` |
|
||
|
||
SkyWalking Agent 是否能稳定提供独立 `span.id` 以实际原型结果为准。无法稳定提供时允许只
|
||
输出 `trace.id`,不得解析不稳定的内部字符串格式。
|
||
|
||
External Agent 模式通过 SkyWalking 官方 Logback Toolkit 从当前日志事件读取 `tid`;
|
||
这不是业务代码读取 MDC,也不能假定 `tid` 一定存在于异步日志线程的 MDC 中。日志编码器
|
||
只读取允许的关联字段,不得把整个 MDC Map 自动写入 JSON。
|
||
|
||
## 7. Request ID
|
||
|
||
### 7.1 输入规则
|
||
|
||
客户端可以传入 `X-Request-Id`,但必须同时满足:
|
||
|
||
- 长度为 1–64 个字符。
|
||
- 首字符是字母或数字。
|
||
- 其余字符只允许字母、数字、`.`、`_`、`:`、`-`。
|
||
|
||
建议校验表达式:
|
||
|
||
```regex
|
||
^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$
|
||
```
|
||
|
||
请求头缺失、为空或不合法时,服务端生成 UUID。响应始终返回最终采用的
|
||
`X-Request-Id`。
|
||
|
||
### 7.2 代码边界
|
||
|
||
新增通用 `RequestIdAccessor` 和对应的 Request ID Scope:
|
||
|
||
- Filter 负责解析、校验、建立和清理 Request ID 上下文。
|
||
- 独立 ThreadLocal Scope 是 Request ID 的进程内权威来源。
|
||
- 为该 Scope 注册 Micrometer `ThreadLocalAccessor`,由
|
||
`ContextPropagatingTaskDecorator` 捕获、恢复和清理。
|
||
- Scope 同步维护日志所需的 MDC 镜像,但读取方不能把 MDC 当作权威来源。
|
||
- API 响应工厂通过该抽象读取 Request ID。
|
||
- 审计编排通过该抽象或明确参数读取 Request ID。
|
||
- 应用服务、Controller 和 DTO 不再直接调用 `MDC.get()`。
|
||
- MDC 只作为日志适配器,不再作为业务上下文的权威来源。
|
||
|
||
## 8. Tracing 配置
|
||
|
||
`skillhub-app` 使用 Spring Boot 3.2.3 管理的依赖版本:
|
||
|
||
```xml
|
||
<dependency>
|
||
<groupId>io.micrometer</groupId>
|
||
<artifactId>micrometer-tracing-bridge-otel</artifactId>
|
||
</dependency>
|
||
<dependency>
|
||
<groupId>io.opentelemetry</groupId>
|
||
<artifactId>opentelemetry-exporter-otlp</artifactId>
|
||
</dependency>
|
||
```
|
||
|
||
基础配置:
|
||
|
||
```yaml
|
||
management:
|
||
tracing:
|
||
sampling:
|
||
probability: ${SKILLHUB_TRACING_SAMPLING_PROBABILITY:0.1}
|
||
baggage:
|
||
enabled: false
|
||
propagation:
|
||
type: W3C
|
||
otlp:
|
||
tracing:
|
||
timeout: ${SKILLHUB_OTLP_TIMEOUT:5s}
|
||
compression: ${SKILLHUB_OTLP_COMPRESSION:gzip}
|
||
```
|
||
|
||
基础配置不得为 OTLP endpoint 提供默认地址。只有 `otel-sdk` 部署显式设置以下标准
|
||
Spring Boot 配置时才创建 Exporter:
|
||
|
||
```bash
|
||
MANAGEMENT_OTLP_TRACING_ENDPOINT=http://otel-collector:4318/v1/traces
|
||
```
|
||
|
||
一期沿用 OpenTelemetry 1.31 的默认 BatchSpanProcessor 有界队列和丢弃策略,不增加应用内
|
||
重试、熔断或自定义队列实现。
|
||
|
||
## 9. 日志输出
|
||
|
||
### 9.1 输出模式
|
||
|
||
- 本地开发默认使用可读的文本日志。
|
||
- `SKILLHUB_LOG_FORMAT=json` 启用 ECS 风格 JSON stdout。
|
||
- JSON 编码器显式输出标准字段和三个关联字段,不启用“输出全部 MDC”。
|
||
- JSON ConsoleAppender 外包一层 Logback AsyncAppender,初始队列容量为 1024,并允许通过
|
||
`SKILLHUB_LOG_ASYNC_QUEUE_SIZE` 调整。
|
||
- AsyncAppender 使用非阻塞策略;队列耗尽时日志可能丢失,审计事实不依赖该通道。
|
||
- 异常使用 `error.type`、`error.message`、`error.stack_trace`。
|
||
- 队列容量保持可配置,默认值在原型压测后固定,不在设计阶段猜测。
|
||
- 异常和队列丢弃行为必须在测试中验证。
|
||
|
||
示例:
|
||
|
||
```json
|
||
{
|
||
"@timestamp": "2026-07-31T10:10:10.123Z",
|
||
"log.level": "INFO",
|
||
"service.name": "skillhub",
|
||
"service.version": "0.2.15",
|
||
"service.environment": "test",
|
||
"request.id": "req-123",
|
||
"trace.id": "4bf92f3577b34da6a3ce929d0e0e4736",
|
||
"span.id": "00f067aa0ba902b7",
|
||
"log.logger": "com.iflytek.skillhub...",
|
||
"message": "..."
|
||
}
|
||
```
|
||
|
||
应用只输出 stdout,不直接依赖 Elasticsearch SDK,也不直接写 Elasticsearch。
|
||
|
||
### 9.2 审计边界
|
||
|
||
`audit_log` 数据库记录仍是审计事实来源。stdout 日志不能代替审计记录,审计留存和归档
|
||
不在本方案中处理。
|
||
|
||
## 10. 上下文传播
|
||
|
||
### 10.1 Spring 异步执行器
|
||
|
||
为现有 `skillhubEventExecutor` 配置 Spring Framework 6.1 的
|
||
`ContextPropagatingTaskDecorator`:
|
||
|
||
- 提交任务时捕获 Request ID 和 Trace Context。
|
||
- 执行任务时恢复上下文。
|
||
- 执行完成后在 `finally` 中清理。
|
||
- `CallerRunsPolicy` 触发时也必须保持正确的嵌套作用域。
|
||
|
||
测试必须重复复用同一工作线程,证明不同请求之间不会串号。
|
||
|
||
### 10.2 消息队列与长生命周期后台线程
|
||
|
||
Redis Stream 消费循环和 Reclaimer 不继承应用启动线程或任意请求的 MDC。Producer 通过
|
||
通用消息 Observation 把 W3C Trace Context 与受控 Request ID 注入 transport metadata;
|
||
Consumer/Reclaimer 逐条提取、建立 Scope,并在处理结束后清理。Scanner HTTP 调用自然成为
|
||
Consumer Span 的子调用。
|
||
|
||
上下文不写入 `ScanTask` 或搜索业务 payload,也不改变可靠任务状态机。普通定时任务没有
|
||
上游 carrier,仍建立独立执行上下文;长期延迟任务使用稳定任务 ID 或 Span Link,不维持
|
||
超长父 Span。
|
||
|
||
### 10.3 HTTP 出站
|
||
|
||
一期只管理两类 HTTP Client:
|
||
|
||
- 内部 Scanner Client:使用 Spring 管理且带 Observation 的 Builder,传播 W3C Trace
|
||
Context。
|
||
- 其他现有 Client:GitHub、GitLab、内置 Skill 公网下载和 S3 Client 均不在一期新增
|
||
Trace Context 传播。
|
||
|
||
后续新增 Client 必须明确选择内部或外部配置,不能依赖全局 Host 正则或在业务代码中手工
|
||
删除 Header。
|
||
|
||
## 11. SkyWalking 与 Elasticsearch 接入
|
||
|
||
### 11.1 OTel SDK 模式
|
||
|
||
推荐链路:
|
||
|
||
```text
|
||
SkillHub
|
||
→ OTLP/HTTP
|
||
→ OpenTelemetry Collector
|
||
→ OTLP
|
||
→ SkyWalking OAP
|
||
```
|
||
|
||
Collector 用于协议适配和后端路由,不是 SkillHub 的启动依赖。
|
||
|
||
SkyWalking 10.3 的 OTLP Trace 会转换为 Zipkin Trace,并通过 Zipkin Query/Lens UI 查询。
|
||
它不等价于 SkyWalking Java Agent 的原生拓扑、慢 SQL 和 Profiling 能力,部署文档必须
|
||
明确该差异。原型报告必须记录实际使用的 Maven 依赖、Collector、OAP 和 Agent 版本及
|
||
查询结果。
|
||
|
||
### 11.2 External Agent 模式
|
||
|
||
需要 SkyWalking 原生能力时:
|
||
|
||
- 使用 `external-agent`。
|
||
- 不配置 SkillHub OTLP endpoint。
|
||
- 由部署环境挂载并启动 SkyWalking Java Agent。
|
||
- 使用 SkyWalking 官方 Logback Toolkit 提供 Trace ID。
|
||
- 日志基础设施将 `tid` 映射为 `trace.id`。
|
||
|
||
### 11.3 日志链路
|
||
|
||
```text
|
||
SkillHub JSON stdout
|
||
→ Filebeat / Fluent Bit
|
||
→ Elasticsearch
|
||
→ Kibana
|
||
```
|
||
|
||
Kibana 使用 `trace.id` 查询日志,SkyWalking 使用同一个 Trace ID 查询调用链。
|
||
|
||
## 12. 实施步骤
|
||
|
||
### 阶段一:Request ID 与日志边界
|
||
|
||
1. 增加 Request ID 校验。
|
||
2. 建立 `RequestIdAccessor`。
|
||
3. 移除应用服务、Controller、DTO 对 MDC 的直接读取。
|
||
4. 增加允许字段明确的结构化日志配置。
|
||
5. 增加 Request ID 和日志字段测试。
|
||
|
||
可观察结果:
|
||
|
||
- 非法 Request ID 被替换。
|
||
- API 响应和审计记录仍使用同一 Request ID。
|
||
- 业务类不再 import `org.slf4j.MDC`。
|
||
|
||
### 阶段二:Micrometer + OTel
|
||
|
||
1. 增加 Tracing Bridge 和 OTLP Exporter 依赖。
|
||
2. 增加 `none`、`otel-sdk`、`external-agent` 模式。
|
||
3. 设置 W3C、关闭 baggage、配置采样率。
|
||
4. 保证无 endpoint 时不会产生网络连接。
|
||
5. 保证每个模式只存在一个实际 Tracer。
|
||
|
||
可观察结果:
|
||
|
||
- `none` 模式只有 `request.id`。
|
||
- `otel-sdk` 模式日志出现标准 Trace 字段。
|
||
- `external-agent` 模式不会产生应用内 OTel Trace。
|
||
|
||
### 阶段三:传播边界
|
||
|
||
1. 为 `skillhubEventExecutor` 增加上下文传播。
|
||
2. 验证线程复用、嵌套任务和 `CallerRunsPolicy`。
|
||
3. 让内部 Scanner Client 使用 Spring 管理且可观测的 Client Builder。
|
||
4. 验证外部 HTTP Client 不发送 Trace Context。
|
||
|
||
### 阶段四:部署示例与远端验证
|
||
|
||
1. 提供最小 OTel Collector 配置示例。
|
||
2. 补充 SkyWalking OTLP 与 Agent 模式差异。
|
||
3. 将待测分支合入 `big-main`,记录合入后的精确 Commit SHA。
|
||
4. 构建绑定 `big-main` SHA 的测试镜像。
|
||
5. 在共享测试机使用独立容器、网络、数据卷和动态端口运行三个原型。
|
||
6. 生成中文测试报告并保存在本地私有目录,不提交开源仓库。
|
||
|
||
每个阶段使用独立的小提交并保留在同一实现分支;前一阶段的范围测试通过后再进入下一
|
||
阶段。公开 Issue 和 PR 统一在阶段五创建。
|
||
|
||
### 阶段五:社区交付(最后执行)
|
||
|
||
该阶段必须在远端验证全部通过后执行:
|
||
|
||
1. 创建新的可观测性建设 Issue,说明它承接 #597 中的“通用日志关联与链路追踪”部分。
|
||
2. 搜索索引可靠异步交付继续作为独立问题,不混入新的可观测性 Issue。
|
||
3. 从经过验证的实现分支创建新的 PR,并关联新 Issue。
|
||
4. PR 只包含公开代码、配置、自动化测试和公开部署说明;不得包含测试机地址、凭证、
|
||
私有端口、原始远端日志或本地中文测试报告。
|
||
5. 在 #597、#644 及其他被替代的关联项中回复:
|
||
- 原问题是否真实存在。
|
||
- 为什么不采用原 PR 的实现。
|
||
- 新方案的边界和主要改动。
|
||
- 已完成的自动化及远端验证摘要。
|
||
- 新 Issue 和替代 PR 的链接。
|
||
6. 确认维护者需要的信息完整后,关闭已被替代的 PR;不在验证完成前抢先关闭。
|
||
7. #597 等关联 Issue 只根据剩余问题是否已有明确承接决定关闭、缩小范围或继续保留,
|
||
不因替代 PR 创建而自动关闭。
|
||
8. 新 PR 通过 Review 和 CI 后,确认 PR Head 仍等于已验证的功能 SHA,且该 SHA 可从已
|
||
测试的 `big-main` SHA 到达;满足后才允许更新 `main`。
|
||
9. 如果 Review 或 CI 修复改变了代码、配置或测试脚本,则原验证证据失效:先将新 SHA
|
||
合入 `big-main`,重新构建镜像并完成受影响的远端验证,再更新 `main`。
|
||
|
||
## 13. 验证方案
|
||
|
||
### 13.1 自动化测试
|
||
|
||
至少覆盖:
|
||
|
||
- 未传 Request ID 时自动生成。
|
||
- 合法 Request ID 被保留。
|
||
- 空值、超长值和非法字符被替换。
|
||
- Filter 正常、异常退出后都清理上下文。
|
||
- API 响应、审计和日志中的 Request ID 一致。
|
||
- JSON 只输出允许的关联字段。
|
||
- Trace 采样率在测试中设为 `1.0` 后可稳定断言。
|
||
- `@Async` 线程恢复父上下文。
|
||
- 连续复用同一线程执行不同请求时不串号。
|
||
- `CallerRunsPolicy` 下上下文正确恢复。
|
||
- `none`、`otel-sdk`、`external-agent` 的 Spring Context 互斥。
|
||
- 未配置 OTLP endpoint 时不创建网络导出。
|
||
- 内部 Scanner 请求携带 `traceparent`。
|
||
- Redis Stream Producer/Consumer 保持同一 Trace 和 Request ID,处理结束后线程不串号。
|
||
- 重试发布和 Reclaimer 重新消费仍能恢复消息关联上下文。
|
||
- 外部 HTTP 请求不携带 `traceparent`。
|
||
|
||
### 13.2 远端原型
|
||
|
||
#### 原型 A:none
|
||
|
||
- 不部署 Collector。
|
||
- SkillHub 正常启动并完成核心 Smoke Test。
|
||
- 日志存在 `request.id`,不存在伪造的 Trace 字段。
|
||
|
||
#### 原型 B:otel-sdk
|
||
|
||
- SkillHub → Collector → SkyWalking 跑通。
|
||
- JSON 日志进入 Elasticsearch/Kibana。
|
||
- Kibana 与 SkyWalking 能用同一 `trace.id` 查询。
|
||
- Collector 停止后 SkillHub API 和异步任务继续工作。
|
||
|
||
#### 原型 C:external-agent
|
||
|
||
- SkyWalking Java Agent 提供原生 Trace。
|
||
- 应用内 OTel Exporter 不工作。
|
||
- 日志能用 SkyWalking Trace ID 关联。
|
||
- 不产生双 Trace、重复 Span 或两个冲突的 Trace ID。
|
||
|
||
### 13.3 远端测试场景
|
||
|
||
- HTTP 成功、4xx、5xx 和未认证请求。
|
||
- Scanner 成功、超时和失败。
|
||
- 异步事件正常执行和抛出异常。
|
||
- Redis Stream 正常消费、失败重试、Pending Reclaim 和重复投递。
|
||
- 并发请求重复使用线程池。
|
||
- Collector 启动、停止和恢复。
|
||
- 日志采集器停止或消费变慢。
|
||
- 采样率 `0.0`、`0.1` 和 `1.0`。
|
||
- 容器收到 SIGTERM 后日志和 Trace 的关闭行为。
|
||
- 日志中不出现 Authorization、Cookie、Token、密码和完整请求体。
|
||
|
||
## 14. 验收标准
|
||
|
||
以下条件全部满足后,一期才算完成:
|
||
|
||
- [ ] 三种模式行为与本文一致。
|
||
- [ ] 业务代码不再直接读取或写入 MDC。
|
||
- [ ] Request ID 校验、响应和审计关联测试通过。
|
||
- [ ] 日志字段符合约定,且不输出完整 MDC。
|
||
- [ ] Spring 异步执行器上下文传播和隔离测试通过。
|
||
- [ ] Redis Stream 消息上下文传播、重试、Reclaimer 和隔离测试通过。
|
||
- [ ] 内外部 HTTP 传播边界测试通过。
|
||
- [ ] 无 OTLP endpoint 时不存在外部连接尝试。
|
||
- [ ] Collector 中断不影响 SkillHub 业务结果。
|
||
- [ ] OTel SDK 与 SkyWalking Agent 不会同时产生 Trace。
|
||
- [ ] `make test-backend-app` 通过。
|
||
- [ ] `make typecheck-web` 和 `make lint-web` 通过。
|
||
- [ ] 基于 `big-main` 合入后精确 SHA 构建的远端三个原型通过。
|
||
- [ ] 中文测试报告保存在本地私有目录。
|
||
- [ ] 新的可观测性 Issue 和替代 PR 已创建并互相关联。
|
||
- [ ] #597、#644 等关联项已获得清晰回复,被替代的旧 PR 已关闭。
|
||
- [ ] 关联 Issue 已根据剩余范围分别关闭、缩小范围或保留,且状态理由清楚。
|
||
- [ ] 新 PR Head 与已验证功能 SHA 一致,且可从已测试的 `big-main` SHA 到达。
|
||
- [ ] 通过验证后才允许更新 `main`。
|
||
|
||
## 15. 回滚
|
||
|
||
出现问题时:
|
||
|
||
1. 将 `SKILLHUB_TRACING_MODE` 改为 `none`。
|
||
2. 删除 `MANAGEMENT_OTLP_TRACING_ENDPOINT`。
|
||
3. 将 `SKILLHUB_LOG_FORMAT` 改为 `text`。
|
||
4. 保留 Request ID 和原有文本日志能力。
|
||
5. 通过滚动重启恢复,不进行运行时模式切换。
|
||
|
||
Tracing 和结构化日志关闭后不得影响 SkillHub 的业务状态、数据库状态或任务执行语义。
|
||
|
||
## 16. 已知限制
|
||
|
||
- 10% Head Sampling 下,全量日志中的部分 `trace.id` 在 SkyWalking 中没有对应 Trace。
|
||
- SkyWalking OTLP 模式的展示能力弱于原生 Java Agent。
|
||
- 日志队列在背压时可能丢弃日志,这是保护业务线程的预期行为。
|
||
- External Agent 提供哪些 MDC 字段取决于具体 Agent 和版本。
|
||
- 一期只处理通用关联和传播,不保证搜索索引异步交付可靠性。
|
||
|
||
## 17. 参考资料
|
||
|
||
- [Spring Boot 3.2.3 Tracing](https://docs.spring.io/spring-boot/docs/3.2.3/reference/html/actuator.html#actuator.micrometer-tracing)
|
||
- [Micrometer Tracing](https://docs.micrometer.io/tracing/reference/)
|
||
- [OpenTelemetry Java OTLP Exporter](https://opentelemetry.io/docs/languages/java/exporters/)
|
||
- [W3C Trace Context](https://www.w3.org/TR/trace-context/)
|
||
- [SkyWalking OpenTelemetry Trace](https://skywalking.apache.org/docs/main/v10.3.0/en/setup/backend/otlp-trace/)
|
||
- [SkyWalking Logback Toolkit](https://skywalking.apache.org/docs/skywalking-java/next/en/setup/service-agent/java-agent/application-toolkit-logback-1.x/)
|
||
- [Elastic ECS Tracing Fields](https://www.elastic.co/docs/reference/ecs/ecs-tracing)
|
||
- [方案调研](./research/2026-07-31-observability-common-solutions.md)
|