不加载PHP OpenTelemetry SDK实现Trace‌与Logs

article/2025/6/24 19:13:06

目录

  • 前言
  • 一、回到OpenTelemetry原理看问题
    • 1、数据接收(Receivers)
    • 2、数据处理(Processors)
    • 3、数据导出(Exporters)
  • 二、不加载OpenTelemetry SDK实现Trace‌与Logs示例

前言

前面两篇我们分别介绍了OpenTelemetry原理以及借助PHP OpenTelemetry SDK实现的分布式链路追踪Trace‌和日志Logs,按理说我们已经可以起飞了✈️。

基于OpenTelemetry的分布式链路追踪Trace‌实现(PHP篇)
基于OpenTelemetry的日志Logs实现(PHP篇)

但是实际情况可能各有不同,我们知道sdk对php版本的要求至少是v7.4+,0代码自动插桩的话甚至需要v8,有些PHP项目使用的PHP版本相对老旧,而且由于历史的原因升级是一件很麻烦的事。那怎么办呢?不能升级PHP版本就无法使用SDK且无法实现自己项目的OpenTelemetry 布式链路追踪Trace‌和日志Logs?答案当然是:❌。

在这里插入图片描述

一、回到OpenTelemetry原理看问题

我们之前说到,OpenTelemetry 其实就是个协议规范,原理可以回头参看《基于OpenTelemetry的分布式链路追踪Trace‌实现(PHP篇)》第三章OpenTelemetry的架构原理,也就是说如果遵循规范其实上报就不是问题。

可观测链路 OpenTelemetry 版支持接收应用的链路追踪、指标和日志数据,提供直接上报通过 OpenTelemetry Collector 转发两种上报方式。
在这里插入图片描述
Application: 一般的应用程序,同时使用了 OpenTelemetry 的 Library (实现了 API 的 SDK)。

OTel Libraty:也称为 SDK,负责在客户端程序里采集观测数据,包括 metrics,traces,logs,对观测数据进行处理,之后观测数据按照 exporter 的不同方式,通过 OTLP 方式发送到 Collector 或者直接发送到 Backend 中。

OTel Collector:负责根据 OpenTelemetry 的协议收集数据的组件,以及将观测数据导出到外部系统。这里的协议指的是 OTLP (OpenTelemetry Protocol)。不同的提供商要想能让观测数据持久化到自己的产品里,需要按照 OpenTelemetry 的标准 exporter 的协议接受数据和存储数据。同时社区已经提供了常见开源软件的输出能力,如 Prometheus,Jaeger,Kafka,zipkin 等。

Backend: 负责持久化观测数据Collector 本身不会去负责持久化观测数据,需要外部系统提供,在 Collector 的 exporter 部分,需要将 OTLP 的数据格式转换成 Backend 能识别的数据格式。目前社区的已经集成的厂商非常多,除了上述的开源的,常见的厂商包括 AWS,阿里,Azure,Datadog,Dynatrace,Google,Splunk,VMWare 等都实现了 Collector 的 exporter 能力。

在这里插入图片描述
otle collector是一种供应商无关的接收、处理和导出遥测数据的方式。如果不是直接发送到后端存储而是通过otel-collector处理转发,则我们需要将otel-collector部署运行起来。

为什么不直接将数据发送到可观测性后端?而是通过otel-collector处理转发?
对于大多数开发语言都有现成的sdk库可以使用,并将可观测数据导出到可观测性后端,例如jaeger,prometheus,对于小规模集群来说,这是一种快速获得价值体现的方式,但是也不利于统一管理。
所以一般来说,我们建议使用otel-collector,因为它允许快速卸载数据,并且otel-collector可以进行很多操作,例如重试、批处理、加密甚至敏感数据过滤。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

OpenTelemetry Collector 对追踪数据的处理流程遵循模块化管道设计,主要分为以下四个阶段,并由配置文件中定义的组件顺序决定执行逻辑:

1、数据接收(Receivers)

多协议适配‌
Collector 通过 OTLP 接收器(Receiver)支持 HTTP 和 gRPC 两种传输协议,自动解析请求头中的 Content-Type(如 application/x-protobuf 或application/json) 完成数据解码。例如,HTTP 接收器监听特定端口(如 4318)接收 OTLP/HTTP 格式的追踪数据。

上下文重建‌
接收器解析请求体中的二进制 Protobuf 数据后,将其转换为包含 TraceID、SpanID、操作名称等上下文信息的标准化内部数据结构

2、数据处理(Processors)

数据经过接收器后进入处理管道,典型的处理步骤包括:

批处理优化‌
将多个 Span 合并为批次,减少对后端存储系统的写入压力。
数据过滤‌
根据配置规则丢弃低价值 Span(如健康检查请求)或敏感字段脱敏。
元数据增强‌
添加环境变量信息(如 Kubernetes 节点标签)或统一添加自定义业务标签。
错误重试‌
在网络波动导致导出失败时,通过内存队列暂存数据并重试发送。

