PHP用OpenTelemetry抓不到span,首要检查opentelemetry.so是否通过php.ini显式加载且自动插件已生效;其次确保context正确传递、手动span需设parent并显式end;最后调优exporter的batch size与timeout参数。

PHP 用 OpenTelemetry 抓不到 span?先检查自动注入是否生效
OpenTelemetry PHP 的自动插件(auto-instrumentation)依赖 opentelemetry-auto-instrumentation 扩展 + 启动时加载,不是装完扩展就自动埋点。常见现象是 OTEL_SERVICE_NAME 设了、SDK 初始化了,但 Jaeger/Zipkin 里完全没数据——大概率是自动插件根本没加载。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 确认扩展已启用:
php -m | grep opentelemetry必须输出opentelemetry - 检查
opentelemetry.so是否在php.ini中通过extension=opentelemetry.so显式加载(不能只靠dl()或运行时加载) - 启动 PHP-FPM 或 CLI 时,必须带上环境变量:
OTEL_SERVICE_NAME=my-app OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 php index.php;Web 环境需在 FPM pool 配置中用env[OTEL_SERVICE_NAME]透传 - 自动插件默认只覆盖
curl、PDO、mysqli、Redis等有限扩展;Laravel/ThinkPHP 的路由、中间件、DB 查询等链路,得靠手动加Tracer::spanBuilder()补全
手动创建 span 时 context 丢失?别直接 new SpanBuilder
PHP 的 OpenTelemetry SDK 不支持无上下文的 span 创建。直接写 $span = $tracer->spanBuilder('api.login')->startSpan() 得到的是孤立 span,不会被父 span(比如入口 HTTP 请求 span)关联,调用链就断了。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 必须从当前 context 拿 active span:
$parent = $context->getValue(TraceContext::KEY),再用$tracer->spanBuilder('xxx')->setParent($parent)->startSpan() - 更稳妥的做法是用
trace\propagation\extract()从 HTTP header(如traceparent)中还原 context,尤其跨服务调用时 - 注意
Span::end()必须显式调用,PHP 的析构函数不保证及时触发,漏掉会导致 span 不上报 - 避免在异步回调(如
pcntl_fork子进程、Swoole 定时器)里复用主线程 context,子上下文需独立Context::createEmpty()并手动注入
HTTP 调用链断在 curl_exec?看 CURLOPT_HEADERFUNCTION 和 traceparent 注入时机
自动插件能拦截 curl_exec,但前提是 curl handle 没被提前修改过 header 行为。常见断链原因是:业务代码设置了 CURLOPT_HEADERFUNCTION 或 CURLOPT_WRITEFUNCTION,导致 OpenTelemetry 插件无法在请求发出前注入 traceparent header。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 不要覆盖
CURLOPT_HEADERFUNCTION;如需读 header,改用CURLOPT_HEADER+CURLOPT_RETURNTRANSFER合并解析 - 手动注入 traceparent 更可靠:
curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge($headers, ['traceparent: ' . $traceHeader])),其中$traceHeader来自Propagation::toTraceparent($context) - 注意
curl_setopt_array()可能覆盖插件设置的 header,建议用单次curl_setopt()追加 - 若用 Guzzle,优先升级到 7.5+,其内置 OpenTelemetry middleware 支持自动 propagation,比原生 curl 更稳
上报延迟高或丢 span?调整 exporter batch 和 timeout
默认配置下,OpenTelemetry PHP 的 OTLP exporter 使用 512 的 batch size 和 30s timeout,小流量服务常出现“等不满一批就超时”,导致 span 积压或丢弃;大流量则可能因单次 gRPC 请求过大失败。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 调低 batch timeout:
OTEL_BSP_SCHEDULE_DELAY=1000(单位 ms),让小流量也能快速 flush - 限制单批大小:
OTEL_BSP_MAX_EXPORT_BATCH_SIZE=64,避免 gRPC payload 超限(默认 1.5MB) - 禁用压缩(如果网络不差):
OTEL_EXPORTER_OTLP_COMPRESSION=none,PHP 的 gzip 压缩开销不小 - CLI 脚本结束前务必调
ShutdownHandler::shutdown(),否则最后一批 span 几乎必丢
链路追踪不是开了就灵,context 传递、exporter 阻塞、插件覆盖盲区,三处任一出问题,整条链就断成碎片。调试时先盯死 OTEL_LOG_LEVEL=debug 输出的 span lifecycle 日志,比翻文档快得多。











