跳转至

OpenTelemetry PHP 服务可观测性最佳实践


前言

本文介绍如何基于 GuanceCloud/opentelemetry-php-instrumentation 将 PHP 服务接入观测云,并补齐日志、PHP-FPM 指标和 Profiling,形成一套可直接落地的可观测方案。

这套方案适合 PHP-FPMCLI WorkerSupervisor、容器内 PHP 进程等常见部署方式。链路数据优先通过 DataKit 4317 端口以 OTLP gRPC 方式上报;联调排障阶段可临时改用 9529/otelHTTP 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 出来的扩展仓库。

这里有两个必须写清楚的边界:

  • 扩展来源可以使用 GuanceCloud fork 的 release 资产
  • composer require 安装的 open-telemetry/sdkopen-telemetry/exporter-otlpopen-telemetry/opentelemetry-auto-* 仍然是官方 PHP 包

也就是说,当前 fork 的改动主要在 PHP 扩展层,不等于整套 PHP SDK、exporter 和 auto instrumentation 生态都已经 fork。

组件清单

落地 OpenTelemetry PHP,至少需要以下组件:

  • DataKit:负责接收链路、日志、指标、Profile 数据
  • PHP opentelemetry 扩展:负责自动装配能力
  • OpenTelemetry PHP SDK:负责数据构造与导出
  • OTLP Exporter:负责通过 gRPCHTTP 上报到 DataKit
  • 对应框架或组件的 instrumentation library:负责 Laravel、Slim、Symfony、PDO、Guzzle 等自动埋点

其中,只有安装 opentelemetry 扩展还不够,项目内还必须安装 SDK + exporter + 对应自动装配包,否则即使扩展加载成功,也无法形成完整链路数据。

准备工作

安装 DataKit

主机需先安装 DataKit,并保证本机可以访问 127.0.0.1:4317127.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 是否正常:

curl http://127.0.0.1:9529/v1/ping
ss -lntp | grep -E '4317|9529'
Warning

如果应用发送到 http://127.0.0.1:9529/otel/v1/traces 返回 404,通常不是 PHP 侧问题,而是 DataKit 的 opentelemetry 输入没有真正启用。优先检查 opentelemetry.conf 是否存在并已随 DataKit 重启生效。

链路接入

1. 安装并启用 OTEL 扩展

按照 OpenTelemetry 官方 zero-code 文档,最简路径应优先选“系统包”或“镜像安装”,而不是一开始就走编译。

推荐顺序如下:

  1. Linux 包管理器安装
  2. Docker 镜像安装
  3. 宿主机已具备 pecl 时再走 pecl
  4. 最后才考虑源码编译
Warning

不要默认假设 Linux 主机一定有 pecl。例如本文验证使用的主机在 2026-07-30 的实际状态就是“phpize 存在,但 pecl 不存在”。

另外还要注意:yum install php-pecl-opentelemetrypecl 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 镜像:

install-php-extensions opentelemetry

如果宿主机已经具备 pecl,可以直接执行:

pecl install opentelemetry

如果宿主机没有 pecl,则优先选择以下方式之一:

  • 由平台侧直接提供匹配 PHP 版本的 opentelemetry.so
  • 使用系统包管理器安装
  • 容器镜像内通过 install-php-extensions 安装

对于 GuanceCloud fork,当前更推荐的企业落地方式是:

  • Windows:直接使用 release 中已经打包好的 zip 资产
  • Linux:由 CI 构建对应 PHP 小版本的 opentelemetry.so,再由运维或制品库统一分发

这样才能确保安装到的确实是 gtrace 版本,而不是官方 upstream 扩展。

Windows:

  • GuanceCloud/opentelemetry-php-instrumentation Release 页面下载与当前 PHP 小版本、ts/nts、编译器匹配的 zip 包
  • php_opentelemetry.dll 放入 PHP ext/ 目录
  • php.ini 中启用扩展

无论使用哪种方式,选择扩展包时都需要严格匹配以下条件:

  • PHP 小版本,例如 8.1/8.2/8.3/8.4
  • ts/nts
  • 平台与编译器
  • 目标运行方式对应的 PHP 二进制

php.ini 中启用扩展:

[opentelemetry]
extension=opentelemetry.so
opentelemetry.attr_hooks_enabled = On

确认扩展已加载:

php --ri opentelemetry

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

OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:9529/otel

如果你使用 PHP-FPMApacheSupervisorsystemd 或容器启动 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

如需区分环境,补充:

