Telemetria: most OpenTelemetry i awaryjna implementacja no-op
W skrócie
Dział zatytułowany „W skrócie”Moduł Telemetry to opcjonalny most łączący silnik z OpenTelemetry (OTel) SDK. Gdy SDK jest zainstalowany, emituje spany i metryki z atrybutami po sanityzacji. Gdy SDK jest nieobecny, kompletny zestaw obiektów no-op dla tracera i miernika sprawia, że wywołania instrumentacji pozostają poprawne i praktycznie bezkosztowe. Instrumentację można bezpiecznie pozostawić w ścieżce kodu.
Instalacja
Dział zatytułowany „Instalacja”composer require nextpdf/core:^3Przegląd koncepcyjny
Dział zatytułowany „Przegląd koncepcyjny”Celem projektu jest obserwowalność przy zerowym koszcie, gdy SDK jest nieobecny. Gorące ścieżki silnika wywołują tracer i miernik bez wcześniejszych sprawdzeń. To, czy te wywołania wykonują pracę, zależy od środowiska uruchomieniowego, a nie od warunku w każdym miejscu wywołania.
OpenTelemetryInterceptor pełni rolę mostu. isAvailable() informuje, czy SDK OTel jest obecny. startSpan(string $name, array $attributes = []) / endSpan(?object $span) obejmują operację śledzeniem, a recordMetric() zapisuje wartość licznika lub wskaźnika. Gdy OTel jest nieobecny, interceptor informuje o niedostępności, a wywołania pozostają bezczynne. TelemetryBridge łączy interceptor z punktami obserwacji silnika.
AttributeSanitizer jest warstwą bezpieczeństwa. sanitize(array $attributes) oczyszcza mapę atrybutów, zanim opuści proces. Atrybuty telemetrii to częsty kanał przypadkowego ujawnienia informacji umożliwiających identyfikację osoby (PII), dlatego sanityzacja jest częścią kontraktu, a nie dodatkiem. Sanitizer, interceptor i most są @since 2.3.0.
NullTracer, NullSpanBuilder, NullSpan, NullMeter, NullCounter i NullHistogram stanowią awaryjną implementację no-op. Odwzorowują kształt wywołań udostępnianych przez SDK OTel: spanBuilder(), setAttribute() (łańcuchowe), startSpan(), end(), createHistogram(), createUpDownCounter(), add() i record(). Nie wykonują żadnej pracy. Ponieważ awaryjna implementacja jest kompletna, instrumentowany kod nie rozgałęzia się w zależności od dostępności; wywołuje tracer, a no-op przejmuje wywołanie bez efektu.
Powierzchnia API
Dział zatytułowany „Powierzchnia API”| Klasa | Kluczowe składowe | Rola |
|---|---|---|
OpenTelemetryInterceptor | isAvailable(), startSpan(), endSpan(), recordMetric() | Most spanów i metryk OTel (@since 2.3.0) |
TelemetryBridge | połączenia z silnikiem | Łączy interceptor z punktami obserwacji silnika (@since 2.3.0) |
AttributeSanitizer | sanitize(array $attributes): array | Oczyszcza atrybuty z uwzględnieniem bezpieczeństwa PII (@since 2.3.0) |
NullTracer | spanBuilder(string $name): NullSpanBuilder | Tracer no-op |
NullSpanBuilder | setAttribute(), startSpan(): NullSpan | Konstruktor spanów no-op (łańcuchowy) |
NullSpan | end() | Span no-op |
NullMeter | createHistogram(), createUpDownCounter() | Miernik no-op |
NullCounter / NullHistogram | add(), record() | Instrumenty no-op |
Uruchom composer docs:generate-api-php -- --module=Telemetry, aby wygenerować pełną tabelę PHPDoc.
Przykład kodu — szybki start
Dział zatytułowany „Przykład kodu — szybki start”Źródło: 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']);Gdy SDK OTel jest nieobecny, każde z powyższych wywołań jest no-op. Kod pozostaje identyczny, a koszt wynosi zero.
Przykład kodu — produkcja
Dział zatytułowany „Przykład kodu — produkcja”Opakuj operację renderowania, używając atrybutów po sanityzacji, aby metadane dostarczone przez wywołującego nie mogły wyciekać do spanu.
<?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); } }}Przypadki brzegowe i pułapki
Dział zatytułowany „Przypadki brzegowe i pułapki”- Awaryjna implementacja no-op jest z założenia kompletna. Nie osłaniaj instrumentacji wywołaniem
isAvailable()„dla oszczędności pracy”. No-op i tak nic nie kosztuje, a taka osłona dodaje rozgałęzienie, które ten projekt eliminuje. - Zawsze przepuszczaj atrybuty dostarczone przez wywołującego przez
AttributeSanitizer, zanim dołączysz je do spanu lub metryki. Atrybuty telemetrii to przypadkowy kanał ujawniania PII. endSpan(null)jest poprawne: span o wartości null to przypadek no-op. KażdestartSpan()paruj zendSpan()w blokufinally.NullSpanBuilder::setAttribute()zwracastaticna potrzeby łańcuchowania. W trybie no-op łańcuch jest z założenia bezczynny.- Profil odtwarzalności jest
structural: spany zawierają znaczniki czasu i identyfikatory śladu, dlatego dwa uruchomienia różnią się w tych polach.
Wydajność
Dział zatytułowany „Wydajność”Gdy OTel jest nieobecny, koszt ogranicza się do wywołania metody trafiającego do no-op i jest praktycznie zerowy. Gdy OTel jest obecny, koszt pochodzi z SDK OTel; most dodaje sanityzację atrybutów, która jest liniowa względem liczby atrybutów. Wartość performance_budget wynosząca 1500 ms czasu zegarowego / 64 MB wartości szczytowej to referencyjny budżet silnika, a nie gwarancja poziomu usług (SLA) dla telemetrii.
Uwagi dotyczące bezpieczeństwa
Dział zatytułowany „Uwagi dotyczące bezpieczeństwa”Telemetria jest powierzchnią wyprowadzania danych. AttributeSanitizer utrzymuje sekrety i PII poza spanami i metrykami. Traktuj sanityzację jako obowiązkową dla każdego atrybutu, na który wpływa wywołujący; w tym projekcie jest to wymóg bezpiecznej telemetrii. Eksporter OTel wysyła dane do zewnętrznego zaplecza, a to zaplecze stanowi granicę zaufania. Konfiguruj jego punkt końcowy i poświadczenia z menedżera sekretów, a nie z konfiguracji zapisanej w repozytorium. Załóż, że dane spanów i metryk trafiają do odbiornika logów, i odpowiednio je oczyszczaj. Zobacz model zagrożeń silnika w /modules/core/security/.
Zgodność
Dział zatytułowany „Zgodność”Ten moduł nie formułuje żadnego normatywnego twierdzenia dotyczącego specyfikacji formatu Portable Document Format (PDF). Stanowi most do modelu danych OpenTelemetry, zewnętrznej specyfikacji obserwowalności, a nie do klauzuli PDF. Awaryjna implementacja no-op odwzorowuje powierzchnię API OpenTelemetry, aby instrumentowany kod pozostał przenośny. To właściwość zgodności API, a nie deklaracja zgodności z PDF. Zgodność silnika jest walidowana przez wyrocznie i zestawy wzorcowe opisane w /modules/core/conformance/.
Zobacz także
Dział zatytułowany „Zobacz także”- Moduł Observability — szersza powierzchnia stanu uruchomieniowego.
- Moduł Performance — diagnostyka pamięci, która współgra z telemetrią.
- Contracts / Observability — kontrakty ustrukturyzowanych wyjątków i degradacji.
- Model bezpieczeństwa silnika