排查 Python 自动检测问题
安装问题
Python 包安装失败
Python 包的安装需要 gcc 和 gcc-c++,如果您运行的是精简版的 Linux,例如 CentOS,则可能需要安装它们。
yum -y install python3-devel
yum -y install gcc-c++
apt install -y python3-dev
apt install -y build-essential
apk add python3-dev
apk add build-base
使用 uv 进行引导
当使用 uv 包管理器时,运行 opentelemetry-bootstrap -a install 可能会导致依赖项设置出错或出现意外情况。
相反,您可以动态生成 OpenTelemetry 的依赖项,并使用 uv 进行安装。
首先,安装适当的包(或将其添加到项目文件中并运行 uv sync)
uv pip install opentelemetry-distro opentelemetry-exporter-otlp
现在,您可以安装自动检测
uv run opentelemetry-bootstrap -a requirements | uv pip install --requirement -
最后,使用 uv run 启动应用程序(请参阅 配置代理)
uv run opentelemetry-instrument python myapp.py
请注意,每次运行 uv sync 或更新现有包时,都必须重新安装自动检测。因此,建议将安装作为构建管道的一部分。
检测问题
Flask 调试模式下的重新加载器会破坏检测
可以在 Flask 应用中这样启用调试模式
if __name__ == "__main__":
app.run(port=8082, debug=True)
调试模式会通过启用重新加载器来破坏检测的进行。要运行检测而调试模式又启用,请将 use_reloader 选项设置为 False。
if __name__ == "__main__":
app.run(port=8082, debug=True, use_reloader=False)
预分叉服务器问题
像 Gunicorn 带有多个工作进程的预分叉服务器可以这样运行:
gunicorn myapp.main:app --workers 4
但是,指定超过一个 --workers 可能会破坏自动检测应用时的指标生成。这是因为分叉(创建工作进程/子进程)会在每个子进程的后台线程之间产生不一致,并会锁定一些关键的 OpenTelemetry SDK 组件。特别是,PeriodicExportingMetricReader 会生成自己的线程来定期将数据刷新到导出器。另请参阅问题 #2767 和 #3307。分叉后,每个子进程都会尝试在内存中查找一个实际上并未运行的线程对象,并且任何原始锁都可能不会为每个子进程解锁。另请参阅 Python issue 6721 中描述的分叉和死锁。
解决方法
对于带有 OpenTelemetry 的预分叉服务器,存在一些解决方法。下表总结了不同自动检测的 Web 服务器网关堆栈(带有多个工作进程且已预分叉)的当前信号导出支持情况。更多详细信息和选项请参阅下文。
| 带有多个工作进程的堆栈 | 追踪 | 指标 | 日志 |
|---|---|---|---|
| Uvicorn | x | x | |
| Gunicorn | x | x | |
| Gunicorn + UvicornWorker | x | x | x |
使用 Gunicorn 和 UvicornWorker 进行部署
要自动检测带有多个工作进程的服务器,如果它是异步服务器网关接口 (ASGI) 应用(FastAPI、Starlette 等),建议使用 uvicorn.workers.UvicornWorker 进行部署。UvicornWorker 类专为处理分叉而设计,可保留后台进程和线程。例如:
opentelemetry-instrument gunicorn \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000 \
myapp.main:app
使用编程方式自动检测
在服务器分叉后,在工作进程内使用 编程方式自动检测 进行初始化,而不是使用 opentelemetry-instrument。例如:
from opentelemetry.instrumentation.auto_instrumentation import initialize
initialize()
from your_app import app
如果使用 FastAPI,请注意,由于检测的补丁方式,initialize() 必须在导入 FastAPI 之前调用。例如:
from opentelemetry.instrumentation.auto_instrumentation import initialize
initialize()
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
然后,使用以下命令运行服务器:
uvicorn main:app --workers 2
使用 Prometheus 和直接 OTLP
考虑使用最新版本的 Prometheus 直接接收 OTLP 指标。设置一个 PeriodicExportingMetricReader 和每个进程一个 OTLP 工作进程来推送到 Prometheus 服务器。我们建议不要在分叉时使用 PrometheusMetricReader,请参阅问题 #3747。
使用单个工作进程
或者,在预分叉中使用单个工作进程进行零代码检测:
opentelemetry-instrument gunicorn your_app:app --workers 1
连接问题
gRPC 连接
要调试 Python gRPC 连接问题,请设置以下 gRPC 调试环境变量:
export GRPC_VERBOSITY=debug
export GRPC_TRACE=http,call_error,connectivity_state
opentelemetry-instrument python YOUR_APP.py