Telemetry: บริดจ์ OpenTelemetry และตัวเลือกสำรองแบบ no-op
ภาพรวมโดยย่อ
หัวข้อที่มีชื่อว่า “ภาพรวมโดยย่อ”โมดูล Telemetry คือบริดจ์แบบเลือกใช้ของเอนจินสำหรับเชื่อมต่อกับ software development kit (SDK) ของ OpenTelemetry (OTel) เมื่อติดตั้ง SDK แล้ว โมดูลจะปล่อย span และ metric พร้อมแอตทริบิวต์ที่ผ่านการล้างข้อมูลแล้ว เมื่อไม่มี SDK ชุดอ็อบเจกต์ tracer และ meter แบบ no-op ที่ครบถ้วนจะทำให้การเรียกใช้เครื่องมือวัด (instrumentation) ยังคงทำงานได้โดยแทบไม่มีต้นทุน คุณจึงปล่อยให้เครื่องมือวัดอยู่ในเส้นทางโค้ดได้อย่างปลอดภัย
การติดตั้ง
หัวข้อที่มีชื่อว่า “การติดตั้ง”composer require nextpdf/core:^3ภาพรวมเชิงแนวคิด
หัวข้อที่มีชื่อว่า “ภาพรวมเชิงแนวคิด”เป้าหมายของการออกแบบคือการสังเกตการณ์ (observability) ที่ไม่มีต้นทุนเมื่อไม่มี SDK เส้นทางที่ทำงานบ่อย (hot path) ของเอนจินจะเรียก tracer และ meter โดยไม่ตรวจสอบล่วงหน้า การเรียกเหล่านั้นจะทำงานจริงหรือไม่ขึ้นอยู่กับ runtime ไม่ใช่เงื่อนไขที่จุดเรียกแต่ละจุด
OpenTelemetryInterceptor คือบริดจ์ isAvailable() รายงานว่ามี OTel SDK อยู่หรือไม่ startSpan(string $name, array $attributes = []) / endSpan(?object $span) จะครอบการดำเนินการที่ติดตาม (traced operation) และ recordMetric() จะบันทึกค่าตัวนับ (counter) หรือค่าเกจ (gauge) เมื่อไม่มี OTel interceptor จะรายงานว่าไม่พร้อมใช้งาน และการเรียกต่าง ๆ จะไม่ทำงาน TelemetryBridge เชื่อม interceptor เข้ากับจุดสังเกตการณ์ของเอนจิน
AttributeSanitizer คือชั้นความปลอดภัย sanitize(array $attributes) จะล้างแผนที่แอตทริบิวต์ก่อนที่ข้อมูลจะออกจากกระบวนการ แอตทริบิวต์ของ telemetry เป็นช่องทางที่ข้อมูลซึ่งระบุตัวบุคคลได้ (personally identifiable information หรือ PII) มักหลุดรอดโดยไม่ตั้งใจ ดังนั้นการล้างข้อมูลจึงเป็นส่วนหนึ่งของสัญญา ไม่ใช่ส่วนเสริม ตัวล้างข้อมูล interceptor และบริดจ์มีสถานะ @since 2.3.0
NullTracer, NullSpanBuilder, NullSpan, NullMeter, NullCounter, และ NullHistogram คือตัวเลือกสำรองแบบ no-op อ็อบเจกต์เหล่านี้ตรงกับรูปแบบการเรียกที่ OTel SDK เปิดเผย: spanBuilder(), setAttribute() (เชื่อมต่อเป็นลูกโซ่ได้), startSpan(), end(), createHistogram(), createUpDownCounter(), add(), และ record() อ็อบเจกต์เหล่านี้ไม่ทำอะไรเลย เนื่องจากตัวเลือกสำรองมีครบถ้วน โค้ดที่ติดตั้งเครื่องมือวัดจึงไม่ต้องแยกสาขาตามความพร้อมใช้งาน เพียงเรียก tracer แล้ว no-op จะรับการเรียกนั้นไว้
พื้นผิว API
หัวข้อที่มีชื่อว่า “พื้นผิว API”| คลาส | สมาชิกสำคัญ | บทบาท |
|---|---|---|
OpenTelemetryInterceptor | isAvailable(), startSpan(), endSpan(), recordMetric() | บริดจ์ span และ metric ของ OTel (@since 2.3.0) |
TelemetryBridge | การเชื่อมต่อกับเอนจิน | เชื่อม interceptor เข้ากับจุดสังเกตการณ์ของเอนจิน (@since 2.3.0) |
AttributeSanitizer | sanitize(array $attributes): array | ล้างแอตทริบิวต์เพื่อความปลอดภัยด้าน PII (@since 2.3.0) |
NullTracer | spanBuilder(string $name): NullSpanBuilder | tracer แบบ no-op |
NullSpanBuilder | setAttribute(), startSpan(): NullSpan | ตัวสร้าง span แบบ no-op (เชื่อมต่อเป็นลูกโซ่ได้) |
NullSpan | end() | span แบบ no-op |
NullMeter | createHistogram(), createUpDownCounter() | meter แบบ no-op |
NullCounter / NullHistogram | add(), record() | instrument แบบ no-op |
รัน composer docs:generate-api-php -- --module=Telemetry เพื่อสร้างตาราง PHPDoc ฉบับเต็ม
ตัวอย่างโค้ด — เริ่มต้นอย่างรวดเร็ว
หัวข้อที่มีชื่อว่า “ตัวอย่างโค้ด — เริ่มต้นอย่างรวดเร็ว”ที่มา: 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 โค้ดยังคงเหมือนเดิมและมีต้นทุนเป็นศูนย์
ตัวอย่างโค้ด — การใช้งานจริง
หัวข้อที่มีชื่อว่า “ตัวอย่างโค้ด — การใช้งานจริง”ครอบการดำเนินการเรนเดอร์ด้วยแอตทริบิวต์ที่ผ่านการล้างข้อมูลแล้ว เพื่อป้องกันไม่ให้ข้อมูลเมทาดาทาที่ผู้เรียกระบุมาหลุดเข้าไปใน span
<?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เสมอ ก่อนที่จะแนบเข้ากับ span หรือ metric แอตทริบิวต์ของ telemetry เป็นช่องทางหลุดรอดของ PII โดยไม่ตั้งใจ endSpan(null)ใช้งานได้: span ที่เป็น null คือกรณี no-op จับคู่ทุกstartSpan()กับendSpan()ในfinallyNullSpanBuilder::setAttribute()คืนค่าstaticเพื่อให้เชื่อมต่อเป็นลูกโซ่ได้ ภายใต้ no-op ลูกโซ่จะไม่ทำงานโดยการออกแบบ- โปรไฟล์ความสามารถในการทำซ้ำ (reproducibility) เป็นแบบ
structural: span มีการประทับเวลาและตัวระบุการติดตาม (trace identifier) ดังนั้นการรันสองครั้งจะต่างกันในฟิลด์เหล่านั้น
ประสิทธิภาพ
หัวข้อที่มีชื่อว่า “ประสิทธิภาพ”เมื่อไม่มี OTel ต้นทุนคือการเรียกเมท็อดเข้าสู่ no-op ซึ่งแทบไม่มีต้นทุน เมื่อมี OTel ต้นทุนมาจาก OTel SDK ส่วนบริดจ์จะเพิ่มการล้างแอตทริบิวต์ ซึ่งแปรผันเชิงเส้นตามจำนวนแอตทริบิวต์ performance_budget ที่ 1500 ms wall / 64 MB peak คืองบประมาณอ้างอิงของเอนจิน ไม่ใช่ข้อตกลงระดับการให้บริการ (service-level agreement หรือ SLA) ของ telemetry
หมายเหตุด้านความปลอดภัย
หัวข้อที่มีชื่อว่า “หมายเหตุด้านความปลอดภัย”telemetry เป็นพื้นผิวการส่งออกข้อมูล (data-egress surface) AttributeSanitizer จะกันความลับและ PII ไม่ให้เข้าไปใน span และ metric ถือว่าการล้างข้อมูลเป็นข้อบังคับสำหรับแอตทริบิวต์ใด ๆ ที่ได้รับอิทธิพลจากผู้เรียก นี่คือพันธะด้าน telemetry ที่ปลอดภัยของโครงการ ตัวส่งออก (exporter) ของ OTel จะส่งข้อมูลไปยังแบ็กเอนด์ภายนอก และแบ็กเอนด์นั้นเป็นขอบเขตความเชื่อถือ (trust boundary) กำหนดค่า endpoint และข้อมูลรับรองของแบ็กเอนด์จากตัวจัดการความลับ (secret manager) ไม่ใช่จากคอนฟิกที่คอมมิตไว้ ให้สมมติว่าข้อมูล span และ metric ไปถึงปลายทางบันทึก (log sink) และล้างข้อมูลให้สอดคล้องกัน ดูแบบจำลองภัยคุกคาม (threat model) ของเอนจินได้ที่ /modules/core/security/
ความสอดคล้อง
หัวข้อที่มีชื่อว่า “ความสอดคล้อง”โมดูลนี้ไม่ได้กล่าวอ้างเชิงบรรทัดฐานต่อข้อกำหนด Portable Document Format (PDF) โมดูลนี้เป็นบริดจ์ไปยังแบบจำลองข้อมูลของ OpenTelemetry ซึ่งเป็นข้อกำหนดด้านการสังเกตการณ์ภายนอก ไม่ใช่ข้อกำหนด (clause) ของ PDF ตัวเลือกสำรองแบบ no-op สะท้อนพื้นผิว application programming interface (API) ของ OpenTelemetry เพื่อให้โค้ดที่ติดตั้งเครื่องมือวัดยังคงพกพาได้ นั่นเป็นคุณสมบัติด้านความเข้ากันได้ของ API ไม่ใช่คำกล่าวความสอดคล้องของ PDF ความสอดคล้องของเอนจินได้รับการตรวจสอบโดยชุดทดสอบ oracle และ golden ที่อธิบายไว้ใน /modules/core/conformance/
ดูเพิ่มเติม
หัวข้อที่มีชื่อว่า “ดูเพิ่มเติม”- โมดูล Observability — พื้นผิวสถานะ runtime ที่กว้างกว่า
- โมดูล Performance — การวินิจฉัยหน่วยความจำที่ใช้คู่กับ telemetry
- Contracts / Observability — สัญญาด้านข้อยกเว้นเชิงโครงสร้างและการลดระดับการทำงาน
- แบบจำลองความปลอดภัยของเอนจิน