# Otel Recovery Mechanism

<cite>
**本文引用的文件**
- [RECOVERY_GUIDE.md](file://utility/otel/RECOVERY_GUIDE.md)
- [manager.go](file://utility/otel/manager.go)
- [recovery.go](file://utility/otel/recovery.go)
- [config.go](file://utility/otel/config.go)
- [utils.go](file://utility/otel/utils.go)
- [handler.go](file://utility/otel/handler.go)
- [errors.go](file://utility/otel/errors.go)
- [recovery_example_test.go](file://utility/otel/recovery_example_test.go)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [组件详解](#组件详解)
6. [依赖关系分析](#依赖关系分析)
7. [性能与可靠性考量](#性能与可靠性考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件围绕 OpenTelemetry（OTel）在服务下线后自动恢复连接的机制进行系统化说明。目标是帮助开发者快速理解并正确使用 OTel 的导出器重试、健康检查与后台恢复管理器三者协同工作的方式，确保在 OTel 收集器短暂不可用或重启后，应用能够自动恢复数据上报，避免长时间断流。

## 项目结构
OTel 恢复机制位于 utility/otel 目录，关键文件包括：
- 配置与初始化：config.go、utils.go
- 核心管理器：manager.go
- 连接恢复管理器：recovery.go
- 日志桥接处理器：handler.go
- 错误类型：errors.go
- 使用指南与示例：RECOVERY_GUIDE.md、recovery_example_test.go

```mermaid
graph TB
subgraph "OTel 模块"
CFG["配置(Config)"]
MGR["管理器(Manager)"]
REC["恢复管理器(ConnRecoveryManager)"]
HND["日志处理器(LogHandler)"]
ERR["错误类型(Errors)"]
end
CFG --> MGR
MGR --> REC
MGR --> HND
MGR --> ERR
```

图表来源
- [config.go](file://utility/otel/config.go#L1-L86)
- [manager.go](file://utility/otel/manager.go#L1-L309)
- [recovery.go](file://utility/otel/recovery.go#L1-L162)
- [handler.go](file://utility/otel/handler.go#L1-L165)
- [errors.go](file://utility/otel/errors.go#L1-L25)

章节来源
- [config.go](file://utility/otel/config.go#L1-L86)
- [manager.go](file://utility/otel/manager.go#L1-L309)
- [recovery.go](file://utility/otel/recovery.go#L1-L162)
- [handler.go](file://utility/otel/handler.go#L1-L165)
- [errors.go](file://utility/otel/errors.go#L1-L25)

## 核心组件
- 配置（Config）：集中管理服务名、收集器地址、压缩、头部、采样率以及重试与超时等关键参数。
- 管理器（Manager）：负责创建 TracerProvider 与 LoggerProvider，配置导出器的重试策略与超时，并提供 HealthCheck 以验证连接。
- 连接恢复管理器（ConnRecoveryManager）：后台定时健康检查，跟踪连接状态与重试次数，支持动态调整检查间隔与最大重试次数，并在连接恢复时自动重置。
- 日志处理器（LogHandler/EnhancedLogHandler）：将 GoFrame 日志桥接到 OTel 日志，携带服务名、级别、调用者、上下文等属性。
- 全局工具（utils.go）：封装 InitWithConfig、Shutdown、获取恢复管理器、全局连接状态查询等便捷接口。
- 错误类型（errors.go）：统一的错误包装，便于上层捕获与定位。

章节来源
- [config.go](file://utility/otel/config.go#L1-L86)
- [manager.go](file://utility/otel/manager.go#L1-L309)
- [recovery.go](file://utility/otel/recovery.go#L1-L162)
- [handler.go](file://utility/otel/handler.go#L1-L165)
- [utils.go](file://utility/otel/utils.go#L1-L255)
- [errors.go](file://utility/otel/errors.go#L1-L25)

## 架构总览
OTel 恢复机制由“导出器重试 + 健康检查 + 后台恢复管理器”三层协同构成：
- 导出器重试：在连接失败时按指数退避策略自动重试，避免瞬时抖动导致的持续失败。
- 健康检查：通过创建测试 Span 验证与收集器的连通性，作为恢复管理器的判断依据。
- 恢复管理器：周期性执行 HealthCheck，记录重试次数与状态；连接恢复时自动重置重试计数。

```mermaid
sequenceDiagram
participant App as "应用"
participant Utils as "全局工具(utils.go)"
participant Manager as "管理器(manager.go)"
participant Exporter as "OTLP 导出器"
participant RecMgr as "恢复管理器(recovery.go)"
App->>Utils : InitWithConfig(config)
Utils->>Manager : NewOTelManager(config)
Manager->>Exporter : 初始化并配置重试/超时
Utils->>RecMgr : NewConnRecoveryManager(manager)
Utils->>RecMgr : Start()
Note over RecMgr : 后台定时执行 HealthCheck
loop 每隔检查间隔
RecMgr->>Manager : HealthCheck(ctx)
alt 连接失败
Manager-->>RecMgr : 返回错误
RecMgr->>RecMgr : 增加重试计数/记录日志
else 连接成功
Manager-->>RecMgr : 返回nil
RecMgr->>RecMgr : 重置重试计数/记录恢复
end
end
```

图表来源
- [utils.go](file://utility/otel/utils.go#L23-L57)
- [manager.go](file://utility/otel/manager.go#L106-L214)
- [recovery.go](file://utility/otel/recovery.go#L58-L114)

章节来源
- [utils.go](file://utility/otel/utils.go#L23-L57)
- [manager.go](file://utility/otel/manager.go#L106-L214)
- [recovery.go](file://utility/otel/recovery.go#L58-L114)

## 组件详解

### 配置（Config）
- 关键字段：服务名、收集器地址、是否不安全、压缩、头部、采样率、超时、重试开关及初始/最大重试间隔与总时长。
- 默认值：Insecure=false、Compressor=gzip、SampleRate=1.0、Timeout=10s、RetryEnabled=true、RetryInitInterval=1s、RetryMaxInterval=30s、RetryMaxElapsed=5m。
- 校验与默认：ValidateAndSetDefaults 会在缺失时填充默认值，保证初始化稳定性。

章节来源
- [config.go](file://utility/otel/config.go#L1-L86)

### 管理器（Manager）
- 初始化链路追踪与日志导出器，均开启重试与超时配置，并设置批处理超时与导出超时。
- 提供 HealthCheck：创建测试 Span 并添加事件，用于验证连接可用性。
- 提供全局访问器：TracerProvider、LoggerProvider、资源信息、采样率开关等。

章节来源
- [manager.go](file://utility/otel/manager.go#L106-L214)
- [manager.go](file://utility/otel/manager.go#L233-L251)

### 连接恢复管理器（ConnRecoveryManager）
- 后台监控：默认每 30 秒检查一次，可通过 SetCheckInterval 动态调整。
- 重试控制：最大重试次数默认 5 次（对应约 6 分钟），可通过 SetMaxRetries 调整。
- 状态查询：IsConnected、GetConnectionStatus、GetLastCheckTime。
- 恢复逻辑：HealthCheck 成功则重置重试计数；失败则累计重试并输出日志；超过最大重试次数后记录错误日志。

```mermaid
flowchart TD
Start(["开始检查"]) --> Health["执行 HealthCheck"]
Health --> Ok{"连接成功?"}
Ok --> |是| Reset["重置重试计数<br/>记录恢复日志"]
Ok --> |否| Inc["增加重试计数"]
Inc --> Over{"超过最大重试次数?"}
Over --> |是| LogErr["记录超时错误日志"]
Over --> |否| Wait["等待下次检查"]
Reset --> Wait
LogErr --> Wait
Wait --> End(["结束"])
```

图表来源
- [recovery.go](file://utility/otel/recovery.go#L74-L114)

章节来源
- [recovery.go](file://utility/otel/recovery.go#L1-L162)

### 日志处理器（LogHandler/EnhancedLogHandler）
- 将 GoFrame 日志转换为 OTel 日志记录，附带服务名、级别、trace_id、调用者、前缀、堆栈（错误级别）、上下文等属性。
- 支持增强版处理器，可选择是否包含堆栈与上下文，以及注入自定义属性回调。

章节来源
- [handler.go](file://utility/otel/handler.go#L1-L165)

### 全局工具（utils.go）
- InitWithConfig：创建 Manager 并自动启动恢复管理器。
- Shutdown：先停止恢复管理器，再优雅关闭 Manager。
- GetRecoveryManager/IsConnected：提供全局访问与连接状态查询。
- Span/Log 辅助：CreateSpan、AddSpanAttribute/Event/Error/Status、LogWithContext 等。

章节来源
- [utils.go](file://utility/otel/utils.go#L23-L57)
- [utils.go](file://utility/otel/utils.go#L59-L120)
- [utils.go](file://utility/otel/utils.go#L127-L201)
- [utils.go](file://utility/otel/utils.go#L232-L244)

### 错误类型（errors.go）
- 统一包装初始化失败、导出器失败、关闭失败与未初始化等错误，便于上层处理。

章节来源
- [errors.go](file://utility/otel/errors.go#L1-L25)

## 依赖关系分析
- Manager 依赖 OpenTelemetry SDK 的 trace 与 log Provider，以及 OTLP gRPC 导出器。
- ConnRecoveryManager 依赖 Manager 的 HealthCheck 能力，形成“恢复管理器 -> 管理器”的调用关系。
- utils.go 作为门面，协调 Manager 与 ConnRecoveryManager 的生命周期。
- handler.go 依赖全局 Manager 以创建 Logger 并发送 OTel 日志。

```mermaid
classDiagram
class Config {
+string ServiceName
+string CollectorURL
+bool Insecure
+string Compressor
+map~string,string~ Headers
+float64 SampleRate
+duration Timeout
+bool RetryEnabled
+duration RetryInitInterval
+duration RetryMaxInterval
+duration RetryMaxElapsed
+Validate()
+ValidateAndSetDefaults()
+Clone()
}
class Manager {
-Config* config
-resource.Resource* resource
-trace.TracerProvider tracerProvider
-log.LoggerProvider logProvider
+initTracing()
+initLogging()
+HealthCheck(ctx) error
+Shutdown(ctx) error
+CreateTracer(name) Tracer
+CreateLogger(name) Logger
}
class ConnRecoveryManager {
-Manager* manager
-Config* config
-bool isConnected
-int maxRetries
-int currentRetries
-duration checkInterval
+Start()
+Stop()
+IsConnected() bool
+GetConnectionStatus() string
+SetCheckInterval(d)
+SetMaxRetries(n)
+ResetRetryCount()
-monitorConnection()
-checkAndRecover()
-handleConnectionFailure()
}
class LogHandler {
+Handle(ctx, in)
}
class Utils {
+InitWithConfig(cfg) error
+Shutdown(ctx) error
+GetRecoveryManager() *ConnRecoveryManager
+IsConnected() bool
}
Config --> Manager : "提供配置"
Manager --> ConnRecoveryManager : "被恢复管理器依赖"
Utils --> Manager : "创建/关闭"
Utils --> ConnRecoveryManager : "启动/停止"
Manager --> LogHandler : "创建Logger并发送日志"
```

图表来源
- [config.go](file://utility/otel/config.go#L1-L86)
- [manager.go](file://utility/otel/manager.go#L1-L309)
- [recovery.go](file://utility/otel/recovery.go#L1-L162)
- [handler.go](file://utility/otel/handler.go#L1-L165)
- [utils.go](file://utility/otel/utils.go#L1-L255)

章节来源
- [config.go](file://utility/otel/config.go#L1-L86)
- [manager.go](file://utility/otel/manager.go#L1-L309)
- [recovery.go](file://utility/otel/recovery.go#L1-L162)
- [handler.go](file://utility/otel/handler.go#L1-L165)
- [utils.go](file://utility/otel/utils.go#L1-L255)

## 性能与可靠性考量
- 导出器重试：采用指数退避（内置），初始间隔与最大间隔、总时长均可配置，避免瞬时失败导致持续重试。
- 健康检查：短超时上下文（例如 5 秒）用于快速判定，降低对主业务的影响。
- 批处理与压缩：日志导出器使用默认批处理大小与超时，压缩可降低带宽占用。
- 连接复用：gRPC 默认复用连接，减少握手开销。
- 资源与优雅关闭：Manager 维护 shutdown 回调列表，确保 Provider 有序关闭；utils.go 在 Shutdown 中先停恢复管理器，再关闭 Manager。

章节来源
- [manager.go](file://utility/otel/manager.go#L106-L214)
- [utils.go](file://utility/otel/utils.go#L46-L57)

## 故障排查指南
- 连续失败日志过多：增大检查间隔或初始重试间隔，减少日志噪声。
- 内存增长：检查批处理大小、采样率与是否正确调用 Shutdown。
- 网络连通性：确认收集器地址与端口、防火墙策略、TLS 配置与认证头。
- 连接超时：适当提高 Timeout 与 RetryMaxElapsed，观察恢复管理器状态输出。

章节来源
- [RECOVERY_GUIDE.md](file://utility/otel/RECOVERY_GUIDE.md#L228-L331)
- [recovery.go](file://utility/otel/recovery.go#L100-L114)

## 结论
通过导出器重试、健康检查与后台恢复管理器的协同，OTel 恢复机制能够在收集器短暂不可用或重启后自动恢复数据上报，显著提升系统的韧性与可观测性。配合合理的超时与重试配置、日志桥接与优雅关闭流程，可在不同环境下稳定运行。

## 附录

### 快速使用要点
- 初始化：使用默认配置或自定义重试策略，调用 InitWithConfig 完成初始化并启动恢复管理器。
- 监控：通过 GetRecoveryManager().GetConnectionStatus() 获取连接状态与重试次数。
- 调整：根据环境需求调整检查间隔与最大重试次数。
- 关闭：调用 Shutdown 优雅停止恢复管理器与 OTel Provider。

章节来源
- [RECOVERY_GUIDE.md](file://utility/otel/RECOVERY_GUIDE.md#L83-L161)
- [utils.go](file://utility/otel/utils.go#L23-L57)

### 示例参考
- 连接恢复测试：演示恢复管理器行为与状态查询。
- 健康检查测试：验证 HealthCheck 的返回结果。
- 配置校验与默认值：验证 ValidateAndSetDefaults 的行为。
- 自定义重试配置：展示如何覆盖默认重试参数。

章节来源
- [recovery_example_test.go](file://utility/otel/recovery_example_test.go#L1-L205)