ทำให้ OpenTelemetry ทำงานได้สำเร็จแล้ว แต่ทำไมมันถึงซับซ้อนขนาดนี้?
(iconsolutions.com)- คำขอจากลูกค้าให้ รองรับ OpenTelemetry ทำให้เห็นว่า observability ที่อิง Prometheus·Jaeger·OpenTracing เดิมนั้นไม่เหมือนกับความต้องการด้าน metrics·logs·traces ของ OTel เสียทีเดียว
- logs และ metrics ย้ายได้ค่อนข้างง่ายด้วยการเพิ่ม appender และการตั้งค่า แต่ distributed tracing ยากกว่ามาก เพราะ Spring และ Akka ต้องแชร์ trace context เดียวกันภายใน JVM เดียวกัน
- OTel และ Lightbend Telemetry/OpenTracing ใช้ Tracer API และการติดตั้ง SpanContext คนละแบบ ทำให้ทรานแซกชันเดียวกันถูกแยกออกเป็นคนละ trace
- วิธีแก้คือ inject context ของ OTel ลงใน Java
Map, extract ออกมาเป็น Jaeger SpanContext แล้วค่อย activate แบบแมนนวลด้วยGlobalExtendedTracer.get().local().activateContext()ของ Lightbend - OTel ช่วยเรื่องการทำมาตรฐาน observability ได้ แต่เมื่อผสมกับ instrumentation เดิมที่อิง Akka·Jaeger อาจจำเป็นต้องมี การเชื่อม context อย่างชัดเจน
สัญญาณ observability ที่ OTel พยายามรวมเข้าด้วยกัน
- OpenTelemetry(OTel) เป็นทั้งเฟรมเวิร์กและทูลคิทด้าน observability ที่พยายามทำมาตรฐานเครื่องมือซึ่งเดิมแยกกันอยู่ ให้มาอยู่ในสัญญาณ 3 แบบคือ metrics, logs และ traces
- ชุดเครื่องมือเดิมถูกแยกตามหน้าที่
- Prometheus: metrics
- ตัวรวบรวมศูนย์กลางอย่าง Logstash และ Elasticsearch: logs
- OpenTracing: distributed tracing
- OTel ไม่ได้ให้แค่สเปก แต่ยังมีคอมโพเนนต์หลักด้วย
- OpenTelemetry Protocol(OTLP): โปรโตคอลที่แอปพลิเคชันใช้รายงานข้อมูล telemetry
- OpenTelemetry Collector: คอมโพเนนต์สำหรับรับ ประมวลผล และส่งออกข้อมูล telemetry แบบไม่ผูกกับ vendor
- SDK สำหรับมากกว่า 10 ภาษา: ใช้ทำ OTLP และ telemetry export
- แอปพลิเคชันสามารถส่งสัญญาณไปยัง OTel Collector ผ่าน auto-instrumentation, API และ language SDK ได้ และฝั่ง infrastructure ก็สามารถส่งสัญญาณเข้า Collector ได้เช่นกัน
การรองรับเดิมของ IPF และคำขอจากลูกค้า
- IPF มีการเชื่อมต่อกับ ELK Stack, ระบบ monitoring และเอกสารด้าน observability อยู่แล้ว และลูกค้าก็ใช้งานในสภาพแวดล้อม production มาตลอด
- ด้วยลักษณะของเฟรมเวิร์ก จึงไม่อาจรู้ได้ว่าแอปพลิเคชันที่ใช้ไลบรารีจะถูกนำไป deploy ในสภาพแวดล้อมแบบใด จึงต้องไม่บังคับ vendor รายใดรายหนึ่ง แต่ให้ abstraction และค่าเริ่มต้นที่ override ได้แทน
- คำแนะนำพื้นฐานเดิมคือส่ง logs ไปยังตัวรวบรวมอย่าง Elasticsearch หรือ LogScale และเปิดใช้/รองรับ Prometheus ซึ่งแทบกลายเป็นมาตรฐานสำหรับ metrics ไปแล้ว
- ลูกค้าร้องขอ tracing บน OTel พร้อมกันเกือบสามเคส และเมื่อจะใช้ tracing เป็น OTel ก็เกิดแนวโน้มที่จะย้าย logs และ metrics ไปด้วยพร้อมกัน
- logs และ metrics จัดการได้ค่อนข้างง่ายด้วย appender ใหม่และการตั้งค่าเพิ่มเติม แต่ tracing ยังเป็นอีกปัญหาหนึ่งต่างหาก
ทำไม distributed tracing ถึงต้องมี context propagation
- ในระบบ distributed หากต้องการติดตามทรานแซกชันเดียวตลอดทั้งระบบ จำเป็นต้องส่งต่อข้อมูลที่ใช้เชื่อมการเรียกต่าง ๆ เข้ากับทรานแซกชันนั้น ซึ่งเรียกว่า context propagation
- trace คือโครงสร้างแม่ที่ครอบหน่วยงานย่อยหลายตัวที่เรียกว่า span และ span สามารถมีหลายตัวและซ้อนกันได้
- ในเว็บอีคอมเมิร์ซ กระบวนการกดปุ่ม “buy now” สามารถถูกรวมเป็น trace เดียวได้
- span ที่ frontend ติดต่อกับ backend
- child span ที่ backend ติดต่อกับบริการชำระเงิน จัดส่ง และจัดการคำสั่งซื้อ
- child span เพิ่มเติมที่บริการ downstream แต่ละตัวใช้สื่อสารกับระบบอื่นต่ออีกทอดหนึ่ง
- เมื่อใช้ OTel แต่ละบริการแบบ distributed จะรายงานส่วนของ trace ของตัวเองไปยัง OTel Collector และ OTel จะประกอบภาพรวมทั้งหมดไว้ใต้ trace ID เดียว
มาตรฐาน context propagation 4 แบบ และร่องรอยของ OpenTracing
- การติดตั้ง context propagation ที่ OTel ต้องรองรับมี 4 แบบ
- ฝั่ง Akka ของ IPF รองรับ OpenTracing ที่ประกาศเลิกใช้แล้วอยู่ก่อน และใช้งาน การรองรับ OpenTracing ของ Lightbend Telemetry
- Lightbend Telemetry 2.20.0 เพิ่มการรองรับ OpenTelemetry logs/events และ metrics แล้ว แต่ ยังไม่มี tracing support ที่สำคัญ
- ในทางทฤษฎี OTel tracing ดูคล้ายกับการรีแบรนด์ของ OpenTracing และ OpenTracing ของ Lightbend Telemetry ก็รองรับรูปแบบการส่งต่อทั้ง 4 แบบ จึงดูเหมือนน่าจะทำงานร่วมกันได้ แต่ผลลัพธ์จริงไม่เป็นเช่นนั้น
trace ที่ขาดตอนระหว่าง Spring และ Akka
- IPF ใช้ทั้ง Spring และ Akka ร่วมกัน
- Spring Boot และ Spring IoC: ใช้สำหรับ bootstrap แอปพลิเคชัน การตั้งค่า และการประกอบ dependency
- Akka: ใช้สำหรับ event sourcing, scheduling, clustering, sharding, integration เป็นต้น
- ลูกค้าสามารถเริ่ม payment flow ได้จาก Spring REST controller หรือเมธอดที่ติด
@KafkaListener - ก่อน OTel ทั้งสามด้านทำงานร่วมกันได้โดยแทบไม่มีปัญหาใหญ่
- Metrics: Spring และ Akka เปิดเผย Prometheus endpoint คนละชุด
- Logs: ทั้งสองเฟรมเวิร์กใช้ SLF4J และ Logback
- Traces: ทั้งคู่ใช้ OpenTracing
- เมื่อใช้ OTel นั้น metrics และ logs ยังส่งออกได้ปกติ เพราะ Spring และ Akka ทำงานแยกจากกันได้ แต่ tracing จำเป็นต้องแชร์ trace context เดียวกันภายใน JVM
- ปัญหาจริงคือภายในแอปเดียวกัน แนวคิดการติดตามเดียวกันถูกแทนด้วย API คนละชุดสองชุด และ API ทั้งสองไม่ได้สื่อสารกัน
- พฤติกรรมที่ถูกต้องคือ Akka HTTP client ควร reuse trace ID เดิม
123และสร้างแค่ span ID ใหม่ เพื่อให้เป็นหน่วยงานย่อยใหม่ภายใต้ trace เดิม แต่สิ่งที่เกิดขึ้นจริงคือมีการสร้างสอง trace ที่ไม่เกี่ยวข้องกัน
opentracing-shim และการชนกันของ implementation
- ฝั่ง OTel มี
opentracing-shimที่ทำให้ OTelTracerดูเหมือนเป็น OpenTracingTracer - แต่ Lightbend Telemetry ใช้ implementation ของ Tracer แบบ custom จึงทำให้ทั้ง shim และ Jaeger ใช้งานล้มเหลว
- ใน log มี error ดังนี้
Expected to have an OpenTelemetry Span but got cinnamon.opentracing.TraceLocal$ContextOnlySpanExpected to have a JaegerSpanContext but got io.opentelemetry.opentracingshim.SpanContextShim
- Jaeger ล้มเหลวเมื่อได้รับ context จาก OTel shim และ OTel ก็ล้มเหลวเมื่อได้รับ context จาก Lightbend
การตรวจสอบ Java Agent และ tracing ภายในของ Lightbend
- ทั้ง OTel และ instrumentation ของ Lightbend Telemetry ต่างก็ใช้ Java Agent เพื่อ hook การเรียกเมธอดบางตัวในบางคลาส แล้วรายงานกิจกรรมไปยัง tracer
- instrumentation ของ Lightbend Telemetry ไม่ได้เป็นโอเพนซอร์ส จึงต้องตรวจสอบโค้ด tracer ที่ decompile แล้วเพื่อทำความเข้าใจการทำงาน
- มีการสร้างตัวอย่างย่อสำหรับทำซ้ำปัญหา เพื่อตรวจสอบว่าจุดใดที่ OTel trace context จากฝั่ง Spring ขาดหายไปก่อนถึงฝั่ง Akka
- จุดที่ Jaeger ล้มเหลวคือโค้ดใน
JaegerTracer.javaบรรทัดนี้ - ตัวเรียกคือคลาส instrumentation แบบ proprietary ของ Lightbend Telemetry ชื่อ
OpenTracingAkkaPersistenceActorInstrumentation.class - ในโค้ดที่ decompile แล้ว เงื่อนไขสำคัญอยู่ที่สถานะของ
var5- ถ้า
var5ซึ่งเป็น OpenTracingSpanContextไม่เป็น null ก็จะผูก span ใหม่ให้เป็นลูกของ active span ปัจจุบัน - ถ้า
var5เป็น null span นั้นก็จะไม่เกี่ยวข้องกับ trace เดิม - ถ้า
var5ไม่ใช่ Jaeger SpanContext ก็จะทำให้ Jaeger ล้มเหลว
- ถ้า
เชื่อม OTel กับ OpenTracing ด้วยการแปลงแบบแมนนวล
SpanContextถูกดึงมาจากthis.traceLocal.currentContext()และtraceLocalถูก initialize จากExtendedTracerของ Lightbend- ในเอกสารของ Lightbend มีวิธีเข้าถึง
ExtendedTracerแบบ globalGlobalExtendedTracer.get()
GlobalExtendedTracer.get()จะคืนค่าExtendedTracerและlocal()จะคืนค่าTraceLocalตัวเดียวกับที่ไลบรารี instrumentation ใช้อยู่TraceLocalนี้มีเมธอดactivateContextที่รับ OpenTracingSpanContext- แนวทางแก้มี 4 ขั้นตอน
- ไม่ใช้ OTel shim
- inject OpenTelemetry Context ปัจจุบันลงใน Java
Map - ใช้ค่าจาก
Mapนั้น extract ออกมาเป็น Jaeger SpanContext - activate Jaeger SpanContext ใน
TraceLocalของ Lightbend ก่อนเข้าสู่ Akka
- งานใน OTel propagators API ที่ใช้คือ inject and extract operations
- โค้ดแกนหลักทำตามลำดับดังนี้
- สร้าง
HashMapว่าง - inject OTel context ลงใน map ด้วย
GlobalOpenTelemetry.get().getPropagators().getTextMapPropagator().inject(...) - สร้าง JaegerSpanContext ด้วย
new TextMapCodec(false).extract(new TextMapAdapter(otelContext)) - activate context ก่อนเข้า Akka ด้วย
GlobalExtendedTracer.get().local().activateContext(openTracingContext)
- สร้าง
พฤติกรรมที่ยืนยันแล้วและคำแนะนำในการใช้งานจริง
- หลังเชื่อมแบบแมนนวลแล้ว trace ต่อเนื่องได้ตามคาด
- ตั้งแต่ Spring REST call
/submitเป็นต้นไป ทั้ง flow เชื่อมกันเป็น trace เดียว - สามารถใช้งานส่วนที่ instrument ด้วย OTel API ปนกับส่วนที่ instrument ด้วย OpenTracing API ได้
- trace ถูกส่งต่อข้ามขอบเขต HTTP ได้
- ตั้งแต่ Spring REST call
- ในตัวอย่างมีการใช้ชื่อต่างกันเพื่อแยก instrumentation สองชนิด แต่ในสภาพแวดล้อมลูกค้าจริง แนะนำให้ตั้ง
otel.service.nameและcinnamon.applicationให้ตรงกัน เพื่อให้จากภายนอกมองเป็นแอปพลิเคชันเดียว
ทำไมมันถึงซับซ้อน และความกังวลที่ยังเหลืออยู่
- หากจะเขียน Lightbend Telemetry ใหม่บน OTel API ก็อาจเป็นงานใหญ่ เพราะต้องพอร์ต instrumentation จำนวนมากที่ยังผูกอยู่กับ Jaeger API ไปเป็น OTel API
- OTel Collector รองรับการเก็บ trace แบบ legacy Zipkin อยู่แล้ว ทำให้ Lightbend อาจรองรับ OTel แบบสมบูรณ์ได้ผ่านการพึ่งพา legacy support
- สาเหตุโดยตรงของความซับซ้อนคือการพยายามผสานระบบ instrumentation สองชุดที่ใช้ไลบรารี tracing คนละตัวเข้าด้วยกัน
- โครงการ OTel พยายามจัดระเบียบโลก observability ด้วยความพยายามทำมาตรฐาน เช่น semantic conventions แม้จะดูซับซ้อนในช่วงแรกที่ทำความเข้าใจ แต่ก็ถูกประเมินว่าเป็นโครงการ FOSS ที่มีประโยชน์
- ยังมีความกังวลว่า Akka จะส่ง trace context ระหว่าง thread ภายใน actor model ได้ถูกต้องหรือไม่
- ในการทดสอบโหลดขนาดเล็ก พบว่าทำงานได้ตามคาด
- มีการเปิด ticket ที่เกี่ยวข้องไว้ฝั่ง Akka แล้ว
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ตลอดช่วงที่เรียนรู้และพอร์ต Otel ผมรู้สึกเหมือนกลับไปอยู่ในโลก Java อีกครั้ง ทุกครั้งที่ไล่โค้ดทีละบรรทัดมันเหมือน EnterpriseFizzBuzz ไม่มีทางค้นพบอะไรได้เองเลย และศัพท์เฉพาะของมันก็ดูเหมือนถูกสร้างโดยคนที่เมาอะไรสักอย่าง
บน NodeJS การใช้ CPU สูงกว่า StatsD ประมาณ 4 เท่า สุดท้ายจึงต้องทำการ aggregate เองเพื่อลดการใช้งานและลดการระเบิดของแท็กด้วย StatsD ไม่เป็นไรแม้หลายโปรเซสจะรายงานแท็กเดียวกัน แต่ OTEL จะเขียนทับไปเลย
ตอนโหลดสูงสุด CPU หนึ่งตัววิ่งที่การใช้งาน 60–80% และก่อนจะมีอะไรเปลี่ยนแปลงก็ยังขยายแนวตั้งไม่ได้ด้วย สำหรับภาษาที่ใช้หนึ่งโปรเซสต่อหนึ่งคอร์ OTEL เหมือนตั้งตัวเป็นศัตรูอย่างจริงจังจนเหมือนเป็นเรื่องตลก ใช้ Prometheus ไปเลยดีกว่า และในทางปฏิบัติก็ไม่มีคู่แข่งอื่นด้วย
ตอนลองตั้งค่า otel ง่าย ๆ บน .NET ผมอ่านเอกสารของเวนเดอร์ที่องค์กรเลือกอยู่หลายชั่วโมงก็ยังไม่เข้าใจ เลยเข้า Discord ที่เพื่อนร่วมงานดูแลอยู่ โมเดลธุรกิจส่วนหนึ่งของที่นั่นคือ “ถ้าอยากใช้ otel ที่ใช้ได้จริงในผลิตภัณฑ์โอเพนซอร์ส ก็ต้องจ่ายเงิน” และผมก็รู้สึกทันทีว่าต่อให้ค่าใช้จ่ายเท่าไรก็คุ้ม
แทนที่จะทำ OTEL implementation ผมยอมสร้างไลบรารี event/pub-sub ที่เสถียรขึ้นมาอีกตัวโดยไม่มีประสบการณ์ล่วงหน้าดีกว่า
คอนฟิกขั้นต่ำจริง ๆ ก็เล็กพอสมควร มีแค่เว็บ UI, อินสแตนซ์เซิร์ฟเวอร์ และ DB ที่คุณรู้อยู่แล้วก็พอ: https://skywalking.apache.org/docs/main/latest/en/setup/back...
มันมีด้านที่คล้าย Zabbix ในวงการมอนิเตอร์ริ่งอยู่ ทั้งสองอย่างคงไม่ได้ทำให้ใครว้าว แต่ความใช้งานได้จริงนั้นเพียงพอ
process.vpidขึ้นมา สามารถประสานให้ค่านั้นไม่ซ้ำกันระหว่างที่แอปยังมีชีวิตอยู่ได้ด้วยอะไรทำนอง global objectจากนั้นก็วางบางอย่างไว้เพื่อรวมค่าและลบแอตทริบิวต์นั้นออก ใน statsd/delta ถ้าสูญเสียการส่งสัญญาณไปหนึ่งครั้ง ข้อมูลทั้งหมดจะบิดเบี้ยว แต่ในวิธีสะสมจะเสียแค่ความแม่นยำ
กรณีใช้งานของผมคือ เมตริกแบบ push-based จากเครื่องมือ “batch” ไม่ใช่โปรเซสระยะยาวที่ scrape ได้
เหตุผลที่ Otel ดูซับซ้อน เป็นเพราะเวนเดอร์ด้าน observability หลายรายทำให้การทำ observability ง่ายมากด้วย SDK, เอเจนต์ และ API เฉพาะของตัวเอง Otel พยายามแก้ปัญหานี้ และผมคิดว่าคนที่สร้างมันทำได้ยอดเยี่ยม
Grafana ก็ควรได้รับคำชมที่ยอมรับ OpenTelemetry ให้เป็นองค์ประกอบชั้นหนึ่งของ ecosystem
ผมผลักดันการใช้ Datadog มาหลายปี แต่สำหรับขนาดระหว่างบริษัทระดับกลางกับองค์กรขนาดใหญ่ ราคากลายเป็นสิ่งที่รับไม่ไหว เมื่อเวลาผ่านไป OpenTelemetry API และ SDK เสถียรขึ้น จึงนำมาใช้เป็นมาตรฐาน observability ของแอปพลิเคชัน
อย่างไรก็ตาม เอกสารโดยรวมยังปรับปรุงได้อีก และการที่เอกสาร onboarding แตกต่างกันตามภาษาไม่ใช่เรื่องที่เหมาะนัก
ตอนนี้ทีมใช้สแตก NodeJS/Typescript และได้ทำชุดแพ็กเกจกับตัวอย่างสแตก Grafana เพื่อให้เริ่มใช้ OpenTelemetry ได้เร็ว: https://github.com/zonneplan/open-telemetry-js
ปัญหาใหญ่ที่สุดของเวนเดอร์ APM ทุกเจ้าคือทันทีที่เอเจนต์เวทมนตร์มี kernel hook ก็จะเกิดสารพัดเรื่องที่นักพัฒนาอธิบายไม่ได้
สมัยก่อนที่บริษัทอื่นมีการนำ Dynatrace มาใช้ โชคดีที่แอปมีเมตริกในตัวเพียงพออยู่แล้ว ถึงขั้นที่ lead SRE มองว่าเป็น “ตัวอย่างที่ดี” ของการทำ instrumentation แต่ทันทีที่ติดตั้งเอเจนต์ Dynatrace บนโฮสต์ของแอป ก็เกิด Heisenbug หลายอย่างที่ต้องรีสตาร์ตโหนด และยังวัด performance degradation ได้โดยตรงด้วย
น่าขันที่เมตริกช่วยให้หลีกเลี่ยงความเจ็บปวดได้ แต่ไม่มีใครรู้วิธีแก้ ที่แย่ที่สุดคือกรณีที่ตอนอัปเดต MSSQL แล้ว failover ทำให้ connection pool ของ ADO.NET ปนเปื้อนอย่างประหลาด
เป็นโครงสร้างที่ซับซ้อนเท่าที่จำเป็นเท่านั้น ควรหลีกเลี่ยงฟีเจอร์ที่เหมือนเวทมนตร์ และใช้แค่ subset ที่มีคุณค่าที่สุดตามบริบทและเข้าใจง่ายก็พอ
ในทีมของเราเรียบง่ายมาก ใช้ ไลบรารีที่ส่งเฉพาะ trace และ trace ก็ให้คุณค่ามากที่สุดต่อการสังเกตแอปพลิเคชัน อีกทั้งยังใส่ข้อมูลประเภทอื่นได้ด้วย โดยพื้นฐานแล้วก็เหมือนใช้ hashmap แทน string หรือ float
เราใช้ manual instrumentation แทน auto instrumentation ตั้งใจเลือกว่าจะสังเกตอะไร และเข้าใจดีว่าโค้ดส่วนไหนปล่อย span ออกมา นอกจากนี้ยังมีกฎการตั้งชื่อที่สอดคล้องกับโครงสร้างโค้ดด้วย
ฝั่ง backend ใช้ทั้งบริการ third-party ราคาถูกและการติดตั้ง all-in-one Jaeger สำหรับพัฒนาในเครื่อง อย่างหลังแค่รันไฟล์ executable หนึ่งไฟล์หรือ Docker container หนึ่งตัวก็พอ และไม่บันทึก span ลงดิสก์ ส่วนใหญ่ใช้เพื่อให้ทีมสบายใจว่าจะไม่ทำให้บริการ third-party ล้น
การ monitor infrastructure มีการตั้งค่าเดิมอยู่แล้ว และในกรณีของเราไม่รู้สึกว่าการรวบรวม log กับ metric ของ infrastructure ทั้งหมดมีคุณค่ามากนัก มองว่า OTEL metric และ log ยังอยู่ช่วงเริ่มต้น แต่ vendor ไม่ได้พูดแบบนั้น
ตอนนี้กำลังหา endpoint สำหรับส่ง metric แบบง่าย ๆ ครั้งเดียวจากบางส่วนของ infrastructure ที่ยัง scrape ไม่ได้
Otel อาจโอเคสำหรับโปรเจกต์ใหม่ แต่การเปิดใช้กับบริการ production ที่มี telemetry อยู่แล้วให้ความรู้สึกเหมือนเปลี่ยนยางรถที่กำลังวิ่งอยู่
ผมเชื่อว่าอาจดีสำหรับ greenfield project ที่ใช้แต่ otel และไม่มี framework ที่ไม่ใช่ otel แต่ผมยังไม่ได้อยู่ในโลกแบบนั้น
หนึ่งในปัญหาใหญ่ที่สุดคือ ประสบการณ์พัฒนาในเครื่อง อยากรองรับ log, trace, metric ในเครื่อง แต่ไม่อยากต้องเปิด Docker image จำนวนมากเพื่อสิ่งนั้น อยากดูผ่าน log ก่อน deploy ว่า metric, trace, baggage และ activity span จะหน้าตาเป็นอย่างไร
ล่าสุดทีม .NET ออก .NET Aspire มา ซึ่งดีมาก ทำให้ visualize ทุกอย่างในที่เดียวได้ง่ายใน local development stack และทำงานเหมือน orchestrator ที่เขียนเป็นโค้ด
เวลานำไป deploy บน k8s ก็ชี้ OTEL endpoint ไปที่ DataDog Agent แล้วทุกอย่างก็ทำงานเลย เราหลีกเลี่ยง custom trace library และ SDK ของ DataDog แล้วใช้แต่ OTEL
ตอนนี้ประสบการณ์พัฒนาดีขึ้นพอสมควร
https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals...
https://docs.datadoghq.com/opentelemetry/#overview
ตั้งค่าครั้งแรกบนเครื่องพัฒนาในเครื่องใช้เวลา 5 นาที หลังจากนั้นก็แค่รัน
/path/to/openobserveในแท็บ terminal แยกก็จบ ถ้าอยากหลีกเลี่ยงความซับซ้อนมหึมาของ single statically linked binary ก็มี Docker image สำหรับรันทั้ง local และ remote ให้ด้วย :Pเป็น all-in-one OpenTelemetry backend ที่มีกราฟสวย ๆ และในโปรเจกต์ของผมยังไม่เคยล้มเหลวแบบที่สังเกตได้เลย
ถ้าใช้ Aspire จะเพิ่มความซับซ้อนที่ไม่จำเป็นในระดับแอป และผูกติดกับ ecosystem ที่แคบ สำหรับ local development มีทางเลือกที่พิสูจน์แล้วมากมายอย่าง docker compose และ Aspire ก็ไม่ได้ง่ายกว่า docker compose กับ environment variable อย่างชัดเจนด้วย
ถ้าจะทำ otel ใน Python แนะนำให้ใช้ client ของ Logfire ถึงแม้ไม่ได้ใช้บริการ Logfire ก็ตาม
เป็นโอเพนซอร์ส และส่งไปยัง endpoint ที่รองรับ otel ใด ๆ ก็ได้ แถม client ที่ทีม pydantic ทำยังดีกว่าและเรียบง่ายกว่าไลบรารี otel อย่างเป็นทางการเป็น 10 เท่า
มีบทสัมภาษณ์ที่น่าสนใจซึ่ง Samuel Colvin อธิบายว่าเขามาถึงจุดนี้ได้อย่างไร: https://www.bitecode.dev/p/samuel-colvin-on-logfire-mixing-p...
ดังนั้นผมจึงเริ่มโปรเจกต์โอเพนซอร์สที่มุ่งทำให้การนำ OpenTelemetry มาใช้เป็นเรื่องง่ายเหมือน คำสั่งบรรทัดเดียว: https://github.com/odigos-io/odigos
ทุกวันนี้เว็บเฟรมเวิร์กจำนวนมากช่วยจัดการการทำ instrumentation ส่วนใหญ่ให้แทน เช่น ถ้าใช้ opentelemetry-js แล้วโฮสต์ของอย่าง https://signoz.io เอง ก็สามารถตั้งขึ้นมาได้ในไม่ถึงหนึ่งชั่วโมง และได้ข้อมูลจำนวนมากโดยไม่ต้องเขียนโค้ด custom
OpenTelemetry เติบโตมาจาก trace แต่ metric และ log ปล่อยให้โซลูชันเฉพาะทางจัดการจะดีกว่ามาก
รู้สึกเหมือนปัญหา “abstraction ที่รั่ว” หรือ “framework ที่รั่ว” ถ้าอยากเอาทุกอย่างมาไว้ใต้ร่มเดียวกัน ฐานข้อมูล SQL ก็ทำทั้งหมดนี้พร้อมกันได้เหมือนกัน แต่นั่นไม่ได้แปลว่าควรทำ
https://cra.mr/the-problem-with-otel/
ถึงอย่างนั้นทุกครั้งที่ต้องจัดการกับ OTel ก็ยังไม่ชอบอยู่ดี
ถ้าอ่านจนจบจะเห็นว่าความเจ็บปวดส่วนใหญ่เป็นสิ่งที่สร้างขึ้นเอง ใน stack มาตรฐานของ Python (mysql, flask, redis, requests ฯลฯ) มันง่ายมาก แค่ใส่ import ไม่กี่ตัวไว้ด้านบนของ service ก็เชื่อมต่ออัตโนมัติและ trace ทุกอย่างได้โดยไม่วุ่นวายอะไร
aiohttpเวอร์ชันล่าสุดคือ 3.11.X และ auto instrumentation ระบุว่ารองรับ3.X[0] แต่ผลลัพธ์จริงขึ้นอยู่กับว่าaiohttpที่ใช้ใหม่แค่ไหน และฝั่ง auto instrumentation อยู่ในสถานะใดถ้าทุกอย่างลงตัวก็ทำงานเหมือนเวทมนตร์ แต่ช่องให้ผ่านนั้นค่อนข้างแคบ
[0]: https://github.com/open-telemetry/opentelemetry-python-contr...
trace ทำงานแล้ว และตั้งค่า spanmetrics exporter แล้วด้วย ถ้า query prometheus โดยตรงก็เห็น spanmetrics แต่ไม่ว่าจะทำอย่างไรก็ไม่โผล่ในแท็บ “monitor” ของ jaeger
หลังเสียเวลาไป 3 วัน หัวหน้าก็บอกว่า “แค่ทำ manual instrumentation แล้วส่งทั้งหมดเข้า SQL Server จากนั้นทำ Grafana dashboard ดีไหม” แต่ก็ไม่อยากทำแบบนั้นเหมือนกัน
เป็น use case ที่ง่ายที่สุดแล้วยังไม่เวิร์ก ต้องเพิ่ม Grafana เข้าไปอีกหรือเปล่า?
เหตุผลที่ซับซ้อนก็เพราะมันถูกออกแบบมาเพื่อ บริษัทที่ขายซอฟต์แวร์ที่เข้ากันได้กับ Otel ไม่ใช่เพื่อวิศวกรที่นำไปใช้งาน
กลับกัน คิดว่า backend ต่าง ๆ ค่อนข้างช้าในการนำไปใช้ด้วยซ้ำ
ความหมายของคำเปลี่ยนได้ ไม่เป็นไร แต่ก็น่าสนใจที่ตอนนี้เหมือนคำสำหรับ การเขียนซอฟต์แวร์ให้ตรงตามสเปก หายไป เหลือแต่ “การนำซอฟต์แวร์ที่มีอยู่ไป deploy บนเซิร์ฟเวอร์”