必须显式配置tracerprovider和otlp exporter并调用flaskinstrumentor().instrument_app(app),否则flask不会上报trace数据;span名称默认为"http get",需通过span_name_callback自定义以反映真实路由。

Flask 应用启动时如何自动注入 OpenTelemetry SDK
不手动初始化 TracerProvider 和 exporter,Flask 就不会上报 trace 数据——这是最常被忽略的前提。OpenTelemetry Python SDK 不会自动 hook Flask,必须显式配置并注册全局 tracer provider。
推荐在应用创建后、路由注册前完成初始化,避免部分请求(如健康检查或静态资源)漏采样:
- 调用
trace.set_tracer_provider(TracerProvider())设置全局 provider - 用
BatchSpanProcessor包裹 exporter(如OTLPSpanExporter或ConsoleSpanExporter),再 add 到 provider - 最后调用
FlaskInstrumentor().instrument_app(app),不是.instrument()(后者会 patch 全局 Flask 类,可能干扰多 app 场景)
from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter from opentelemetry.instrumentation.flask import FlaskInstrumentor <p>app = Flask(<strong>name</strong>)</p><h1>必须先设置 provider</h1><p>trace.set_tracer_provider(TracerProvider()) trace.get_tracer_provider().add_span_processor( BatchSpanProcessor(ConsoleSpanExporter()) )</p><h1>再 instrument 当前 app 实例</h1><p>FlaskInstrumentor().instrument_app(app) </p>
为什么 Flask 的 request context 里拿不到 span?
因为默认情况下,FlaskInstrumentor 只在请求进入和响应返回时创建 span,但中间的业务逻辑(比如视图函数内部、数据库操作)若没显式获取当前 span,就无法打日志或加 attribute。
关键点是:Flask 的上下文(request、g)和 OpenTelemetry 的 context 是两个体系,必须用 trace.get_current_span() 主动读取,而不是依赖 Flask 的生命周期钩子。
- 在视图函数中直接调用
trace.get_current_span()获取 active span - 用
span.set_attribute("user.id", user_id)补充业务字段,比写日志更利于聚合分析 - 避免在异步视图(
async def)中直接用同步 span API;需确保 event loop 中 context 未丢失,必要时用context.attach()
OTLP exporter 连不上 collector 怎么快速定位?
常见现象是控制台无任何输出、trace 在 Jaeger/Tempo 里完全空白,但 ConsoleSpanExporter 能打印——说明 SDK 初始化成功,问题出在网络或 collector 配置。
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
优先检查三处:
-
OTLPSpanExporter(endpoint="http://localhost:4317")中的协议必须是http://(gRPC 默认端口 4317)或https://;用http://却连 gRPC endpoint 会静默失败 - collector 是否真正监听该地址:运行
curl -v http://localhost:4317应返回 404(而非 connection refused) - Flask 进程是否与 collector 在同一网络命名空间(Docker Compose 中要确认 service link 和 network mode)
临时启用 debug 日志:logging.basicConfig(level=logging.DEBUG),SDK 会在连接失败时输出 Failed to export spans 及底层异常。
如何让 span 名称反映真实路由而非固定为 "HTTP GET"
默认 FlaskInstrumentor 生成的 span name 是 HTTP GET,丢失了路径信息,导致无法区分 /api/users 和 /api/orders。
解决方案是自定义 span_name_callback 函数,并传给 instrument_app:
def custom_span_name(environ):
return f"HTTP {environ.get('REQUEST_METHOD', 'GET')} {environ.get('PATH_INFO', '/')}"
<p>FlaskInstrumentor().instrument_app(
app,
span_name_callback=custom_span_name
)
</p>
注意:该回调接收 WSGI environ 字典,不是 Flask 的 request 对象;不要在里面调用 request.path,否则会因 context 未激活而报 RuntimeError: Working outside of application context。
Flask 的请求生命周期和 OpenTelemetry context propagation 是松耦合的,很多问题其实卡在“以为自动生效”上——比如没设 provider、没 instrument_app、或在错误时机读 span。真正稳定的可观测性,靠的是每一步都显式确认状态,而不是依赖框架隐式行为。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










