Salta ai contenuti

Osservare il rendering con OpenTelemetry

NextPDF include una strumentazione OpenTelemetry integrata: 10 span di traccia e 7 metriche lungo l’intero ciclo di vita di generazione del PDF. Il contratto è overhead nullo e zero configurazione quando l’SDK OTel è assente — nessun errore di autoload, nessuna penalizzazione delle prestazioni. Installando l’SDK e registrando globalmente un TracerProvider/MeterProvider, lo stesso codice esporta automaticamente. Un AttributeSanitizer basato su allowlist applica una Zero-Trust Data Policy, così la telemetria non trasporta mai contenuto del documento o PII.

Questa pagina completa, dal lato PHP-native, il materiale concettuale OpenTelemetry indipendente dal trasporto. Un esempio eseguibile e un test di supporto ne verificano il comportamento.

Terminal window
composer require nextpdf/core:^3

Core, da solo, fornisce la superficie di strumentazione sicura in modalità no-op. Per esportare dati live, aggiungere l’SDK e un exporter.

Terminal window
composer require open-telemetry/sdk:^1
composer require open-telemetry/exporter-otlp:^1 # or zipkin / prometheus

Esistono due punti di ingresso:

  • TelemetryBridge — una facade statica. isAvailable() controlla una sola volta la presenza di OTel e ne memorizza l’esito nella cache. startSpan() / endSpan() / recordMetric() usano un percorso di cortocircuito verso un no-op quando OTel è assente. Questo realizza il contratto a overhead nullo. Quando OTel è assente, queste chiamate si completano in molto meno di un microsecondo.
  • OpenTelemetryInterceptor — il percorso di integrazione con l’SDK. Traccia automaticamente i 10 span noti, registra le 7 metriche note e instrada ogni attributo attraverso AttributeSanitizer. Verifica la presenza dell’SDK in fase di costruzione e memorizza il risultato nella cache. Tutti i riferimenti alle classi OTel sono protetti da guard a runtime, così la classe si carica anche senza l’SDK. I limiti consigliati del BatchSpanProcessor (maxQueueSize=2048, maxExportBatchSize=512) sono esposti come accessor statici.

I 10 span: document.build, font.resolve, html.parse, writer.serialize, image.decode, layout.pass, barcode.encode, form.build, navigation.build, attachment.embed. Le 7 metriche: render.duration, render.page_count, render.warnings, render.memory_peak, render.file_size, render.font_count, render.image_count.

AttributeSanitizer opera esclusivamente su allowlist. Le chiavi consentite sono metadati strutturali come pdf.page_count, pdf.file_size_bytes, pdf.output_profile e nextpdf.tier. HTML grezzo, flussi di byte PDF, blob base64 e percorsi del filesystem vengono scartati incondizionatamente. Ciò risponde a due indicazioni delle linee guida NIST SP 800-92: la telemetria non deve trasportare contenuto sensibile e la riservatezza della telemetria è un controllo esplicito.

La superficie API è generata dal PHPDoc di NextPDF\Telemetry\TelemetryBridge, NextPDF\Telemetry\OpenTelemetryInterceptor e NextPDF\Telemetry\AttributeSanitizer. I membri principali utilizzati di seguito sono TelemetryBridge::isAvailable() / startSpan() / endSpan() / recordMetric(); OpenTelemetryInterceptor::knownSpans() / knownMetrics() / maxQueueSize() / maxExportBatchSize(); e AttributeSanitizer::sanitize().

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Telemetry\TelemetryBridge;
$span = TelemetryBridge::startSpan('document.build', [
'pdf.page_count' => 1,
'nextpdf.tier' => 'core',
]);
$doc = Document::createStandalone();
$doc->addPage();
$doc->setFont('helvetica', '', 12);
$doc->cell(0, 10, 'Observed render');
$pdf = $doc->getPdfData();
TelemetryBridge::recordMetric('render.file_size', strlen($pdf), []);
TelemetryBridge::endSpan($span); // null-safe when OTel is absent
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/out.pdf');

