OpenTelemetry 故障排查

本文档提供 OpenTelemetry 接入和使用过程中常见问题的排查方法和解决方案。

通用排查步骤

1. 检查环境变量

# 检查所有 OpenTelemetry 环境变量
env | grep OTEL_
# 检查关键配置
echo $OTEL_SERVICE_NAME
echo $OTEL_EXPORTER_OTLP_ENDPOINT
echo $OTEL_EXPORTER_OTLP_HEADERS

2. 启用调试日志

# 启用详细日志
export OTEL_LOG_LEVEL=debug

3. 使用 Console Exporter

临时使用 Console Exporter 验证数据生成:

export OTEL_TRACES_EXPORTER=console
export OTEL_METRICS_EXPORTER=console
export OTEL_LOGS_EXPORTER=console

4. 检查网络连接

# 测试 endpoint 连接
curl -v uptrace-grpc.yodao.cn:4317
# 测试 gRPC 连接
grpcurl -plaintext api.uptrace.dev:4317 list

常见问题

问题 1: 数据未发送到后端

症状: APM 平台看不到任何数据

排查步骤:

  1. 检查环境变量配置:
echo $OTEL_SERVICE_NAME
echo $OTEL_EXPORTER_OTLP_ENDPOINT
echo $OTEL_EXPORTER_OTLP_HEADERS
  1. 检查网络连接:
curl -v $OTEL_EXPORTER_OTLP_ENDPOINT
  1. 启用调试日志:
export OTEL_LOG_LEVEL=debug
  1. 使用 Console Exporter 验证:
export OTEL_TRACES_EXPORTER=console
# 运行应用,查看控制台输出
  1. 检查采样率:
# 临时设置为 100% 采样
export OTEL_TRACES_SAMPLER_ARG=1.0

解决方案:

  • 确认 endpoint 地址正确
  • 确认 headers 包含正确的认证信息
  • 检查防火墙规则
  • 验证 DSN 是否有效

问题 2: Span 未关联

症状: Trace 中的 Span 没有父子关系,显示为独立的 Trace

原因: Context 传递不正确

解决方案:

Go:

// ✅ 正确:传递 context
func 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") // 使用传入的 ctx
defer span.End()
}

Python:

# ✅ 正确:传递 context
def 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-resources
try (Scope scope = parentSpan.makeCurrent()) {
Span childSpan = tracer.spanBuilder("child")
.startSpan();
// ...
}

问题 3: 内存泄漏

症状: 内存使用持续增长

可能原因:

  • 没有调用 span.End()
  • 队列积压
  • 资源未释放

解决方案:

  1. 确保 Span 正确结束:
// ✅ 正确:使用 defer
func Operation(ctx context.Context) {
ctx, span := tracer.Start(ctx, "operation")
defer span.End() // 确保总是调用
// 业务逻辑
}
  1. 调整队列大小:
export OTEL_BSP_MAX_QUEUE_SIZE=1024
export OTEL_BSP_SCHEDULE_DELAY=2000
  1. 检查资源释放:
defer func() {
if err := tp.Shutdown(ctx); err != nil {
log.Printf("Error shutting down: %v", err)
}
}()

问题 4: 高 CPU 使用率

症状: CPU 使用率异常高

可能原因:

  • 采样率过高
  • 同步导出
  • 属性处理过多

解决方案:

  1. 降低采样率:
export OTEL_TRACES_SAMPLER_ARG=0.01 # 1%
  1. 确保异步导出:
// ✅ 正确:使用 BatchSpanProcessor
sdktrace.WithBatcher(exporter)
// ❌ 错误:使用 SimpleSpanProcessor
sdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(exporter))
  1. 限制属性数量:
export OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=64

问题 5: 网络带宽过高

症状: 网络流量异常高

可能原因:

  • 采样率过高
  • 未启用压缩
  • 属性值过大

解决方案:

  1. 降低采样率:
export OTEL_TRACES_SAMPLER_ARG=0.01
  1. 启用压缩:
export OTEL_EXPORTER_OTLP_COMPRESSION=gzip
  1. 限制属性值长度:
export OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT=512

问题 6: 框架未自动埋点

症状: 某些框架的调用没有被追踪

可能原因:

  • 框架版本不支持
  • 埋点库未启用
  • 配置不正确

解决方案:

  1. 检查框架支持:

    • 查看 OpenTelemetry 文档
    • 检查框架版本要求
  2. 启用埋点库:

# Go
export OTEL_INSTRUMENTATION_GIN_ENABLED=true
# Python
pip install opentelemetry-instrumentation-gin
# Java
# 确保 Java Agent 包含相应的 instrumentation
  1. 检查配置:
# 查看启用的埋点库
env | grep OTEL_INSTRUMENTATION

问题 7: 认证失败

症状: 收到认证错误

错误信息:

authentication failed: invalid DSN

解决方案:

  1. 检查 DSN 格式:
echo $OTEL_EXPORTER_OTLP_HEADERS
# 应该包含: uptrace-dsn=http://token@uptrace-grpc.yodao.cn/project
  1. 验证 Token 有效性:

    • 联系管理员确认 Token 是否有效
    • 检查 Token 是否过期
  2. 检查 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

解决方案:

  1. 检查网络连接:
curl -v uptrace-grpc.yodao.cn:4317
ping api.uptrace.dev
  1. 增加超时时间:
export OTEL_EXPORTER_OTLP_TIMEOUT=30000 # 30 秒
  1. 检查防火墙规则:
    • 确保允许访问 endpoint
    • 检查端口是否开放(gRPC: 4317, HTTP: 4318)

问题 9: 采样率过低

症状: 看不到足够的 Trace 数据

解决方案:

  1. 临时提高采样率:
export OTEL_TRACES_SAMPLER_ARG=1.0 # 100%
  1. 检查采样器配置:
echo $OTEL_TRACES_SAMPLER
echo $OTEL_TRACES_SAMPLER_ARG
  1. 使用智能采样:
    • 关键路径 100% 采样
    • 普通路径 10% 采样

问题 10: 数据延迟

症状: 数据在 APM 平台延迟显示

可能原因:

  • 批量导出延迟
  • 网络延迟
  • 后端处理延迟

解决方案:

  1. 减少批量延迟:
export OTEL_BSP_SCHEDULE_DELAY=2000 # 2 秒
  1. 检查网络延迟:
ping api.uptrace.dev
  1. 使用同步导出(仅用于调试):
// 仅用于调试,生产环境不推荐
sdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(exporter))

语言特定问题

Go

问题: Context 传递错误

// ❌ 错误
func ChildFunction() {
ctx := context.Background() // 创建新的 context
ctx, span := tracer.Start(ctx, "child")
defer span.End()
}
// ✅ 正确
func ChildFunction(ctx context.Context) {
ctx, span := tracer.Start(ctx, "child") // 使用传入的 context
defer 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)
# ✅ 正确:使用 contextvars
import contextvars
ctx_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-resources
try (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;
});
}
// ✅ 正确:使用 AsyncLocalStorage
const { 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()
// ✅ 正确:使用 using
using var activity = ActivitySource.StartActivity("operation");
// 业务逻辑

调试工具

1. Console Exporter

export OTEL_TRACES_EXPORTER=console
export OTEL_METRICS_EXPORTER=console
export 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"))
}

获取帮助

如果以上方法都无法解决问题,可以:

  1. 查看日志: 启用调试日志查看详细信息
  2. 检查文档: 查看 OpenTelemetry 官方文档
  3. 社区支持:
    • GitHub Issues
    • OpenTelemetry Slack
    • Stack Overflow

下一步

参考资源

在Gitlab上编辑本文档