首先安装依赖:

 composer require open-telemetry/sdk open-telemetry/exporter-otlp

opentelemetry_demo.php

<?php
require 'vendor/autoload.php';

use OpenTelemetry\SDK\Trace\TracerProviderFactory;
use OpenTelemetry\SDK\Metrics\MeterProviderFactory;
use OpenTelemetry\SDK\Logs\LoggerProviderFactory;
use OpenTelemetry\API\Trace\SpanKind;
use OpenTelemetry\API\Trace\StatusCode;
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\Contrib\Otlp\MetricExporter;
use OpenTelemetry\Contrib\Otlp\LogsExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;

class OpenTelemetryDemo {
    private $tracer;
    private $meter;
    private $logger;

    public function __construct($endpoint = 'http://localhost:4318') {
        // 初始化 Tracer
        $tracerProvider = (new TracerProviderFactory())->create();
        $this->tracer = $tracerProvider->getTracer('demo-app', '1.0.0');

        // 初始化 Meter
        $meterProvider = (new MeterProviderFactory())->create();
        $this->meter = $meterProvider->getMeter('demo-app', '1.0.0');

        // 初始化 Logger
        $loggerProvider = (new LoggerProviderFactory())->create();
        $this->logger = $loggerProvider->getLogger('demo-app', '1.0.0');
    }

    public function processOrder($orderId) {
        // 创建 Span (Trace)
        $span = $this->tracer->spanBuilder('process_order')
            ->setSpanKind(SpanKind::KIND_SERVER)
            ->startSpan();

        $span->setAttribute('order.id', $orderId);
        $span->addEvent('order_processing_started');

        try {
            // 模拟业务逻辑
            $this->validateOrder($orderId);
            $this->saveOrder($orderId);

            // 记录 Metric
            $counter = $this->meter->createCounter('orders_processed', 'orders', 'Total orders processed');
            $counter->add(1, Attributes::create(['status' => 'success']));

            // 记录 Log
            $this->logger->emit('info', 'Order processed successfully', ['order_id' => $orderId]);

            $span->setStatus(StatusCode::STATUS_OK);
            echo "订单 $orderId 处理成功\n";

        } catch (Exception $e) {
            $span->recordException($e);
            $span->setStatus(StatusCode::STATUS_ERROR, $e->getMessage());

            $counter = $this->meter->createCounter('orders_failed', 'orders', 'Total orders failed');
            $counter->add(1, Attributes::create(['error' => $e->getMessage()]));

            $this->logger->emit('error', 'Order processing failed', [
                'order_id' => $orderId,
                'error' => $e->getMessage()
            ]);

            echo "订单 $orderId 处理失败: " . $e->getMessage() . "\n";
        } finally {
            $span->end();
        }
    }

    private function validateOrder($orderId) {
        $span = $this->tracer->spanBuilder('validate_order')
            ->setSpanKind(SpanKind::KIND_INTERNAL)
            ->startSpan();

        sleep(1); // 模拟验证耗时
        $span->addEvent('validation_completed');
        $span->end();
    }

    private function saveOrder($orderId) {
        $span = $this->tracer->spanBuilder('save_order')
            ->setSpanKind(SpanKind::KIND_INTERNAL)
            ->startSpan();

        sleep(1); // 模拟保存耗时

        // 记录延迟 Metric
        $histogram = $this->meter->createHistogram('order_save_duration', 'ms', 'Order save duration');
        $histogram->record(1000, Attributes::create(['operation' => 'save']));

        $span->end();
    }
}

// 使用示例
$otel = new OpenTelemetryDemo();

// 处理多个订单
for ($i = 1; $i <= 3; $i++) {
    $otel->processOrder("ORDER-$i");
}

echo "\n所有订单处理完成\n";
echo "Traces、Metrics 和 Logs 已发送到 OpenTelemetry Collector\n";

docker-compose.yml

version: '3.8'

services:
  # OpenTelemetry Collector
  otel-collector:
    image: otel/opentelemetry-collector:latest
    command: ["--config=/etc/otel-collector-config.yaml"]
    volumes:
      - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
    ports:
      - "4317:4317"   # OTLP gRPC
      - "4318:4318"   # OTLP HTTP
      - "13133:13133" # health_check

  # Jaeger (查看 Traces)
  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "16686:16686" # Jaeger UI
      - "14250:14250" # gRPC

  # Prometheus (查看 Metrics)
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"

  # Grafana (可视化)
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin

otel-collector-config.yaml

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:

exporters:
  jaeger:
    endpoint: jaeger:14250
    tls:
      insecure: true

  prometheus:
    endpoint: "0.0.0.0:8889"

  logging:
    loglevel: debug

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [jaeger, logging]

    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [prometheus, logging]

    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [logging]

prometheus.yml

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'otel-collector'
    static_configs:
      - targets: ['otel-collector:8889']

1. 安装依赖

  composer require open-telemetry/sdk open-telemetry/exporter-otlp

2. 启动服务

 docker-compose up -d

3. 运行示例

php opentelemetry_demo.php

4. 查看结果

Jaeger UI (Traces): http://localhost:16686

Prometheus (Metrics): http://localhost:9090

Grafana (可视化): http://localhost:3000

核心概念:

  • Traces - 分布式追踪,查看请求链路
  • Metrics - 指标监控,统计计数、延迟等
  • Logs - 日志记录,结构化日志

完成!我创建了完整的 OpenTelemetry 标准化案例:

文件说明:

  1. opentelemetry_demo.php - 完整版,包含 Traces、Metrics、Logs 三大支柱

  2. docker-compose.yml - 一键启动所有服务

  3. otel-collector-config.yaml - Collector 配置

  4. prometheus.yml - Prometheus 配置

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