コンテンツにスキップ

テレメトリ:OpenTelemetry ブリッジと no-op フォールバック

テレメトリモジュールは、エンジン向けのオプションの OpenTelemetry ブリッジです。OpenTelemetry SDK がインストールされている場合は、サニタイズ済みの属性とともにスパンとメトリクスを発行します。インストールされていない場合は、完全な no-op の tracer オブジェクトと meter オブジェクト一式により、インストルメンテーションの呼び出しは有効なままコストゼロで維持されます。そのため、インストルメンテーションをコードパスに残しておいても常に安全です。

Terminal window
composer require nextpdf/core:^3

設計目標は、OTel が存在しない場合にゼロコストで済む可観測性です。エンジンのホットパスは、tracer と meter を無条件に呼び出します。それらの呼び出しが何かを実行するかどうかは、各呼び出し箇所の条件分岐ではなく、ランタイムによって決まります。

OpenTelemetryInterceptor がブリッジを担います。isAvailable() は、OTel SDK が存在するかどうかを示します。startSpan(string $name, array $attributes = []) / endSpan(?object $span) はトレース対象の操作を囲み、recordMetric() はカウンターまたはゲージの値を記録します。OTel が存在しない場合、インターセプターは利用不可であることを示し、呼び出しは不活性になります。TelemetryBridge は、インターセプターをエンジンの観測ポイントに接続します。

AttributeSanitizer は安全性を担う層です。sanitize(array $attributes) は、属性マップがプロセス外へ出る前にスクラブします。テレメトリ属性は偶発的な PII 流出の典型的な経路であるため、サニタイズは付け足しではなく契約の一部です。これは @since 2.3.0 で、インターセプターとブリッジも同様です。

NullTracerNullSpanBuilderNullSpanNullMeterNullCounter、および NullHistogram が no-op フォールバックです。これらは OTel SDK が公開するものと同じ形状を実装します。spanBuilder()setAttribute()(チェーン可能)、startSpan()end()createHistogram()createUpDownCounter()add()record() ですが、何も行いません。フォールバックが完全であるため、インストルメント化されたコードは可用性に応じて分岐する必要がありません。tracer を呼び出すと、no-op がその呼び出しを吸収します。

クラス主なメンバー役割
OpenTelemetryInterceptorisAvailable(), startSpan(), endSpan(), recordMetric()OTel の span/metric ブリッジ(@since 2.3.0
TelemetryBridgeエンジンへの接続インターセプターを観測ポイントに接続(@since 2.3.0
AttributeSanitizersanitize(array $attributes): arrayPII に安全な属性スクラバー(@since 2.3.0
NullTracerspanBuilder(string $name): NullSpanBuilderno-op の tracer
NullSpanBuildersetAttribute(), startSpan(): NullSpanno-op の span builder(チェーン可能)
NullSpanend()no-op の span
NullMetercreateHistogram(), createUpDownCounter()no-op の meter
NullCounter / NullHistogramadd(), record()no-op のインストルメント

完全な PHPDoc テーブルを確認するには、composer docs:generate-api-php -- --module=Telemetry を実行してください。

ソース:examples/33-opentelemetry-observability.php

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Telemetry\OpenTelemetryInterceptor;
$otel = new OpenTelemetryInterceptor(/* optional OTel tracer/meter */);
$span = $otel->startSpan('pdf.render', ['doc.pages' => 12]);
// ... render work ...
$otel->endSpan($span);
$otel->recordMetric('pdf.render.bytes', 482_113, ['profile' => 'pdfa4']);

OTel SDK が存在しない場合、上記の呼び出しはすべて no-op です。コードは同じままで、コストはゼロです。

呼び出し元が提供したメタデータがスパンに漏れないように、サニタイズ済みの属性でレンダリングをラップします。

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Telemetry\AttributeSanitizer;
use NextPDF\Telemetry\OpenTelemetryInterceptor;
final readonly class InstrumentedRenderer
{
public function __construct(
private OpenTelemetryInterceptor $otel,
private AttributeSanitizer $sanitizer,
) {}
/**
* @param callable():string $render Returns the rendered PDF bytes.
* @param array<string, mixed> $attributes Caller-supplied span attributes.
*/
public function render(callable $render, array $attributes): string
{
$span = $this->otel->startSpan('pdf.render', $this->sanitizer->sanitize($attributes));
try {
return $render();
} finally {
$this->otel->endSpan($span);
}
}
}
  • no-op フォールバックは設計上完全です。「処理を節約するため」にインストルメンテーションを isAvailable() でガードしないでください。no-op はすでにコストゼロであり、ガードすると、この設計が取り除こうとしている分岐を追加してしまいます。
  • 呼び出し元が提供した属性は、スパンやメトリクスに渡す前に必ず AttributeSanitizer に通してください。テレメトリ属性は偶発的な PII 流出の経路です。
  • endSpan(null) は有効です。null のスパンは no-op のケースとして扱われます。すべての startSpan()finally 内の endSpan() と対にしてください。
  • NullSpanBuilder::setAttribute() はメソッドチェーン用に static を返します。チェーンは no-op では不活性ですが、これはバグではなく意図的な動作です。
  • 再現性プロファイルは structural です。スパンはタイムスタンプとトレース ID を保持するため、2 回の実行ではこれらのフィールドが異なります。

OTel が存在しない場合、発生するのは no-op へのメソッド呼び出しだけで、実質的にコストはありません。存在する場合、コストはこのモジュールではなく OTel SDK 側で発生します。ブリッジは属性のサニタイズを追加しますが、そのコストは属性数に対して線形です。performance_budget の 1500 ms ウォール / 64 MB ピークはエンジンの基準値であり、テレメトリの SLA ではありません。

テレメトリは、データを外部へ送出する境界面です。AttributeSanitizer は、機密情報や PII をスパンとメトリクスから排除するための制御です。呼び出し元の影響を受けるすべての属性で、サニタイズを必須として扱ってください。これは、安全なテレメトリに対するプロジェクト上の義務です。OTel エクスポーターは、データを外部バックエンドに送信します。そのバックエンドとの境界は信頼境界です。そのエンドポイントと認証情報は、コミット済みの設定ではなくシークレットマネージャーから構成してください。スパンとメトリクスのデータは、ログシンクに到達すると想定すべきです。その前提でスクラブしてください。エンジンの脅威モデルについては /modules/core/security/ を参照してください。

このモジュールは、PDF 仕様について規範的な主張を一切行いません。これは OpenTelemetry データモデルへのブリッジであり、PDF の条項ではなく外部の可観測性仕様に関するものです。no-op フォールバックは OTel API サーフェスを反映するため、インストルメント化されたコードは移植可能です。これは API 互換性の性質であり、PDF 準拠の表明ではありません。エンジンの準拠は、/modules/core/conformance/ に記載されたオラクルとゴールデンスイートによって検証されます。