performance-x/opentelemetry-php-instrumentation-trait 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

performance-x/opentelemetry-php-instrumentation-trait

Composer 安装命令:

composer require performance-x/opentelemetry-php-instrumentation-trait

包简介

A trait to simplify creating OpenTelemetry instrumentations for PHP classes and interfaces

README 文档

README

A trait to simplify creating OpenTelemetry instrumentations for PHP classes, interfaces, and functions.

Installation

composer require performance-x/opentelemetry-php-instrumentation-trait

Usage

The trait is designed to be used in instrumentation classes that register OpenTelemetry hooks for specific targets.

<?php
namespace OpenTelemetry\Contrib\Instrumentation\Drupal;

use Drupal\Core\Cache\CacheBackendInterface;
use OpenTelemetry\API\Trace\SpanKind;
use PerformanceX\OpenTelemetry\Instrumentation\InstrumentationTrait;

class CacheBackendInstrumentation {
  use InstrumentationTrait;

  public static function register(): void {
    // Create instance with name and prefix
    $instrumentation = self::create(
      name: 'io.opentelemetry.contrib.php.drupal',
      prefix: 'drupal.cache',
      className: CacheBackendInterface::class
    );

    // Or with custom span kind
    $instrumentation = self::create(
      name: 'io.opentelemetry.contrib.php.drupal',
      prefix: 'drupal.cache',
      spanKind: SpanKind::KIND_CLIENT,
      className: CacheBackendInterface::class
    );

    // Or with pre-configured instrumentation
    $instrumentation = self::create(
      instrumentation: new CachedInstrumentation('custom.name'),
      prefix: 'drupal.cache',
      className: CacheBackendInterface::class
    );

    // Register method hooks
    $instrumentation
      ->helperHook(
        'get',
        ['cid'],
        'returnValue'
      )
      ->helperHook(
        'set',
        ['cid', 'data', 'expire', 'tags'],
        'returnValue',
        preHandler: function($spanBuilder, $object, array $params, $class, $function, $filename, $lineno) {
          $spanBuilder->setAttribute($this->getAttributeName('ttl'), $params[2] ?? 0);
        },
        postHandler: function($span, $object, array $params, $returnValue, $exception) {
          $span->setAttribute($this->getAttributeName('success'), $returnValue !== FALSE);
        }
      );
  }
}

Features

  • Easy initialization of OpenTelemetry instrumentation
  • Support for both class methods and standalone functions
  • Configurable span kind (defaults to INTERNAL)
  • Automatic prefix for all span attributes via getAttributeName()
  • Parameter mapping to span attributes
  • Support for pre and post handlers with span access
  • Automatic exception handling
  • Return value capturing
  • Code location attributes (function, namespace, file, line)

Configuration Options

The create() method accepts:

  • instrumentation: Optional pre-configured instrumentation instance
  • prefix: Optional prefix for all span attributes
  • spanKind: Kind of spans to create (default: INTERNAL)
  • className: Optional target class name
  • name: Name of the instrumentation if no instrumentation instance provided

At least one of instrumentation or name must be provided.

Hook Configuration

The helperHook() method accepts:

  • methodName: The method or function to hook
  • paramMap: Array of parameters to capture as attributes
  • returnValueKey: Optional key for the return value attribute
  • preHandler: Optional callback for custom span building
  • postHandler: Optional callback for custom span finishing
  • className: Optional override of target class name

Dynamic Span Names

The trait supports updating span names dynamically during span creation. This is particularly useful when the span name depends on runtime information:

$instrumentation->helperHook(
  'save',
  ['entity'],
  preHandler: function($spanBuilder, $object, array $params) {
    $entity = $params[0];
    // Instead of directly setting the name (which isn't possible at this stage),
    // use the UPDATE_NAME attribute
    $spanBuilder->setAttribute(
      static::UPDATE_NAME,
      sprintf(
        'Entity save (%s:%s)',
        $entity->getEntityTypeId(),
        $entity->isNew() ? 'new' : $entity->id()
      )
    );
  }
);