3、数据导出(Exporters)

处理后的数据根据配置通过不同导出器发送到目标系统:

后端存储适配‌
支持 Jaeger、Zipkin、Prometheus 等主流监控系统的专用导出器,也支持通过通用 OTLP 导出器转发到其他 Collector
协议转换‌
自动将 OpenTelemetry 原生格式转换为目标系统兼容的格式(如 Jaeger 的 Thrift 结构)。

我们可以看到Collector 一共遵循两种传输协议:HTTP 和 gRPC,提交的数据可以有两种格式protobuf 和json,可以通过请求头中的Content-Type设定(如 application/x-protobuf 或application/json)。我们还注意到数据接收Receivers的时候还在组织构TraceID、SpanID等以使数据造符合标准化内部数据结构。之前使用SDK的时候这块都是无感知透明化的,也就是SDK已经处理得明明白白了,你只管提交到后端储存就可以啦。

比如我们再次感受下之前通过SDK上报的示例。

putenv('OTEL_SERVICE_NAME=demo1');
putenv('OTEL_PHP_AUTOLOAD_ENABLED=true');
putenv('OTEL_TRACES_EXPORTER=console');//导出协议  console  otlp...
putenv('OTEL_METRICS_EXPORTER=none');
putenv('OTEL_LOGS_EXPORTER=console');
#putenv('OTEL_EXPORTER_OTLP_PROTOCOL=grpc');//上报协议 Traces 支持 grpc、http/protobuf、http/json。 Metrics 支持 grpc、http/protobuf。
#putenv('OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318');//上报端点 http:4318,grpc:4317
#putenv('OTEL_EXPORTER_OTLP_HEADERS=');
#putenv('OTEL_PROPAGATORS=b3,baggage,tracecontext');use OpenTelemetry\API\Globals;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;require_once __DIR__ . '/vendor/autoload.php';$tracer = Globals::tracerProvider()->getTracer('demo-tracer-name');$app = AppFactory::create();$app->get('/rolldice', function (Request $request, Response $response) use ($tracer) {$span = $tracer->spanBuilder('manual-span')->startSpan();try {$span->setAttribute('user_id', 12345);$result = random_int(1, 6);$response->getBody()->write(strval($result));$span->addEvent('rolled dice', ['result' => $result])->end();return $response;} catch (Exception $e) {$span->setStatus($e->getCode(), $e->getMessage());$span->end();$response->getBody()->write('exception');return $response;}});$app->run();

现在我们来看这样的一条HTTP上报路径。

[应用代码] --生成Span数据--> [SDK Exporter] --OTLP/HTTP序列化-->  
[Collector HTTP接收器] --数据处理管道--> [后端存储]

在这个流程里我们计划采用HTTP的application/json格式上报。如果不使用SDK,那么就意味着我们需要自己完成后端存储节点之前的数据规范处理所有工作(我们甚至是否可以大胆地认为就是 [后端存储] 节点之前的所有工作,包含Collector内的动作)。撇开次要因素不提,主要就是一个构造 OTLP/HTTP JSON trace 数据的过程。那么首先我们得先要知道OTLP协议规范的必备数据格式是什么,下文将以例子直接展示。

二、不加载OpenTelemetry SDK实现Trace‌与Logs示例

通过上面的原理分析,事情就变得简单有趣了,直接上示例代码。