L’esempio completo mostra il percorso no-op a overhead nullo, perché viene eseguito con l’SDK assente. Verifica l’allowlist del sanitizer e rispetta il canale di output dell’harness. L’harness di riproducibilità esegue questo script due volte.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Telemetry\AttributeSanitizer;
use NextPDF\Telemetry\OpenTelemetryInterceptor;
use NextPDF\Telemetry\TelemetryBridge;
// Discover the surface — static, dependency-free, SDK-optional.
$spans = OpenTelemetryInterceptor::knownSpans();
$metrics = OpenTelemetryInterceptor::knownMetrics();
// Zero-Trust Data Policy: the sanitizer drops anything off the allowlist
// and anything that looks like a payload.
$sanitizer = new AttributeSanitizer();
$exported = $sanitizer->sanitize([
'pdf.page_count' => 1,
'pdf.output_profile' => 'PDF/A-4',
'document.raw_html' => '<html><body>secret</body></html>', // dropped
'source.path' => '/var/secret/invoice.pdf', // dropped
]);
$span = TelemetryBridge::startSpan('document.build', [
'pdf.page_count' => 1,
'nextpdf.tier' => 'core',
]);
$doc = Document::createStandalone();
$doc->setTitle('Observability demo');
$doc->addPage();
$doc->setFont('helvetica', 'B', 16);
$doc->cell(0, 12, 'Observe rendering with OpenTelemetry', newLine: true);
$pdf = $doc->getPdfData();
TelemetryBridge::recordMetric('render.page_count', 1, []);
TelemetryBridge::recordMetric('render.file_size', strlen($pdf), []);
TelemetryBridge::endSpan($span);
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/out.pdf');
fwrite(STDERR, sprintf(
"spans=%d metrics=%d otel_available=%s sanitized_keys=%s\n",
count($spans),
count($metrics),
TelemetryBridge::isAvailable() ? 'yes' : 'no',
implode(',', array_keys($exported)),
));
  • La telemetria non interrompe mai il rendering. Sia il bridge sia l’interceptor assorbono i propri errori interni. Un exporter configurato male degrada l’osservabilità, mai l’output PDF. Evitare di racchiudere il codice di rendering in un catch che tratti un errore di telemetria come un errore di rendering.
  • endSpan(null) è sicuro. startSpan() restituisce null quando OTel è assente e endSpan() accetta null come no-op. Abbinarli sempre e non creare mai diramazioni in base al valore restituito.
  • Le metriche richiedono un MeterProvider registrato. Se è registrato solo un TracerProvider, gli span vengono esportati ma le metriche vengono ignorate silenziosamente. Le metriche sono indicative. Registrare entrambi i provider per una copertura completa.
  • Il sanitizer opera esclusivamente su allowlist. Una nuova chiave di attributo che non è presente nell’allowlist non verrà esportata. Questo comportamento è intenzionale. Estendere l’allowlist nel motore senza aggirare il sanitizer.
  • Propagazione del W3C Trace Context. La propagazione delle tracce tra servizi usa gli header traceparent/tracestate del W3C Trace Context. La gestione è affidata ai propagator dell’SDK OTel, non a NextPDF. La Recommendation W3C Trace Context non è inclusa nel corpus di verifica, perciò questa nota sulla propagazione è RAG-unresolved ed è formulata come indicazione di integrazione anziché come affermazione normativa. Vedere il sidecar.
  • Avvertenza sulla riproducibilità. Il rendering produce un documento il cui /ID e la cui data di modifica vengono rigenerati a ogni salvataggio (ISO 32000-2 §14.3). Il PDF acquisito viene confrontato con il profilo semantic, che copre solo l’AST strutturale e i metadati.
  • Percorso senza OTel: isAvailable() viene memorizzato nella cache dopo la prima chiamata. Le successive chiamate di span e metriche eseguono un singolo controllo booleano, seguito da un return. L’esempio strumentato viene eseguito fino al completamento con l’SDK assente.
  • Con OTel: i limiti del BatchSpanProcessor (maxQueueSize=2048, maxExportBatchSize=512) contengono l’uso di memoria sotto carico sostenuto e l’esportazione resta fuori dall’hot path.
  • Il performance_budget (wall_ms: 3000, peak_mb: 128) limita l’esecuzione dell’harness, non documenti arbitrari.
  • Questa ricetta copre la gap-list §4.3 per #33. In precedenza non esisteva alcun esempio PHP-native, ma solo la pagina concettuale in stile MCP. Sono stati creati un nuovo examples/33-opentelemetry-observability.php e il relativo tests/Cookbook/Php/ObserveWithOpenTelemetryRecipeTest.php di supporto.
  • La telemetria non deve trasportare contenuto del documento o PII. L’allowlist di AttributeSanitizer lo impone nel codice. HTML grezzo, flussi PDF, blob base64 e percorsi del filesystem vengono scartati. Ciò è in linea con le indicazioni di NIST SP 800-92 sul mantenere il contenuto sensibile fuori da log e telemetria e sul proteggere la riservatezza della telemetria.
  • Anche gli attributi aggiunti direttamente sono comunque soggetti all’allowlist. Resta responsabilità dell’utente non introdurre valori sensibili sotto una chiave consentita. Ad esempio, non inserire un identificatore utente in pdf.output_profile.
  • Il dettaglio diagnostico viene trasportato da chiavi strutturate, non da payload in formato libero. È la stessa disciplina che PSR-3 §1.2 applica al contesto dei log.
AffermazioneSpecificaClausolareference_id
La telemetria non deve trasportare contenuto sensibile; è richiesta la gestione delle PII.NIST SP 800-92§3
La riservatezza di telemetria/log è un controllo esplicito.NIST SP 800-92§3
A trasportare il dettaglio sono chiavi di contesto strutturate, non payload in formato libero.PSR-3§1.2
L’/ID e le date di output si rigenerano a ogni salvataggio → profilo semantic.ISO 32000-2§14.3

Questa ricetta descrive il comportamento della strumentazione ingegneristica. Non afferma alcuna certificazione di conformità. I riferimenti a NIST SP 800-92 sostengono l’intento di progettazione di assenza di contenuto nella telemetria, non un’affermazione di conformità.