本文目录导读:

- OpenTelemetry(推荐)
- Jaeger + Jaeger PHP Client
- SkyWalking PHP Agent
- Zipkin PHP
- Laravel专用方案
- 日志集成
- 环境变量配置
- 最佳实践
- 注意事项
我来详细介绍PHP接入链路追踪的几种主流方案:
OpenTelemetry(推荐)
安装扩展
# 安装PHP扩展 pecl install opentelemetry
基础配置
<?php
require_once 'vendor/autoload.php';
use OpenTelemetry\SDK\Trace\TracerProvider;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\Exporter\JaegerExporter;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
// 创建TracerProvider
$resource = ResourceInfoFactory::emptyResource()->merge(
ResourceInfo::create([
'service.name' => 'your-service-name',
])
);
$exporter = new JaegerExporter(
'jaeger',
'http://jaeger:9411/api/v2/spans'
);
$tracerProvider = new TracerProvider(
new SimpleSpanProcessor($exporter),
$resource
);
$tracer = $tracerProvider->getTracer('your-app');
自动埋点
<?php
// 使用OpenTelemetry自动埋点
$tracer = \OpenTelemetry\API\Globals::tracer();
// 创建span
$span = $tracer->spanBuilder('database-query')
->setAttribute('db.system', 'mysql')
->setAttribute('db.statement', 'SELECT * FROM users')
->startSpan();
// 执行操作
try {
// 业务逻辑
$span->end();
} catch (\Exception $e) {
$span->recordException($e);
$span->setStatus(StatusCode::STATUS_ERROR);
$span->end();
throw $e;
}
中间件方式(Laravel示例)
<?php
namespace App\Http\Middleware;
use Closure;
use OpenTelemetry\API\Globals;
use OpenTelemetry\API\Trace\SpanKind;
use OpenTelemetry\API\Trace\StatusCode;
class TracingMiddleware
{
public function handle($request, Closure $next)
{
$tracer = Globals::tracer();
$span = $tracer->spanBuilder($request->getMethod() . ' ' . $request->getPathInfo())
->setSpanKind(SpanKind::KIND_SERVER)
->setAttribute('http.method', $request->getMethod())
->setAttribute('http.url', $request->fullUrl())
->startSpan();
$response = $next($request);
$span->setAttribute('http.status_code', $response->getStatusCode());
$span->end();
return $response;
}
}
Jaeger + Jaeger PHP Client
<?php
require_once 'vendor/autoload.php';
use Jaeger\Config;
use OpenTracing\GlobalTracer;
use OpenTracing\Reference;
// 初始化Jaeger
$config = new Config(
[
'sampler' => [
'type' => 'const',
'param' => true,
],
'logging' => true,
],
'your-service-name'
);
$config->initializeTracer();
$tracer = GlobalTracer::get();
// 创建span
$span = $tracer->startActiveSpan('business-operation', [
'tags' => [
'db.type' => 'mysql',
'customer.id' => '123',
]
]);
try {
// 子操作
$childSpan = $tracer->startActiveSpan('database-query');
// 执行操作
$childSpan->close();
$span->close();
} catch (\Exception $e) {
$span->setTag('error', true);
$span->log(['error' => $e->getMessage()]);
$span->close();
} finally {
$tracer->flush();
}
SkyWalking PHP Agent
<?php
// 安装SkyWalking Agent
// composer require skywalking/agent
use Skywalking\Agent;
use Skywalking\Util\Config;
// 初始化
$config = new Config([
'grpc' => '127.0.0.1:11800',
'service_name' => 'your-service-name',
'instance_name' => 'instance-1'
]);
Agent::init($config);
// 创建Span
$span = Agent::startSpan('business-operation', [
'peer' => 'localhost:8080',
'tags' => [
'db.type' => 'mysql',
'customer.id' => '123',
]
]);
try {
// 业务逻辑
$span->stop();
} catch (\Exception $e) {
$span->setError($e);
$span->stop();
}
Zipkin PHP
<?php
use Zipkin\Annotation;
use Zipkin\Endpoint;
use Zipkin\Samplers\Percentage;
use Zipkin\TracingBuilder;
use Zipkin\Reporters\Http;
// 创建Reporter
$endpoint = Endpoint::create('your-service-name');
$reporter = new Http([
'base_url' => 'http://zipkin:9411/api/v2/spans'
]);
// 采样器
$sampler = Percentage::create(0.1);
// 创建Tracing
$tracing = TracingBuilder::create()
->havingLocalEndpoint($endpoint)
->havingReporter($reporter)
->havingSampler($sampler)
->build();
$tracer = $tracing->getTracer();
// 创建Span
$span = $tracer->newTrace()
->setName('business-operation')
->start();
$span->tag('db.type', 'mysql');
$span->annotate('db.statement', 'SELECT * FROM users');
// 子Span
$child = $tracer->newChild($span->getContext())
->setName('database-query')
->start();
// 完成操作
$child->finish();
$span->finish();
// 发送到Zipkin
$tracing->flush();
Laravel专用方案
使用 Laravel OpenTelemetry
<?php
// config/opentelemetry.php
return [
'service_name' => 'laravel-app',
'exporter' => 'zipkin',
'zipkin' => [
'endpoint' => 'http://localhost:9411/api/v2/spans',
],
'sampler' => [
'type' => 'always_on',
],
];
// ServiceProvider
class TelemetryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(Tracer::class, function ($app) {
return TracerProvider::create()
->setResource(ResourceInfo::create([
'service.name' => config('opentelemetry.service_name')
]))
->setExporter(ExporterFactory::create(config('opentelemetry.exporter')))
->getTracer();
});
}
}
日志集成
<?php
// 在日志中包含Trace ID
class TraceIdProcessor
{
public function __invoke(array $record): array
{
$tracer = \OpenTelemetry\API\Globals::tracer();
$span = $tracer->getCurrentSpan();
if ($span) {
$context = $span->getContext();
$record['extra']['trace_id'] = $context->getTraceId();
$record['extra']['span_id'] = $context->getSpanId();
}
return $record;
}
}
// 配置到Monolog
$logger->pushProcessor(new TraceIdProcessor());
环境变量配置
# .env 配置 OTEL_SERVICE_NAME=your-service-name OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 OTEL_TRACES_EXPORTER=otlp OTEL_PROPAGATORS=jaeger,b3,baggage,tracecontext
最佳实践
统一封装
<?php
class TracingHelper
{
public static function trace(string $operation, callable $callback, array $attributes = [])
{
$tracer = \OpenTelemetry\API\Globals::tracer();
$span = $tracer->spanBuilder($operation)
->setAttributes($attributes)
->startSpan();
try {
$result = $callback();
$span->setStatus(StatusCode::STATUS_OK);
return $result;
} catch (\Exception $e) {
$span->recordException($e);
$span->setStatus(StatusCode::STATUS_ERROR);
throw $e;
} finally {
$span->end();
}
}
}
// 使用
$result = TracingHelper::trace('user-registration', function() {
// 业务逻辑
}, ['user.type' => 'vip']);
性能监控
<?php
// 监控数据库查询
DB::listen(function ($query) {
$tracer = \OpenTelemetry\API\Globals::tracer();
$span = $tracer->spanBuilder('query')
->setAttribute('db.system', 'mysql')
->setAttribute('db.statement', $query->sql)
->setAttribute('db.bindings', json_encode($query->bindings))
->startSpan();
$span->end();
});
// 监控Redis操作
Redis::macro('trace', function ($command, $params) {
$tracer = \OpenTelemetry\API\Globals::tracer();
$span = $tracer->spanBuilder('redis-' . $command)
->setAttribute('redis.command', $command)
->setAttribute('redis.params', json_encode($params))
->startSpan();
try {
$result = $this->command($command, $params);
$span->end();
return $result;
} catch (\Exception $e) {
$span->recordException($e);
$span->end();
throw $e;
}
});
注意事项
- 性能影响:合理设置采样率
- 安全:确保追踪数据不包含敏感信息
- 异步场景:处理协程、消息队列的链路传递
- 错误处理:确保发生异常时也能正确记录
- 资源清理:及时关闭Span释放资源
选择合适的方案,建议优先使用OpenTelemetry,它是目前最通用的标准。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播