/***  上报trace 参考案例*- 可以通过 HTTP 接口(如 OTLP/HTTP)手动上报追踪数据到 OpenTelemetry Collector。*- 需要自己构造符合 OTLP JSON 规范的数据包并发送。*- 推荐优先使用 SDK,接口方式适合特殊场景或兼容老环境。**/// 需要 PHP 7.1+,并安装 guzzlehttp/guzzle
require 'vendor/autoload.php';use GuzzleHttp\Client;$client = new Client();$traceId = bin2hex(random_bytes(16)); // 16字节=32位hex
$spanId = bin2hex(random_bytes(8));   // 8字节=16位hex
$now = (int)(microtime(true) * 1e9);  // 纳秒// 构造 OTLP/HTTP JSON trace 数据
$traceData = ["resourceSpans" => [["resource" => ["attributes" => [["key" => "service.name","value" => ["stringValue" => "php-manual-otel"]]]],"scopeSpans" => [["scope" => ["name" => "manual-php","version" => "1.0.0"],"spans" => [["traceId" => $traceId,"spanId" => $spanId,"name" => "manual-span","kind" => 1, // SPAN_KIND_INTERNAL"startTimeUnixNano" => $now,"endTimeUnixNano" => $now + 1000000, // +1ms"attributes" => [["key" => "http.method","value" => ["stringValue" => "GET"]]],"status" => ["code" => 1 // STATUS_CODE_UNSET]]]]]]]
];try {$response = $client->post('http://collector:4318/v1/traces', ['headers' => ['Content-Type' => 'application/json','xxxx-token' => 'xxx'],'body' => json_encode($traceData),]);echo "Status: " . $response->getStatusCode() . "\n";echo "Response: " . $response->getBody() ."| traceId={$traceId}". "\n";
} catch (Exception $e) {echo "Error: " . $e->getMessage() . "\n";
}
/***  上报logs 参考案例*- 可以通过 HTTP 接口(如 OTLP/HTTP)手动上报追踪数据到 OpenTelemetry Collector。*- 需要自己构造符合 OTLP JSON 规范的数据包并发送。*- 推荐优先使用 SDK,接口方式适合特殊场景或兼容老环境。**/// 需要 PHP 7.1+,并安装 guzzlehttp/guzzle
require 'vendor/autoload.php';use GuzzleHttp\Client;$client = new Client();$now = (int)(microtime(true) * 1e9);  // 纳秒// 构造 OTLP/HTTP JSON log 数据
$logData = ["resourceLogs" => [["resource" => ["attributes" => [["key" => "service.name","value" => ["stringValue" => "php-manual-otel-logs"]]]],"scopeLogs" => [["scope" => ["name" => "manual-php","version" => "1.0.0"],"logRecords" => [["timeUnixNano" => $now,"severityNumber" => 9, // INFO"severityText" => "INFO","body" => ["stringValue" => "This is a manual log from PHP"],"attributes" => [["key" => "http.method","value" => ["stringValue" => "GET"]]]]]]]]]
];try {$response = $client->post('http://collector:4318/v1/logs', ['headers' => ['Content-Type' => 'application/json','xxxx-token' => 'xxx'],'body' => json_encode($logData),]);echo "Status: " . $response->getStatusCode() . "\n";echo "Response: " . $response->getBody() . "\n";
} catch (Exception $e) {echo "Error: " . $e->getMessage() . "\n";
}

至此,我们不加载OpenTelemetry SDK实现Trace‌与Logs就完成啦。当然这只是个简单的例子抛砖引玉供参考,在实际的应用中不加载SDK终归要自己处理很多业务之外繁琐的事情,甚至与可能丢失Collector 很多优化的环节。正如示例所说,接口方式适合特殊场景或兼容老环境的临时解决方案,能升级版本解决的尽量使用SDK,推荐优先使用 SDK。


http://www.hkcw.cn/article/SREFpFWlNr.shtml

相关文章

一文认识并学会c++模板初阶

文章目录 泛型编程:概念 函数模板概念:🚩函数模板格式原理:🚩函数模板实例化与非模板函数共存 类模板类模板实例化 泛型编程: 概念 🚩编写与类型无关的通用代码,是代码复写一种手段…

leetcode刷题日记——二叉树的右视图

[ 题目描述 ]: [ 思路 ]: 二叉树的右视图:即二叉树每层最右边的节点BFS:使用层次遍历,每当遍历到每层最后一个节点时,记录改节点的值运行如下 int* rightSideView(struct TreeNode* root, int* returnS…

python 空气质量可视化,数据分析 + 前后端分离 + ppt 演讲大纲

1. 起因, 目的: 前段时间写的一个小项目,整理为一篇文章,发布出去,然后删掉项目。完整项目,见顶部链接。使用过程, 下面有说明。 2. 先看效果 3. 过程: 后端 python fastapi前端 python plotly # 数据…

|从零开始的Pyside2界面编程|绘图、布局及页面切换

🐑 |从零开始的Pyside2界面编程| 布局及页面切换🐑 文章目录 🐑 |从零开始的Pyside2界面编程| 布局及页面切换🐑♈前言♈♈页面切换♈♈页面布局♈♈总结♈ ♈前言♈ 经过两周的学习自己设备的前端也算是完成了一小半了&#xff…

我的世界Java版1.21.4的Fabric模组开发教程(十一)创建方块

这是适用于Minecraft Java版1.21.4的Fabric模组开发系列教程专栏第十一章——创建方块。想要阅读其他内容,请查看或订阅上面的专栏。 方块(Block) 是构成Minecraft世界的主要组成部分,是组成游戏地图的最基本单元,也是模组开发的核心元素之一…

计算机网络:物理层

目录 一、物理层的基本概念 二、物理层下面的传输媒体 2.1 导引型传输媒体 2.1.1 同轴电缆 2.1.2 双绞线 2.1.3 光纤 2.1.4 电力线 2.2 非导引型传输媒体 2.2.1 无线电波 2.2.2 微波 2.2.3 红外线 2.2.4 可见光 三、传输方式 3.1 串行与并行 3.2 同步与异步 3.…

我的世界Java版1.21.4的Fabric模组开发教程(十)更多物品交互行为

这是适用于Minecraft Java版1.21.4的Fabric模组开发系列教程专栏第十章——更多物品交互行为。想要阅读其他内容,请查看或订阅上面的专栏。 在之前的创建自定义数据组件章节中,我们在自定义物品类中重写了来自Item类中的use()方法,实现了在右…

Linux531rsync定时同步 再回忆

rsync定时同步 环境配置 关闭防火墙,selinux systemctl stop firewalld systemctl disable firewall setenforce 0 cat /etc/selinux/configpei SELINUXdisable设置主机名 systemctl set-hostname code systemctl set-hostname backup设置静态IP rsync由于要设…

MySQL数据库复合查询

前言:本文不对SQL查询做详细讲解,而做案例实践,适合已掌握MySQL基础语法,需要通过实际案例巩固技能的开发者。 首先准备这样三张表 雇员信息表、部门信息、薪水等级。如下: 需要库文件的小伙伴私信我哦!&am…

STM32 串口通信①:USART 全面理解 + 代码详解

一 前言 本篇文章并不会系统的从零开始讲起,适合大家对USART有一定的学习,再看本篇文章会有一定的收获,祝大家在本文中,吸收到新的知识。 二 通信方式 1)按数据传输的方式分(这就是“串行 vs 并行”&…

基于图神经网络的自然语言处理:融合LangGraph与大型概念模型的情感分析实践

在企业数字化转型进程中,非结构化文本数据的处理与分析已成为核心技术挑战。传统自然语言处理方法在处理客户反馈、社交媒体内容和内部文档等复杂数据集时,往往难以有效捕获文本间的深层语义关联和结构化关系。大型概念模型(Large Concept Mo…

极地导航的难点及应对措施(上)

在之前的博文《南北极导航选用什么投影?》和何老师的博文《高纬度、跨极区导航技术》中简单说了说南北极导航的投影设置问题。 本文主要说一说南北极导航中实际工作的难点问题以及应对措施。下图是南北极的位置图,从图中可以看出,南极是大陆…

Centos系统搭建主备DNS服务

目录 一、主DNS服务器配置 1.安装 BIND 软件包 2.配置主配置文件 3.创建正向区域文件 4.创建区域数据文件 5.检查配置语法并重启服务 二、从DNS服务配置 1.安装 BIND 软件包 2.配置主配置文件 3.创建缓存目录 4.启动并设置开机自启 一、主DNS服务器配置 1.安装 BIN…

【图像处理入门】3. 几何变换基础:从平移旋转到插值魔法

摘要 掌握图像的几何变换相当于学会「图像的空间魔法」。本文将带你理解平移/旋转/缩放的数学原理,掌握OpenCV中warpAffine和getAffineTransform的核心用法,对比最近邻、双线性等插值算法的优劣。通过图像翻转、镜像、透视变换实战,学会用变…

TomatoSCI分析日记:数据分析为什么用csv不用excel

其实并不是多余,虽然看到的内容是一样的,但是相比excel文件,csv文件没这么多繁文缛节,效率更高。 1.csv更干净 csv本质是纯文本,只有你看到的数据,没有花里胡哨的单元格格式、颜色、批注等隐藏信息&#…

【鱼皮-用户中心】笔记

任务:完整了解做项目的思路,接触一些企业及的开发技术 title 企业做项目流程需求分析技术选型 计划一一、前端初始化1. **下载node.js**2. **安装yarn**3. **初始化 Ant Design Pro 脚⼿架(关于更多可进入官网了解)**4. **开启Umi…

基于 Chrome 浏览器扩展的Chroma简易图形化界面

简介 ChromaDB Manager 是基于 Chrome 浏览器扩展的一款 ChromaDB(一个流行的向量数据库)的数据查询工具。提供了一个用户友好的界面,可以直接从浏览器连接到本地 ChromaDB 实例、查看集合信息和分片数据。本工具特别适合开发人员快速查看和…

[ElasticSearch] ElasticSearch的初识与基本操作

🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…

Kafka 如何保证不重复消费

在消息队列的使用场景中,避免消息重复消费是保障数据准确性和业务逻辑正确性的关键。对于 Kafka 而言,保证不重复消费并非单一机制就能实现,而是需要从生产者、消费者以及业务层等多个维度协同配合。接下来,我们将结合图文详细解析…

【快速解决】数据库快速导出成sql文件

1、cmd直接打开 输入命令 mysqldump -u用户名 -p密码 数据库名 > 导出文件名.sql修改成自己mysql的用户名和密码,和要导出的数据库名称,给导出的文件起一个名字。 如图所示 这样就成功了。