// When called with a new article entity:
$entity->save();
// Creates span with name: "Entity save (article:new)"

// When called with an existing article entity:
$entity->save();
// Creates span with name: "Entity save (article:123)"

This approach is necessary because span names can only be set during span creation, but sometimes the desired name depends on runtime information available in the pre-handler. By setting the X-PerformanceX-OpenTelemetry-Update-Name attribute (available as InstrumentationTrait::UPDATE_NAME), the trait will automatically update the span name during creation.

Parameter Mapping

The paramMap argument in helperHook() supports several ways to map method parameters to span attributes:

Value Handling

The trait automatically handles different parameter types appropriately. For example, with Drupal's cache set method:

/**
* @see \Drupal\Core\Cache\CacheBackendInterface::set()
*/
$instrumentation->helperHook(
    'set',
    [
        'cid',           // String cache ID stored as-is
        'data',          // Complex data will be JSON encoded
        'expire',        // Integer timestamp stored as-is
        'tags',          // Array will be JSON encoded
    ],
    'returnValue'
);

// When called with:
$cache->set('my-key', ['foo' => 'bar'], time() + 3600, ['tag1', 'tag2']);

// Creates span attributes:
// drupal.cache.cid = "my-key"
// drupal.cache.data = "{\"foo\":\"bar\"}"
// drupal.cache.expire = 1677589324
// drupal.cache.tags = "[\"tag1\",\"tag2\"]"

Simple Parameter Mapping

// Maps the 'cid' parameter to 'drupal.cache.cid' attribute
$instrumentation->helperHook(
    'get',
    ['cid'],  // Parameter name becomes the attribute name
);

// When called with:
$cache->get('my-key');

// Creates span attribute:
// drupal.cache.cid = "my-key"

Custom Attribute Names

// Maps the 'cid' parameter to 'drupal.cache.key' attribute
$instrumentation->helperHook(
    'get',
    ['cid' => 'key'],  // Parameter name => custom attribute name
);

// When called with:
$cache->get('my-key');

// Creates span attribute:
// drupal.cache.key = "my-key"

Multiple Parameters with Custom Names

$instrumentation->helperHook(
    'set',
    [
        'cid' => 'key',        // Will be prefixed: 'drupal.cache.key'
        'data' => 'value',     // Will be prefixed: 'drupal.cache.value'
        'expire' => 'ttl',     // Will be prefixed: 'drupal.cache.ttl'
        'tags' => 'metadata'   // Will be prefixed: 'drupal.cache.metadata'
    ],
);

// When called with:
$cache->set('my-key', ['foo' => 'bar'], time() + 3600, ['tag1', 'tag2']);

// Creates span attributes:
// drupal.cache.key = "my-key"
// drupal.cache.value = "{\"foo\":\"bar\"}"
// drupal.cache.ttl = 1677589324
// drupal.cache.metadata = "[\"tag1\",\"tag2\"]"

Return Value Handling

The trait can capture method return values. For example, with Drupal's cache get method:

/**
* @see \Drupal\Core\Cache\CacheBackendInterface::get()
* Returns object|false The cache item or FALSE on failure.
*/
$instrumentation->helperHook(
    'get',
    ['cid'],
    'returnValue'  // Capture the return value under this attribute name
);

// When called with:
$cache->get('my-key');  // Returns a cache object: { data: 'cached value', expire: 1677589324 }

// Creates span attributes:
// drupal.cache.cid = "my-key"
// drupal.cache.returnValue = "{\"data\":\"cached value\",\"expire\":1677589324}"

// When called with a missing key:
$cache->get('missing-key');  // Returns FALSE

// Creates span attributes:
// drupal.cache.cid = "missing-key"
// drupal.cache.returnValue = false

Combined with Custom Handlers

