OpenTelemetry PHP 服务可观测性最佳实践¶
前言¶
本文介绍如何基于 GuanceCloud/opentelemetry-php-instrumentation 将 PHP 服务接入观测云,并补齐日志、PHP-FPM 指标和 Profiling,形成一套可直接落地的可观测方案。
这套方案适合 PHP-FPM、CLI Worker、Supervisor、容器内 PHP 进程等常见部署方式。链路数据优先通过 DataKit 4317 端口以 OTLP gRPC 方式上报;联调排障阶段可临时改用 9529/otel 的 HTTP OTLP 方式快速确认链路是否打通。
环境信息¶
- 系统环境:Linux
- 开发语言:PHP 8.2
- 部署方式:PHP-FPM / CLI
- APM 扩展:
GuanceCloud/opentelemetry-php-instrumentation 1.3.1-gtrace - 采集器:DataKit
实现目标¶
- 应用链路接入
- 应用日志接入
- PHP-FPM 指标接入
- Profiling 接入(可选)
接入方案¶
基于 GuanceCloud Fork 的说明¶
本文接入方式基于 GuanceCloud/opentelemetry-php-instrumentation,它是从 OpenTelemetry 官方仓库 fork 出来的扩展仓库。
这里有两个必须写清楚的边界:
- 扩展来源可以使用
GuanceCloudfork 的 release 资产 composer require安装的open-telemetry/sdk、open-telemetry/exporter-otlp、open-telemetry/opentelemetry-auto-*仍然是官方 PHP 包
也就是说,当前 fork 的改动主要在 PHP 扩展层,不等于整套 PHP SDK、exporter 和 auto instrumentation 生态都已经 fork。
组件清单¶
落地 OpenTelemetry PHP,至少需要以下组件:
- DataKit:负责接收链路、日志、指标、Profile 数据
- PHP
opentelemetry扩展:负责自动装配能力 - OpenTelemetry PHP SDK:负责数据构造与导出
- OTLP Exporter:负责通过
gRPC或HTTP上报到 DataKit - 对应框架或组件的 instrumentation library:负责 Laravel、Slim、Symfony、PDO、Guzzle 等自动埋点
其中,只有安装 opentelemetry 扩展还不够,项目内还必须安装 SDK + exporter + 对应自动装配包,否则即使扩展加载成功,也无法形成完整链路数据。
准备工作¶
安装 DataKit¶
主机需先安装 DataKit,并保证本机可以访问 127.0.0.1:4317 或 127.0.0.1:9529。
开启 OpenTelemetry 采集器¶
进入 DataKit 安装目录,复制 sample 配置并重启 DataKit:
mkdir -p /usr/local/datakit/conf.d/opentelemetry
cp /usr/local/datakit/conf.d/samples/opentelemetry.conf.sample \
/usr/local/datakit/conf.d/opentelemetry/opentelemetry.conf
systemctl restart datakit
检查 DataKit 是否正常:
Warning
如果应用发送到 http://127.0.0.1:9529/otel/v1/traces 返回 404,通常不是 PHP 侧问题,而是 DataKit 的 opentelemetry 输入没有真正启用。优先检查 opentelemetry.conf 是否存在并已随 DataKit 重启生效。
链路接入¶
1. 安装并启用 OTEL 扩展¶
按照 OpenTelemetry 官方 zero-code 文档,最简路径应优先选“系统包”或“镜像安装”,而不是一开始就走编译。
推荐顺序如下:
- Linux 包管理器安装
- Docker 镜像安装
- 宿主机已具备
pecl时再走pecl - 最后才考虑源码编译
Warning
不要默认假设 Linux 主机一定有 pecl。例如本文验证使用的主机在 2026-07-30 的实际状态就是“phpize 存在,但 pecl 不存在”。
另外还要注意:yum install php-pecl-opentelemetry 或 pecl install opentelemetry 安装到的通常是官方 upstream 扩展,不是 GuanceCloud fork 的 gtrace 版本。如果你的目标是验证或交付 1.3.1-gtrace,安装来源必须改为 GuanceCloud fork 的 release 资产或你们内部构建产物。
如果你的发行版有现成包,优先直接安装。
CentOS/RHEL 类系统可参考官方推荐的 Remi 仓库方式:
yum update -y
yum install -y epel-release yum-utils
yum install -y http://rpms.remirepo.net/enterprise/remi-release-7.rpm
yum-config-manager --enable remi-php81
yum install -y php php-pecl-opentelemetry
php --ri opentelemetry
Alpine 可直接安装 APK 包:
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
apk add php php81-pecl-opentelemetry@testing
php --ri opentelemetry
Docker 官方 PHP 镜像:
如果宿主机已经具备 pecl,可以直接执行:
如果宿主机没有 pecl,则优先选择以下方式之一:
- 由平台侧直接提供匹配 PHP 版本的
opentelemetry.so - 使用系统包管理器安装
- 容器镜像内通过
install-php-extensions安装
对于 GuanceCloud fork,当前更推荐的企业落地方式是:
- Windows:直接使用 release 中已经打包好的 zip 资产
- Linux:由 CI 构建对应 PHP 小版本的
opentelemetry.so,再由运维或制品库统一分发
这样才能确保安装到的确实是 gtrace 版本,而不是官方 upstream 扩展。
Windows:
- 从
GuanceCloud/opentelemetry-php-instrumentationRelease 页面下载与当前 PHP 小版本、ts/nts、编译器匹配的 zip 包 - 将
php_opentelemetry.dll放入 PHPext/目录 - 在
php.ini中启用扩展
无论使用哪种方式,选择扩展包时都需要严格匹配以下条件:
- PHP 小版本,例如
8.1/8.2/8.3/8.4 ts/nts- 平台与编译器
- 目标运行方式对应的 PHP 二进制
在 php.ini 中启用扩展:
确认扩展已加载:
2. 安装 SDK 和自动装配依赖¶
官方文档的关键点是:仅安装扩展本身不会产生 trace。项目内还必须安装 SDK + exporter + instrumentation libraries。
以 Slim + PSR-18 为例,最小依赖如下:
composer config allow-plugins.php-http/discovery false
composer require \
open-telemetry/sdk \
open-telemetry/exporter-otlp \
php-http/guzzle7-adapter \
nyholm/psr7
如果你的应用不是 Slim,而是其他框架或组件,请按实际技术栈安装对应自动装配包。常见示例如下:
# PSR-18 HTTP Client
composer require open-telemetry/opentelemetry-auto-psr18
# Slim
composer require open-telemetry/opentelemetry-auto-slim
# Laravel
composer require open-telemetry/opentelemetry-auto-laravel
# Symfony
composer require open-telemetry/opentelemetry-auto-symfony
# PDO
composer require open-telemetry/opentelemetry-auto-pdo
# Guzzle
composer require open-telemetry/opentelemetry-auto-guzzle
最小原则是:
- 有扩展
- 有
sdk - 有
exporter-otlp - 有与你当前框架和中间件匹配的
auto-*包
否则只能得到不完整甚至空的链路数据。
3. 配置链路上报参数¶
推荐使用 OTLP gRPC 直连本机 DataKit 4317:
OTEL_PHP_AUTOLOAD_ENABLED=true \
OTEL_SERVICE_NAME=my-php-service \
OTEL_SERVICE_VERSION=1.3.1-gtrace \
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=prod \
OTEL_TRACES_EXPORTER=otlp \
OTEL_METRICS_EXPORTER=none \
OTEL_LOGS_EXPORTER=none \
OTEL_EXPORTER_OTLP_PROTOCOL=grpc \
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317 \
OTEL_PROPAGATORS=baggage,tracecontext
排障时可切换为 HTTP OTLP:
如果你使用 PHP-FPM、Apache、Supervisor、systemd 或容器启动 PHP,请把上述环境变量配置到进程启动环境中,而不是只写在当前 shell 会话里。
推荐最小配置如下:
OTEL_PHP_AUTOLOAD_ENABLED=true
OTEL_SERVICE_NAME=my-php-service
OTEL_SERVICE_VERSION=1.3.1-gtrace
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=none
OTEL_LOGS_EXPORTER=none
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317
如需区分环境,补充:
4. 补充业务埋点¶
框架自动装配只能覆盖通用入口。对于下单、支付、外部接口调用、批处理等关键业务节点,建议使用 WithSpan 补充埋点:
<?php
declare(strict_types=1);
use OpenTelemetry\API\Instrumentation\SpanAttribute;
use OpenTelemetry\API\Instrumentation\WithSpan;
#[WithSpan('order.submit')]
function submitOrder(#[SpanAttribute] string $orderNo): void
{
// 业务逻辑
}
日志接入¶
推荐应用输出 JSON 日志,并显式写入 service、env、version。如果需要日志与链路联动,可把当前 trace_id 和 span_id 一并输出:
use OpenTelemetry\API\Trace\Span;
$context = Span::getCurrent()->getContext();
$traceId = $context->isValid() ? $context->getTraceId() : '';
$spanId = $context->isValid() ? $context->getSpanId() : '';
DataKit 侧开启 logging 采集器,示例配置如下:
[[inputs.logging]]
logfiles = ["/var/log/php-app/*.log"]
source = "php"
service = "my-php-service"
pipeline = "php-json.p"
建议日志字段至少包含:
messagestatusserviceenvversiontrace_idspan_id
PHP-FPM 指标接入¶
如果应用通过 PHP-FPM 运行,建议同时开启 phpfpm 采集器。
- 在
www.conf中开启状态页:
-
通过 Nginx 或 Apache 暴露
/status。 -
DataKit 启用
phpfpm采集器:
这样可以同步观测:
- 活跃进程数
- 空闲进程数
- 连接队列长度
- 慢请求数量
- 单进程请求耗时与内存消耗
Profiling 接入(可选)¶
如果除了链路之外,还需要定位 CPU、内存分配和热点函数问题,可单独开启 PHP Profiling。
当前更稳妥的做法是:
- DataKit 开启
profile采集器 - PHP 安装
dd-trace-php并启用 profiling - 为 PHP 进程配置如下环境变量:
DD_PROFILING_ENABLED=true
DD_SERVICE=my-php-service
DD_ENV=prod
DD_VERSION=1.3.1-gtrace
DD_AGENT_HOST=127.0.0.1
DD_TRACE_AGENT_PORT=9529
Profiling 是链路的补充能力,建议按需开启,不必在所有服务上默认全开。
最小接入顺序¶
如果你的目标是先把链路跑通,再逐步补齐其它观测数据,建议按下面顺序接入:
- 开启 DataKit
opentelemetry输入 - 安装并启用 PHP
opentelemetry扩展 - 安装项目内
sdk + exporter-otlp + 对应 auto-*依赖 - 配置
OTEL_*进程环境变量 - 发起一次真实请求,确认链路已进入观测云
- 再补日志采集、PHP-FPM 指标和 Profiling
这样可以把链路联调步骤压缩到最短,避免一开始同时处理太多组件。
当前 Fork 的不足¶
如果完全对齐 OpenTelemetry 官方 zero-code 体验,当前 GuanceCloud fork 还有几处明显缺口:
- 没有现成的 Linux 预编译二进制资产,Linux 侧安装路径还不够短
- 没有独立可识别的包分发渠道,
pecl install opentelemetry会落到 upstream,而不是gtrace - release 资产与官方文档的“系统包安装”路径没有完全打通,文档不能直接照抄官方安装命令
- 需要单独说明“扩展来自 fork,但 SDK 和 auto instrumentation 依赖仍来自官方 Composer 包”
如果后续要继续优化接入体验,优先级建议如下:
- 为 Linux 增加常用 PHP 小版本的预编译扩展资产
- 提供一份安装脚本,自动识别 PHP 版本、
ts/nts和扩展目录 - 在 release 页面固定给出“适用于哪种 PHP 版本/运行模式”的资产说明
- 在 fork README 中明确区分“upstream 安装路径”和“GuanceCloud gtrace 安装路径”
实践效果¶
完成以上接入后,通常可以得到以下观测能力:
- 在应用性能监测中查看 PHP 服务入口请求、数据库调用、下游 HTTP 调用等链路信息
- 在日志中按照
service/env/version过滤,并基于trace_id回溯同一请求 - 在基础设施或自定义视图中观察 PHP-FPM 的活跃进程、排队、慢请求等运行状态
- 在 Profiling 视图中定位 CPU 热点、内存分配热点和慢函数
最佳实践建议¶
- 统一资源属性:至少固定
service.name、service.version、deployment.environment - 统一发布命名:扩展版本、应用版本、发布标签尽量保持一致,方便版本回溯
- 优先使用
4317/gRPC:生产环境优先走OTLP gRPC,9529/otel更适合联调和排障 - 优先使用现成安装方式:优先镜像预装、已构建制品分发或具备
pecl条件下的PECL安装,不把源码编译作为主推荐路径 - 用进程级环境变量:不要只在登录 shell 中设置
OTEL_*,要写进php-fpm、systemd、容器或启动脚本 - 控制属性基数:不要把手机号、订单号全集、原始 SQL、超长 URL 全量写入 span attribute
- 关键业务手工补点:自动装配覆盖不到的业务节点,用
WithSpan精准补齐 - 日志保留链路字段:统一输出
trace_id/span_id,否则日志和链路无法稳定联动 - 先检查 DataKit 输入:链路打不通时,优先确认
opentelemetry、logging、phpfpm、profile采集器是否已启用