OTEL_RESOURCE_ATTRIBUTES=deployment.environment=prod

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 日志,并显式写入 serviceenvversion。如果需要日志与链路联动,可把当前 trace_idspan_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"

建议日志字段至少包含:

  • message
  • status
  • service
  • env
  • version
  • trace_id
  • span_id

PHP-FPM 指标接入

如果应用通过 PHP-FPM 运行,建议同时开启 phpfpm 采集器。

  1. www.conf 中开启状态页:
pm.status_path = /status
  1. 通过 Nginx 或 Apache 暴露 /status

  2. DataKit 启用 phpfpm 采集器:

[[inputs.phpfpm]]
  status_url = "http://127.0.0.1/status"
  use_fastcgi = false

这样可以同步观测:

  • 活跃进程数
  • 空闲进程数
  • 连接队列长度
  • 慢请求数量
  • 单进程请求耗时与内存消耗

Profiling 接入(可选)

如果除了链路之外,还需要定位 CPU、内存分配和热点函数问题,可单独开启 PHP Profiling。

当前更稳妥的做法是:

  1. DataKit 开启 profile 采集器
  2. PHP 安装 dd-trace-php 并启用 profiling
  3. 为 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 是链路的补充能力,建议按需开启,不必在所有服务上默认全开。

最小接入顺序

如果你的目标是先把链路跑通,再逐步补齐其它观测数据,建议按下面顺序接入:

  1. 开启 DataKit opentelemetry 输入
  2. 安装并启用 PHP opentelemetry 扩展
  3. 安装项目内 sdk + exporter-otlp + 对应 auto-* 依赖
  4. 配置 OTEL_* 进程环境变量
  5. 发起一次真实请求,确认链路已进入观测云
  6. 再补日志采集、PHP-FPM 指标和 Profiling

这样可以把链路联调步骤压缩到最短,避免一开始同时处理太多组件。

当前 Fork 的不足

如果完全对齐 OpenTelemetry 官方 zero-code 体验,当前 GuanceCloud fork 还有几处明显缺口:

  • 没有现成的 Linux 预编译二进制资产,Linux 侧安装路径还不够短
  • 没有独立可识别的包分发渠道,pecl install opentelemetry 会落到 upstream,而不是 gtrace
  • release 资产与官方文档的“系统包安装”路径没有完全打通,文档不能直接照抄官方安装命令
  • 需要单独说明“扩展来自 fork,但 SDK 和 auto instrumentation 依赖仍来自官方 Composer 包”

如果后续要继续优化接入体验,优先级建议如下:

  1. 为 Linux 增加常用 PHP 小版本的预编译扩展资产
  2. 提供一份安装脚本,自动识别 PHP 版本、ts/nts 和扩展目录
  3. 在 release 页面固定给出“适用于哪种 PHP 版本/运行模式”的资产说明
  4. 在 fork README 中明确区分“upstream 安装路径”和“GuanceCloud gtrace 安装路径”

实践效果

完成以上接入后,通常可以得到以下观测能力:

  • 在应用性能监测中查看 PHP 服务入口请求、数据库调用、下游 HTTP 调用等链路信息
  • 在日志中按照 service/env/version 过滤,并基于 trace_id 回溯同一请求
  • 在基础设施或自定义视图中观察 PHP-FPM 的活跃进程、排队、慢请求等运行状态
  • 在 Profiling 视图中定位 CPU 热点、内存分配热点和慢函数

最佳实践建议

  • 统一资源属性:至少固定 service.nameservice.versiondeployment.environment
  • 统一发布命名:扩展版本、应用版本、发布标签尽量保持一致,方便版本回溯
  • 优先使用 4317/gRPC:生产环境优先走 OTLP gRPC9529/otel 更适合联调和排障
  • 优先使用现成安装方式:优先镜像预装、已构建制品分发或具备 pecl 条件下的 PECL 安装,不把源码编译作为主推荐路径
  • 用进程级环境变量:不要只在登录 shell 中设置 OTEL_*,要写进 php-fpmsystemd、容器或启动脚本
  • 控制属性基数:不要把手机号、订单号全集、原始 SQL、超长 URL 全量写入 span attribute
  • 关键业务手工补点:自动装配覆盖不到的业务节点,用 WithSpan 精准补齐
  • 日志保留链路字段:统一输出 trace_id/span_id,否则日志和链路无法稳定联动
  • 先检查 DataKit 输入:链路打不通时,优先确认 opentelemetryloggingphpfpmprofile 采集器是否已启用

参考资料

文档评价

文档内容是否对您有帮助?