$instrumentation->helperHook(
    'get',
    ['cid'],  // Map the cache ID parameter
    'returnValue',
    preHandler: function($spanBuilder, $object, array $params, $class, $function, $filename, $lineno) {
        // Add timestamp when cache was checked
        $spanBuilder->setAttribute(
            $this->getAttributeName('custom_time'),
            time()
        );
    },
    postHandler: function($span, $object, array $params, $returnValue, $exception) {
        // Track if this was a cache hit
        $span->setAttribute(
            $this->getAttributeName('hit'),
            $returnValue !== FALSE
        );
    }
);

// When called with:
$cache->get('my-key');  // Returns cached data

// Creates span attributes:
// drupal.cache.cid = "my-key"
// drupal.cache.custom_time = 1677589324
// drupal.cache.hit = true
// drupal.cache.returnValue = "{\"data\":\"cached value\",\"expire\":1677589324}"

Error Handling

The trait automatically handles exceptions, but you can customize error handling using post handlers.

Note: While these examples show detailed error capturing, in practice, OpenTelemetry tracing is best combined with proper logging. The trace ID can be added to log entries, allowing you to correlate traces with detailed log messages. This provides better observability than putting log-like information into spans.

/**
* @see \Drupal\Core\Cache\CacheBackendInterface::get()
*/
$instrumentation->helperHook(
    'get',
    ['cid'],
    'returnValue',
    postHandler: function($span, $object, array $params, $returnValue, ?Throwable $exception) {
        if ($exception) {
            // Add minimal error context - detailed information should go to logs
            $span->setAttribute(
                $this->getAttributeName('error_context'),
                [
                    'cache_backend' => get_class($object),
                    'attempted_key' => $params[0] ?? null,
                ]
            );
            // Simple error categorization helps with metrics
            if ($exception instanceof \InvalidArgumentException) {
                $span->setAttribute($this->getAttributeName('error_type'), 'validation');
            } elseif ($exception instanceof \RuntimeException) {
                $span->setAttribute($this->getAttributeName('error_type'), 'connection');
            }
        } elseif ($returnValue === FALSE) {
            // Track cache misses for performance monitoring
            $span->setAttribute($this->getAttributeName('cache_miss'), true);
        }
    }
);

// Error cases are automatically handled:
try {
    $cache->get(null);  // Invalid argument
} catch (\InvalidArgumentException $e) {
    // Span will include:
    // drupal.cache.cid = null
    // exception.message = "Cache ID must be a string"
    // exception.type = "InvalidArgumentException"
    // status_code = "ERROR"
    // drupal.cache.error_type = "validation"
    // drupal.cache.error_context = "{\"cache_backend\":\"Drupal\\Core\\Cache\\DatabaseBackend\",\"attempted_key\":null}"
}

try {
    $cache->get('my-key');  // Connection error
} catch (\RuntimeException $e) {
    // Span will include:
    // drupal.cache.cid = "my-key"
    // exception.message = "Failed to connect to cache backend"
    // exception.type = "RuntimeException"
    // status_code = "ERROR"
    // drupal.cache.error_type = "connection"
    // drupal.cache.error_context = "{\"cache_backend\":\"Drupal\\Core\\Cache\\DatabaseBackend\",\"attempted_key\":\"my-key\"}"
}

Requirements

  • PHP 8.2+
  • OpenTelemetry PHP SDK

License

MIT License

performance-x/opentelemetry-php-instrumentation-trait 适用场景与选型建议

performance-x/opentelemetry-php-instrumentation-trait 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 112 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 01 月 24 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「performance」 「monitoring」 「instrumentation」 「tracing」 「opentelemetry」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 performance-x/opentelemetry-php-instrumentation-trait 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 performance-x/opentelemetry-php-instrumentation-trait 我们能提供哪些服务?
定制开发 / 二次开发

基于 performance-x/opentelemetry-php-instrumentation-trait 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 112
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 14
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-01-24