通过OpenTelemetry为应用埋点并上报链路数据至可观测链路 OpenTelemetry 版后,可观测链路 OpenTelemetry 版即可开始监控应用,您可以查看应用拓扑、调用链路、异常事务、慢事务和SQL分析等一系列监控数据。本文介绍如何使用OpenTelemetry为PHP应用进行自动或手动埋点并上报数据。
前提条件
背景信息
OpenTelemetry PHP支持自动埋点和手动埋点,对PHP的版本要求如下:
自动埋点支持的版本:PHP 8.0 +
手动埋点支持的版本:PHP 7.4 +
支持自动埋点的框架列表如下,完整信息请参见OpenTelemetry官方文档。
示例Demo
示例代码仓库地址:php-opentelemetry-demo
基于OpenTelemery PHP Extension为应用自动埋点并上报链路数据
Auto-demo是基于PHP Slim Web框架实现一个模拟扔骰子游戏的应用,并使用OpenTelemetry为应用自动埋点(即自动创建Trace/Span等链路数据),实现无侵入的PHP应用链路追踪。
OpenTelemetry除了支持Slim框架的自动埋点,还支持多种框架,完整列表请参见官方文档。
前提条件
已安装PHP、Composer、PECL,且PHP版本≥8.0。
操作步骤
创建投骰子应用。
初始化。
mkdir <project-name> && cd <project-name> composer init \ --no-interaction \ --stability beta \ --require slim/slim:"^4" \ --require slim/psr7:"^1" composer update
编写应用代码。
在<project-name>目录下创建一个index.php文件,添加如下内容。
这段代码模拟扔骰子游戏,返回1-6之间的一个随机数。
<?php use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Slim\Factory\AppFactory; require __DIR__ . '/vendor/autoload.php'; $app = AppFactory::create(); $app->get('/rolldice', function (Request $request, Response $response) { $result = random_int(1,6); $response->getBody()->write(strval($result)); return $response; }); $app->run();
此时应用已经编写完成,执行
php -S localhost:8080
命令即可运行应用,访问地址为http://localhost:8080/rolldice
。
构建OpenTelemetry PHP扩展。
下载构建OpenTelemetry PHP extension所需要的工具。
macOS
brew install gcc make autoconf
Linux(apt)
sudo apt-get install gcc make autoconf
使用PECL构建OpenTelemetry PHP扩展。
pecl install opentelemetry
注意,构建成功时输出内容的最后几行如下(路径可能不完全一致):
Build process completed successfully Installing '/opt/homebrew/Cellar/php/8.2.8/pecl/20220829/opentelemetry.so' install ok: channel://pecl.php.net/opentelemetry-1.0.0beta6 Extension opentelemetry enabled in php.ini
(可选)启用OpenTelemetry PHP扩展。
如果上一步输出了
Extension opentelemetry enabled in php.ini
,表明已经启用,请跳过当前步骤。在php.ini文件中添加如下内容:
[opentelemetry] extension=opentelemetry.so
再次验证是否构建并启用成功。
方法一:
php -m | grep opentelemetry
预期输出:
opentelemetry
方法二
php --ri opentelemetry
预期输出:
opentelemetry opentelemetry support => enabled extension version => 1.0.0beta6
为投骰子应用添加OpenTelemetry PHP自动埋点需要的额外依赖。
# 这一步构建时间较长,会在控制台打印很多内容 pecl install grpc composer config allow-plugins.php-http/discovery false composer require \ open-telemetry/sdk \ open-telemetry/opentelemetry-auto-slim \ open-telemetry/exporter-otlp \ php-http/guzzle7-adapter \ open-telemetry/transport-grpc
open-telemetry/sdk:OpenTelemetry PHP SDK。
open-telemetry/opentelemetry-auto-slim:OpenTelemetry PHP针对Slim框架实现的自动埋点插件。
open-telemetry/exporter-otlp:OpenTelemetry PHP OTLP协议数据上报所需的依赖。
运行应用。
执行以下命令。
env OTEL_PHP_AUTOLOAD_ENABLED=true \ OTEL_SERVICE_NAME=<your-service-name> \ OTEL_TRACES_EXPORTER=otlp \ OTEL_METRICS_EXPORTER=none \ OTEL_LOGS_EXPORTER=none \ OTEL_EXPORTER_OTLP_PROTOCOL=grpc \ OTEL_EXPORTER_OTLP_ENDPOINT=<endpoint> \ OTEL_EXPORTER_OTLP_HEADERS=Authentication=<token> \ OTEL_PROPAGATORS=baggage,tracecontext \ php -S localhost:8080
<your-service-name>:应用名,如:
php-demo
。<endpoint>:前提条件中获取的gRPC接入点,如:
http://tracing-analysis-dc-hz.aliyuncs.com:8090
。<token>:前提条件中获取的接入鉴权信息。
在浏览器中访问以下链接。
http://localhost:8080/rolldice
每次进入该页面,OpenTelemetry都会自动创建Trace,并将链路数据上报至阿里云可观测链路 OpenTelemetry 版。
查看链路数据。
登录可观测链路 OpenTelemetry 版控制台,在应用列表页面找到应用名为
<your-service-name>
的应用(例如php-demo),单击应用名称进入应用详情中查看调用链。
基于OpenTelemery PHP SDK为应用手动埋点并上报链路数据
Manual-demo是基于PHP Slim Web框架实现一个模拟扔骰子游戏的应用,并使用OpenTelemetry PHP SDK为应用手动埋点(即在代码中创建Span,并为Span设置属性、事件、状态等),实现自定义的PHP应用链路追踪。
当OpenTelemetry PHP Extension自动埋点不满足您的场景,或者需要增加一些自定义业务埋点时,可以使用手动埋点方式上报链路数据。
前提条件
已安装PHP、Composer、PECL,且PHP版本≥7.4。
操作步骤
创建投骰子应用。
初始化。
mkdir <project-name> && cd <project-name> composer init \ --no-interaction \ --stability beta \ --require slim/slim:"^4" \ --require slim/psr7:"^1" composer update
编写应用代码。
在<project-name>目录下创建一个index.php文件,添加如下内容。
这段代码模拟扔骰子游戏,返回1-6之间的一个随机数。
<?php use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Slim\Factory\AppFactory; require __DIR__ . '/vendor/autoload.php'; $app = AppFactory::create(); $app->get('/rolldice', function (Request $request, Response $response) { $result = random_int(1,6); $response->getBody()->write(strval($result)); return $response; }); $app->run();
此时应用已经编写完成,执行
php -S localhost:8080
命令即可运行应用,访问地址为http://localhost:8080/rolldice
。
导入OpenTelemetry PHP SDK以及OpenTelemetry gRPC Explorer所需依赖。
下载PHP HTTP客户端库,用于链路数据上报。
composer require guzzlehttp/guzzle
下载OpenTelemetry PHP SDK。
composer require \ open-telemetry/sdk \ open-telemetry/exporter-otlp
下载使用gRPC上报数据时所需依赖。
pecl install grpc # 如果之前已经下载过grpc,可以跳过这一步 composer require open-telemetry/transport-grpc
编写OpenTelemetry初始化工具类。
在index.php文件所在目录中创建opentelemetry_util.php文件。
在文件中添加如下代码。
<?php use OpenTelemetry\API\Common\Instrumentation\Globals; use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator; use OpenTelemetry\Contrib\Otlp\SpanExporter; use OpenTelemetry\SDK\Common\Attribute\Attributes; use OpenTelemetry\SDK\Common\Export\Stream\StreamTransportFactory; use OpenTelemetry\SDK\Resource\ResourceInfo; use OpenTelemetry\SDK\Resource\ResourceInfoFactory; use OpenTelemetry\SDK\Sdk; use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler; use OpenTelemetry\SDK\Trace\Sampler\ParentBased; use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor; use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessorBuilder; use OpenTelemetry\SDK\Trace\TracerProvider; use OpenTelemetry\SemConv\ResourceAttributes; use OpenTelemetry\Contrib\Grpc\GrpcTransportFactory; use OpenTelemetry\Contrib\Otlp\OtlpUtil; use OpenTelemetry\API\Common\Signal\Signals; // OpenTelemetry 初始化配置(包含设置应用名、Trace导出方式、Trace上报接入点,并创建全局TraceProvide。需要在PHP应用初始化时就进行OpenTelemetry初始化配置) function initOpenTelemetry() { // 1. 设置 OpenTelemetry 资源信息 $resource = ResourceInfoFactory::emptyResource()->merge(ResourceInfo::create(Attributes::create([ ResourceAttributes::SERVICE_NAME => '<your-service-name>', # 应用名,必填,如php-manual-demo ResourceAttributes::HOST_NAME => '<your-host-name>' # 主机名,选填 ]))); // 2. 创建将 Span 输出到控制台的 SpanExplorer // $spanExporter = new SpanExporter( // (new StreamTransportFactory())->create('php://stdout', 'application/json') // ); // 2. 创建通过 gRPC 上报 Span 的 SpanExplorer $headers = [ 'Authentication' => "<your-token>", ]; $transport = (new GrpcTransportFactory())->create('<grpc-endpoint>' . OtlpUtil::method(Signals::TRACE), 'application/x-protobuf', $headers); $spanExporter = new SpanExporter($transport); // 3. 创建全局的 TraceProvider,用于创建 tracer $tracerProvider = TracerProvider::builder() ->addSpanProcessor( (new BatchSpanProcessorBuilder($spanExporter))->build() ) ->setResource($resource) ->setSampler(new ParentBased(new AlwaysOnSampler())) ->build(); Sdk::builder() ->setTracerProvider($tracerProvider) ->setPropagator(TraceContextPropagator::getInstance()) ->setAutoShutdown(true) // PHP 程序退出后自动关闭 tracerProvider,保证链路数据都被上报 ->buildAndRegisterGlobal(); // 将 tracerProvider 添加到全局 } ?>
<your-service-name>:应用名。
<your-host-name>:主机名。
<your-token>:通过gRPC上报数据的鉴权Token。
<grpc-endpoint>:通过gRPC上报数据的接入点。
修改应用代码,使用OpenTelemetry API创建Span。
在index.php文件中导入所需包。
<?php use OpenTelemetry\API\Common\Instrumentation\Globals; use OpenTelemetry\SDK\Common\Attribute\Attributes; use OpenTelemetry\SDK\Trace\TracerProvider; require __DIR__ . '/opentelemetry_util.php';
调用initOpenTelemetry方法完成初始化,需要在PHP应用初始化时就进行OpenTelemetry初始化配置。
// OpenTelemetry 初始化,包含设置应用名、Trace导出方式、Trace上报接入点,并创建全局TraceProvider initOpenTelemetry();
在rolldice接口中创建Span。
/** * 1. 接口功能:模拟扔骰子,返回一个1-6之间的随机正整数 * 并演示如何创建Span、设置属性、事件、带有属性的事件 */ $app->get('/rolldice', function (Request $request, Response $response) { // 获取 tracer $tracer = \OpenTelemetry\API\Globals::tracerProvider()->getTracer('my-tracer'); // 创建 Span $span = $tracer->spanBuilder("/rolldice")->startSpan(); // 为 Span 设置属性 $span->setAttribute("http.method", "GET"); // 为 Span 设置事件 $span->addEvent("Init"); // 设置带有属性的事件 $eventAttributes = Attributes::create([ "key1" => "value", "key2" => 3.14159, ]); // 业务代码 $result = random_int(1,6); $response->getBody()->write(strval($result)); $span->addEvent("End"); // 销毁 Span $span->end(); return $response; });
创建嵌套Span。
新建一个rolltwodices接口,模拟扔两个骰子,返回两个1-6之间的随机正整数。
以下代码演示如何创建嵌套的Span。
$app->get('/rolltwodices', function (Request $request, Response $response) { // 获取 tracer $tracer = \OpenTelemetry\API\Globals::tracerProvider()->getTracer('my-tracer'); // 创建 Span $parentSpan = $tracer->spanBuilder("/rolltwodices/parent")->startSpan(); $scope = $parentSpan->activate(); $value1 = random_int(1,6); $childSpan = $tracer->spanBuilder("/rolltwodices/parent/child")->startSpan(); // 业务代码 $value2 = random_int(1,6); $result = "dice1: " . $value1 . ", dice2: " . $value2; // 销毁 Span $childSpan->end(); $parentSpan->end(); $scope->detach(); $response->getBody()->write(strval($result)); return $response; });
使用Span记录代码中发生的异常。
新建error接口,模拟接口发生异常。
以下代码演示如何在代码发生异常时使用Span记录状态。
$app->get('/error', function (Request $request, Response $response) { // 获取 tracer $tracer = \OpenTelemetry\API\Globals::tracerProvider()->getTracer('my-tracer'); // 创建 Span $span3 = $tracer->spanBuilder("/error")->startSpan(); try { // 模拟代码发生异常 throw new \Exception('exception!'); } catch (\Throwable $t) { // 设置Span状态为error $span3->setStatus(\OpenTelemetry\API\Trace\StatusCode::STATUS_ERROR, "exception in span3!"); // 记录异常栈轨迹 $span3->recordException($t, ['exception.escaped' => true]); } finally { $span3->end(); $response->getBody()->write("error"); return $response; } });
运行应用。
执行以下命令
php -S localhost:8080
在浏览器中访问以下链接:
http://localhost:8080/rolldice http://localhost:8080/rolltwodices http://localhost:8080/error
每次访问页面,OpenTelemetry会创建链路数据,并将链路数据上报至阿里云可观测链路 OpenTelemetry 版。
查看链路数据。
登录可观测链路 OpenTelemetry 版控制台,在应用列表页面找到应用名为
<your-service-name>
的应用(例如php-manual-demo),单击应用名称进入应用详情中查看调用链。