一个全面的OpenTelemetry Python采集器示例项目,展示了如何在Python应用中使用OpenTelemetry进行分布式追踪和监控。
- 🚀 完整的OpenTelemetry集成:包含API、SDK和多种导出器
- 📊 多种instrumentation示例:数据库、HTTP、Redis、日志等
- 🔍 Jaeger集成:支持将追踪数据发送到Jaeger
- 🛠️ 易于扩展:模块化设计,便于添加新的instrumentation
- 📈 生产就绪:包含最佳实践和错误处理
- Python 3.12+
- Jaeger (推荐使用Docker运行)
# 克隆项目
git clone <repository-url>
cd opentelemetry-pycollector
# 使用uv安装依赖
uv sync
# 或者使用pip
pip install -e .# 使用Docker运行Jaeger (推荐)
docker run -d --name jaeger \
-e COLLECTOR_OTLP_ENABLED=true \
-p 16686:16686 \ # Jaeger UI
-p 4317:4317 \ # OTLP gRPC (默认端口)
-p 4318:4318 \ # OTLP HTTP
jaegertracing/all-in-one:latest重要提示:
- 本项目使用 OTLP gRPC 协议,默认端口为 4317
- 确保 Jaeger 启用了 OTLP collector (
COLLECTOR_OTLP_ENABLED=true)
# 运行基本追踪示例
uv run python -m opentelemetry_pycollector.examples.basic_tracing
# 运行嵌套span示例
uv run python -m opentelemetry_pycollector.examples.nested_spans
# 运行instrumentation示例
uv run python -m opentelemetry_pycollector.examples.instrumentation_example
# 运行span attributes示例(示例四)
uv run python -m opentelemetry_pycollector.examples.span_attributes_example
# 运行嵌套span attributes示例(示例五)
uv run python -m opentelemetry_pycollector.examples.nested_span_attributes_exampleopentelemetry_pycollector/
├── src/opentelemetry_pycollector/
│ ├── config/ # 配置管理
│ ├── examples/ # 使用示例
│ │ ├── basic_tracing.py # 示例一:基础追踪
│ │ ├── nested_spans.py # 示例二:嵌套span
│ │ ├── instrumentation_example.py # 示例三:装饰器模式
│ │ ├── span_attributes_example.py # 示例四:设置span attribute
│ │ └── nested_span_attributes_example.py # 示例五:子span attribute
│ ├── instrumentation/ # 各种instrumentation实现
│ └── __init__.py
├── tests/ # 测试文件
├── pyproject.toml # 项目配置
└── README.md # 项目文档
演示如何使用 tracer.start_as_current_span() 进行基础的 span 采集。
服务名称: basic-tracing-demo
运行方式: uv run python -m opentelemetry_pycollector.examples.basic_tracing
特点:
- 基础的 span 创建和使用
- 错误处理和状态记录
- 简单的函数追踪
演示如何创建多层级的 span 结构,模拟复杂的电商业务流程。
服务名称: nested-spans-demo
运行方式: uv run python -m opentelemetry_pycollector.examples.nested_spans
追踪结构示例:
process-order (父 span)
├── validate-order (订单验证)
│ ├── check-inventory (库存检查)
│ └── validate-user (用户验证)
├── process-payment (支付处理)
│ └── payment-gateway-call (支付网关调用)
└── confirm-order (订单确认)
特点:
- 多层级嵌套 span 结构
- 模拟复杂业务流程
- 展示父子 span 关系
演示如何使用装饰器为函数自动添加 OpenTelemetry 追踪功能。
服务名称: instrumentation-example
运行方式: uv run python -m opentelemetry_pycollector.examples.instrumentation_example
核心装饰器: @instrument_function
from opentelemetry_pycollector.instrumentation import instrument_function
@instrument_function(
span_name="my_operation", # 自定义 span 名称
tracer_name="custom-tracer", # Tracer 名称
trace_id="1234...", # 共享 trace_id
record_exception=True, # 记录异常
add_attributes=True # 添加函数元数据
)
def my_function():
pass装饰器参数:
span_name: 自定义 span 名称(默认使用函数名)tracer_name: Tracer 名称,用于区分不同模块或组件trace_id: Trace ID(32字符16进制字符串),用于关联多个函数到同一 tracerecord_exception: 是否记录异常(默认 True)add_attributes: 是否添加函数元数据(默认 True)
使用场景:
- 为现有函数快速添加追踪功能
- API 端点追踪
- 业务逻辑追踪
- 性能分析和错误追踪
trace_id 使用示例:
SHARED_TRACE_ID = "1234567890abcdef1234567890abcdef"
@instrument_function(trace_id=SHARED_TRACE_ID, span_name="operation_a")
def operation_a():
pass
@instrument_function(trace_id=SHARED_TRACE_ID, span_name="operation_b")
def operation_b():
pass
# 这些函数会在同一个 trace 下演示如何在函数中直接设置 span 的 attribute,记录执行状态和上下文信息。
服务名称: span-attributes-example
运行方式: uv run python -m opentelemetry_pycollector.examples.span_attributes_example
使用示例:
with tracer.start_as_current_span("process-order") as span:
span.set_attribute("order.id", order_id)
span.set_attribute("user.id", user_id)
span.set_attribute("order.total_amount", total_amount)
span.set_attribute("payment.method", "credit_card")
span.set_attribute("order.status", "confirmed")特点:
- 在函数执行过程中动态设置 attribute
- 支持字符串、数字、布尔值、时间戳等多种类型
- 使用点号分隔的层次结构命名(如
order.id,payment.status)
适用场景:
- 单一操作追踪
- 状态记录和参数追踪
- 简单场景,操作步骤较少
演示如何在函数中创建子 span,并在每个子 span 中独立设置 attribute。
服务名称: nested-span-attributes-example
运行方式: uv run python -m opentelemetry_pycollector.examples.nested_span_attributes_example
使用示例:
with tracer.start_as_current_span("process-payment") as parent_span:
parent_span.set_attribute("order.id", order_id)
with tracer.start_as_current_span("validate-payment") as validate_span:
validate_span.set_attribute("validation.is_valid", True)
with tracer.start_as_current_span("call-gateway") as gateway_span:
gateway_span.set_attribute("gateway.name", "stripe")特点:
- 清晰的层级结构展示操作关系
- 每个 span 有独立的 attribute
- 支持多层嵌套
适用场景:
- 复杂操作追踪,包含多个独立步骤
- 性能分析,需要分析每个步骤的耗时
- 错误定位,需要精确定位问题步骤
- 使用点号分隔的层次结构:
order.id,payment.status - 保持命名风格一致
- 使用有意义的名称,便于理解
- 合理粒度: span 的粒度要适中,不要太细也不要太粗
- 职责单一: 每个 span 应该代表一个明确的操作
- 层级清晰: 保持清晰的父子关系,避免过深的嵌套
- 不要设置过多的 attribute,影响性能
- 避免设置过大的值(如大字符串、大数组)
- 在高频操作中考虑使用采样策略
- 装饰器会带来少量性能开销,在高频函数上要谨慎使用
- 合理命名 span,使用有意义的名称
- 控制追踪范围,只追踪关键路径
- 在函数内部添加自定义属性,提供更多上下文
- 确保异常被正确记录和传播
- 使用
tracer_name区分不同模块或组件 - 使用
trace_id关联相关的操作到同一 trace
| 变量名 | 默认值 | 描述 |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
http://localhost:4317 | OTLP exporter endpoint (完整 URL) |
JAEGER_URL |
localhost | Jaeger collector 地址(如果未设置 OTEL_EXPORTER_OTLP_ENDPOINT) |
OTEL_EXPORTER_OTLP_TRACES_PORT 或 JAEGER_PORT |
4317 | Jaeger collector 端口 (OTLP gRPC) |
OTEL_SERVICE_NAME |
opentelemetry-pycollector | 服务名称 |
OTEL_CONSOLE_EXPORT |
false | 是否启用控制台导出(用于调试) |
如果执行代码后在 Jaeger UI (http://localhost:16686) 中找不到对应的服务日志,请检查以下几点:
-
检查 Jaeger 是否运行
docker ps | grep jaeger # 或 curl http://localhost:16686/api/services
-
检查端口配置
- 确保 Jaeger collector 监听在 4317 端口(OTLP gRPC)
- 检查防火墙是否允许 TCP 连接
# 检查端口是否开放 netstat -an | grep 4317 # 或 lsof -i :4317
-
使用测试脚本验证连接
# 使用测试脚本发送测试数据 uv run python test_jaeger_connection.py <your-service-name> # 例如: uv run python test_jaeger_connection.py spirits-agentchat
-
启用控制台导出进行调试
from opentelemetry_pycollector.config.telemetry import setup_telemetry # 启用控制台导出,查看 spans 是否被正确创建 tracer = setup_telemetry("your-service-name", enable_console_export=True)
-
检查服务名称匹配
- 确保代码中使用的服务名称与 Jaeger UI 中搜索的名称完全一致
- 服务名称区分大小写
-
确保 spans 被刷新
- 程序结束前会自动调用
shutdown_telemetry()刷新所有 spans - 如果程序异常退出,spans 可能未被导出
- 程序结束前会自动调用
-
检查时间范围
- 在 Jaeger UI 中确保选择了正确的时间范围
- 数据可能有几秒钟的延迟才会显示
Q: 为什么使用端口 4317?
- 本项目使用 OTLP gRPC 协议,默认端口为 4317
- 这是 OpenTelemetry 的标准协议,更现代且功能更强大
- 端口 6831 是 Jaeger Thrift UDP 协议使用的端口(已弃用)
Q: 如何确认数据是否发送到 Jaeger?
- 启用控制台导出:
setup_telemetry(..., enable_console_export=True) - 查看 Jaeger agent 日志:
docker logs jaeger - 使用测试脚本:
python test_jaeger_connection.py <service-name>
uv run pytestuv run black src/
uv run isort src/uv run mypy src/欢迎提交Issue和Pull Request!
MIT License - 详见 LICENSE 文件