ThinkPHP集成SkyWalking需弃用已归档的PHP Agent,改用OpenTelemetry SDK手动埋点:通过中间件解析traceparent实现上下文透传,在HTTP/DB等调用前注入span context,并按白名单过滤非业务流量,最终在SkyWalking UI验证trace_id一致性、parent_span_id嵌套及span标签完整性。

如果您在 ThinkPHP 项目中希望实现与 SkyWalking 的链路追踪集成,则需明确:ThinkPHP 本身不提供自动埋点能力,SkyWalking PHP Agent 官方支持有限且已停止维护,当前主流实践是通过 OpenTelemetry SDK 手动注入 + 中间件控制完成全链路上下文透传。以下是具体实施步骤:
一、禁用 SkyWalking PHP Agent 并切换至 OpenTelemetry 手动埋点
SkyWalking 官方 PHP Agent(skywalking-php)自 2023 年起已归档,不再更新,且其自动注入机制会与 ThinkPHP 中间件采样逻辑冲突,导致 trace 泄漏或上下文丢失。必须停用该 Agent,改用 OpenTelemetry PHP SDK 进行可控埋点。
1、执行 SW_AGENT_DISABLE=1 环境变量设置,确保原有 Agent 不加载
2、通过 Composer 安装 OpenTelemetry SDK:composer require open-telemetry/sdk
立即学习“PHP免费学习笔记(深入)”;
3、在 app/middleware/TraceMiddleware.php 的 handle 方法开头添加初始化代码,避免在控制器中重复初始化
4、确认 opentelemetry/exporter-otlp 已安装,并配置 OTLP HTTP endpoint 指向 SkyWalking OAP 的 http://skywalking-oap:11800/v1/traces
二、在中间件中完成 TraceContext 解析与 Span 创建
请求入口必须解析上游传递的 traceparent header,否则跨服务调用将生成新 trace_id,导致链路断裂。OpenTelemetry 要求在中间件中显式调用 Propagator::extract(),并基于解析结果决定是否创建 root span 或 child span。
1、从 $_SERVER['HTTP_TRACEPARENT'] 中提取 traceparent 字符串
2、调用 TraceContextPropagator::getInstance()->extract($carrier) 恢复上下文
3、使用 TracerProvider::builder()->setSampler(...)->build() 构建带采样策略的 Tracer 实例
4、调用 $tracer->startSpan($request->url(), [...]) 创建 root span(若无父 context)或 child span(若有)
5、将 span 设置为全局可访问对象,供后续 DB、HTTP 等操作中间件复用
三、注入 HTTP 调用透传逻辑(关键跨服务环节)
ThinkPHP 默认的 Http 类或 Guzzle 客户端不会自动携带 traceparent header,必须在发起远程请求前手动注入,否则下游服务无法延续 trace_id。该操作需在业务逻辑调用前完成,不可延迟至响应阶段。
1、在封装的 HTTP 请求方法(如 app/common/HttpHelper.php)中,检查是否存在活跃 span
2、若存在,调用 $propagator->inject($spanContext, $headers) 将 traceparent 写入请求头
3、确保 headers['traceparent'] 被正确附加到 Guzzle 或内置 curl 请求选项中
4、对所有第三方 SDK(如 Redis、MySQL PDO 封装)同样注入 span context,避免子链路缺失
四、过滤非业务流量以降低数据噪音
默认情况下,Eureka 心跳、健康检查、静态资源请求等高频非业务接口会大量涌入 SkyWalking,挤占存储与查询资源。必须在中间件中依据 URI、Header 或请求特征进行白名单/黑名单拦截,仅对核心业务 endpoint 启用 trace。
1、定义业务路径白名单数组,例如 ['/api/v1/user', '/api/v1/order', '/pay/notify']
2、在 TraceMiddleware 中判断 Str::startsWith($request->url(), $whitelist) 是否匹配
3、对不匹配请求直接 return $next($request),跳过 span 创建与上下文管理
4、对含 X-Skip-Trace: true header 的请求也执行跳过逻辑,便于灰度或调试时临时关闭
五、验证链路完整性与上下文一致性
集成完成后必须验证 trace_id 是否跨服务一致、parent_span_id 是否正确嵌套、各 span 的 duration 是否反映真实耗时。验证失败通常源于中间件顺序错误或上下文未正确绑定,而非 SDK 配置问题。
1、启动 ThinkPHP 应用与 SkyWalking UI,发起一次含跨服务调用的请求(如调用订单服务再调用支付服务)
2、在 SkyWalking UI 的「Trace List」中搜索对应 trace_id,确认出现不少于 3 个 service 节点
3、点击 trace 查看详情,核对每个 segment 的 service.name 与 endpoint.name 是否准确
4、检查每个 span 的 parent_span_id 是否非空,且上一级 span 的 id 与其匹配
5、确认 HTTP 请求 span 中包含 http.url 与 http.status_code 标签



















