OpenTelemetry 故障排查
本文档提供 OpenTelemetry 接入和使用过程中常见问题的排查方法和解决方案。
通用排查步骤
1. 检查环境变量
# 检查所有 OpenTelemetry 环境变量env | grep OTEL_# 检查关键配置echo $OTEL_SERVICE_NAMEecho $OTEL_EXPORTER_OTLP_ENDPOINTecho $OTEL_EXPORTER_OTLP_HEADERS
2. 启用调试日志
# 启用详细日志export OTEL_LOG_LEVEL=debug
3. 使用 Console Exporter
临时使用 Console Exporter 验证数据生成:
export OTEL_TRACES_EXPORTER=consoleexport OTEL_METRICS_EXPORTER=consoleexport OTEL_LOGS_EXPORTER=console
4. 检查网络连接
# 测试 endpoint 连接curl -v uptrace-grpc.yodao.cn:4317# 测试 gRPC 连接grpcurl -plaintext api.uptrace.dev:4317 list
常见问题
问题 1: 数据未发送到后端
症状: APM 平台看不到任何数据
排查步骤:
- 检查环境变量配置:
echo $OTEL_SERVICE_NAMEecho $OTEL_EXPORTER_OTLP_ENDPOINTecho $OTEL_EXPORTER_OTLP_HEADERS
- 检查网络连接:
curl -v $OTEL_EXPORTER_OTLP_ENDPOINT
- 启用调试日志:
export OTEL_LOG_LEVEL=debug
- 使用 Console Exporter 验证:
export OTEL_TRACES_EXPORTER=console# 运行应用,查看控制台输出
- 检查采样率:
# 临时设置为 100% 采样export OTEL_TRACES_SAMPLER_ARG=1.0
解决方案:
- 确认 endpoint 地址正确
- 确认 headers 包含正确的认证信息
- 检查防火墙规则
- 验证 DSN 是否有效
问题 2: Span 未关联
症状: Trace 中的 Span 没有父子关系,显示为独立的 Trace
原因: Context 传递不正确
解决方案:
Go:
// ✅ 正确:传递 contextfunc ParentFunction(ctx context.Context) {ctx, span := tracer.Start(ctx, "parent")defer span.End()ChildFunction(ctx) // 传递 ctx}func ChildFunction(ctx context.Context) {ctx, span := tracer.Start(ctx, "child") // 使用传入的 ctxdefer span.End()}
Python:
# ✅ 正确:传递 contextdef parent_function():with tracer.start_as_current_span("parent") as span:child_function() # context 自动传播def child_function():with tracer.start_as_current_span("child") as span:pass
Java:
// ✅ 正确:使用 try-with-resourcestry (Scope scope = parentSpan.makeCurrent()) {Span childSpan = tracer.spanBuilder("child").startSpan();// ...}
问题 3: 内存泄漏
症状: 内存使用持续增长
可能原因:
- 没有调用
span.End() - 队列积压
- 资源未释放
解决方案:
- 确保 Span 正确结束:
// ✅ 正确:使用 deferfunc Operation(ctx context.Context) {ctx, span := tracer.Start(ctx, "operation")defer span.End() // 确保总是调用// 业务逻辑}
- 调整队列大小:
export OTEL_BSP_MAX_QUEUE_SIZE=1024export OTEL_BSP_SCHEDULE_DELAY=2000
- 检查资源释放:
defer func() {if err := tp.Shutdown(ctx); err != nil {log.Printf("Error shutting down: %v", err)}}()
问题 4: 高 CPU 使用率
症状: CPU 使用率异常高
可能原因:
- 采样率过高
- 同步导出
- 属性处理过多
解决方案:
- 降低采样率:
export OTEL_TRACES_SAMPLER_ARG=0.01 # 1%
- 确保异步导出:
// ✅ 正确:使用 BatchSpanProcessorsdktrace.WithBatcher(exporter)// ❌ 错误:使用 SimpleSpanProcessorsdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(exporter))
- 限制属性数量:
export OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=64
问题 5: 网络带宽过高
症状: 网络流量异常高
可能原因:
- 采样率过高
- 未启用压缩
- 属性值过大
解决方案:
- 降低采样率:
export OTEL_TRACES_SAMPLER_ARG=0.01
- 启用压缩:
export OTEL_EXPORTER_OTLP_COMPRESSION=gzip
- 限制属性值长度:
export OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT=512
问题 6: 框架未自动埋点
症状: 某些框架的调用没有被追踪
可能原因:
- 框架版本不支持
- 埋点库未启用
- 配置不正确
解决方案:
检查框架支持:
- 查看 OpenTelemetry 文档
- 检查框架版本要求
启用埋点库:
# Goexport OTEL_INSTRUMENTATION_GIN_ENABLED=true# Pythonpip install opentelemetry-instrumentation-gin# Java# 确保 Java Agent 包含相应的 instrumentation
- 检查配置:
# 查看启用的埋点库env | grep OTEL_INSTRUMENTATION
问题 7: 认证失败
症状: 收到认证错误
错误信息:
authentication failed: invalid DSN
解决方案:
- 检查 DSN 格式:
echo $OTEL_EXPORTER_OTLP_HEADERS# 应该包含: uptrace-dsn=http://token@uptrace-grpc.yodao.cn/project
验证 Token 有效性:
- 联系管理员确认 Token 是否有效
- 检查 Token 是否过期
检查 Headers 格式:
# ✅ 正确格式export OTEL_EXPORTER_OTLP_HEADERS=uptrace-dsn=http://token@uptrace-grpc.yodao.cn/project# ❌ 错误格式export OTEL_EXPORTER_OTLP_HEADERS=api-key=token
问题 8: 连接超时
症状: 连接后端超时
错误信息:
failed to connect: connection timeout
解决方案:
- 检查网络连接:
curl -v uptrace-grpc.yodao.cn:4317ping api.uptrace.dev
- 增加超时时间:
export OTEL_EXPORTER_OTLP_TIMEOUT=30000 # 30 秒
- 检查防火墙规则:
- 确保允许访问 endpoint
- 检查端口是否开放(gRPC: 4317, HTTP: 4318)
问题 9: 采样率过低
症状: 看不到足够的 Trace 数据
解决方案:
- 临时提高采样率:
export OTEL_TRACES_SAMPLER_ARG=1.0 # 100%
- 检查采样器配置:
echo $OTEL_TRACES_SAMPLERecho $OTEL_TRACES_SAMPLER_ARG
- 使用智能采样:
- 关键路径 100% 采样
- 普通路径 10% 采样
问题 10: 数据延迟
症状: 数据在 APM 平台延迟显示
可能原因:
- 批量导出延迟
- 网络延迟
- 后端处理延迟
解决方案:
- 减少批量延迟:
export OTEL_BSP_SCHEDULE_DELAY=2000 # 2 秒
- 检查网络延迟:
ping api.uptrace.dev
- 使用同步导出(仅用于调试):
// 仅用于调试,生产环境不推荐sdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(exporter))
语言特定问题
Go
问题: Context 传递错误
// ❌ 错误func ChildFunction() {ctx := context.Background() // 创建新的 contextctx, span := tracer.Start(ctx, "child")defer span.End()}// ✅ 正确func ChildFunction(ctx context.Context) {ctx, span := tracer.Start(ctx, "child") // 使用传入的 contextdefer span.End()}
问题: Goroutine 中丢失 Context
// ❌ 错误go func() {ctx, span := tracer.Start(context.Background(), "async")defer span.End()}()// ✅ 正确go func(ctx context.Context) {ctx, span := tracer.Start(ctx, "async")defer span.End()}(ctx)
Python
问题: 异步函数中 Context 丢失
# ❌ 错误async def async_function():with tracer.start_as_current_span("async") as span:await asyncio.sleep(1)# ✅ 正确:使用 contextvarsimport contextvarsctx_var = contextvars.ContextVar('trace_context')async def async_function():context = ctx_var.get()with tracer.start_as_current_span("async", context=context) as span:await asyncio.sleep(1)
Java
问题: Span 未正确结束
// ❌ 错误Span span = tracer.spanBuilder("operation").startSpan();// 忘记调用 span.end()// ✅ 正确:使用 try-with-resourcestry (Scope scope = span.makeCurrent()) {// 业务逻辑} finally {span.end();}
JavaScript
问题: Promise 中 Context 丢失
// ❌ 错误function asyncFunction() {const span = tracer.startSpan('async');return fetch('/api/data').then(data => {span.end();return data;});}// ✅ 正确:使用 AsyncLocalStorageconst { AsyncLocalStorage } = require('async_hooks');const asyncLocalStorage = new AsyncLocalStorage();function asyncFunction() {return asyncLocalStorage.run(trace.setSpan(context.active(), span), () => {return fetch('/api/data');});}
.NET
问题: Activity 未正确结束
// ❌ 错误var activity = ActivitySource.StartActivity("operation");// 忘记调用 activity?.Dispose()// ✅ 正确:使用 usingusing var activity = ActivitySource.StartActivity("operation");// 业务逻辑
调试工具
1. Console Exporter
export OTEL_TRACES_EXPORTER=consoleexport OTEL_METRICS_EXPORTER=consoleexport OTEL_LOGS_EXPORTER=console
2. 启用详细日志
export OTEL_LOG_LEVEL=debug
3. 使用 pprof (Go)
import _ "net/http/pprof"go func() {log.Println(http.ListenAndServe("localhost:6060", nil))}()
访问 http://localhost:6060/debug/pprof/ 查看性能数据。
4. 健康检查端点
创建健康检查端点验证 OpenTelemetry 状态:
func healthCheck(w http.ResponseWriter, r *http.Request) {// 检查 OpenTelemetry 状态tp := otel.GetTracerProvider()if tp == nil {http.Error(w, "TracerProvider not initialized", 500)return}w.WriteHeader(200)w.Write([]byte("OK"))}
获取帮助
如果以上方法都无法解决问题,可以:
- 查看日志: 启用调试日志查看详细信息
- 检查文档: 查看 OpenTelemetry 官方文档
- 社区支持:
- GitHub Issues
- OpenTelemetry Slack
- Stack Overflow