Membedah struktur span (nama, attributes, events, status, kind) dan span processor, lalu memahami W3C Trace Context (traceparent, tracestate) serta baggage sebagai mekanisme korelasi trace lintas layanan di OpenTelemetry

Setelah episode 3 memperkenalkan auto dan manual instrumentation, episode ini membedah traces secara mendalam — objek paling penting dalam observability request-centric. Kalian akan belajar anatomi satu span, bagaimana span dikumpulkan dan diproses, serta — yang paling krusial — bagaimana konteks diwariskan dari satu service ke service lain.
Ini penting karena distributed tracing hanya berguna jika trace tersambung dari ujung ke ujung. Trace yang terputus di tengah jalan lebih buruk daripada tidak ada trace: ia memberi kesan data lengkap padahal korelasi rusak diam-diam.
Span adalah unit kerja dalam trace. Setiap span membawa:
HTTP GET, payment.charge.http.response.status_code, order.id).exception).Unset, Ok, Error.SERVER, CLIENT, PRODUCER, CONSUMER, INTERNAL.Tiga konsep ini sering tertukar. Aturan praktisnya:
from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode
tracer = trace.get_tracer("catalog.service")
with tracer.start_as_current_span(
"catalog.get", kind=trace.SpanKind.SERVER
) as span:
span.set_attribute("http.request.method", "GET")
span.set_attribute("http.route", "/products/{id}")
span.set_attribute("http.response.status_code", 200)
span.add_event("cache.miss", {"key": "product:42"})
span.set_status(Status(StatusCode.OK))SpanKind memberi tahu sistem dari arah mana operasi terjadi — krusial untuk membaca trace di backend:
| Kind | Makna | Contoh |
|---|---|---|
INTERNAL | Operasi internal, bukan komunikasi | kalkulasi bisnis |
SERVER | Menerima request | handler HTTP, consumer gRPC |
CLIENT | Membuat request keluar | panggilan HTTP/DB keluar |
PRODUCER | Mengirim pesan ke queue | publish ke Kafka |
CONSUMER | Menerima pesan dari queue | konsumsi dari Kafka |
Satu trace yang sehat biasanya bergantian CLIENT (di pemanggil) → SERVER (di penerima) di setiap hop.
SpanProcessor adalah hook yang dijalankan SDK saat span mulai dan berakhir. Dua tipe yang umum:
from opentelemetry.sdk.trace.export import BatchSpanProcessor
processor = BatchSpanProcessor(
OTLPSpanExporter(endpoint="localhost:4317"),
max_export_batch_size=512,
scheduled_delay_millis=5000,
)
provider.add_span_processor(processor)Beberapa processor bisa dirangkai (misal satu untuk sampling, satu untuk export) — ini jadi fondasi sampling di episode 13.
Satu aplikasi yang diinstrumentasi hanya menghasilkan fragmen trace. Untuk menyambungnya menjadi satu trace utuh, konteks harus mengalir bersama request: dari trace_id + span_id + baggage + tracestate, dikemas dalam format yang dipahami semua service.
Standar yang diadopsi OTel adalah W3C Trace Context dengan dua header:
traceparent — membawa versi, trace_id, parent_span_id, dan trace_flags (sampled atau tidak):traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^
ver trace_id (32 hex) span_id flagstracestate — membawa data tambahan vendor-spesifik dalam pasangan key=value yang dipisahkan koma, agar tiap vendor bisa menyisipkan metadata tanpa merusak header lain.Aturan propagasi: service meng-extract header dari request masuk untuk menjadi parent-nya, lalu meng-inject header yang diperbarui ke setiap request keluar. Inilah yang membuat satu request memakai satu trace_id di seluruh perjalanan.
Baggage adalah mekanisme membawa key-value kecil lintas service tanpa mengikat ke trace ID — misalnya customer.id atau experiment.group agar bisa di-filter di seluruh trace tanpa menambahkan atribut per span di tiap service.
from opentelemetry.baggage import set_baggage, get_baggage
from opentelemetry.context import attach, detach
token = attach(set_baggage("customer.id", "c-42"))
# ... service memanggil service lain ...
print(get_baggage("customer.id"))
detach(token)Warning
Baggage dikirim sebagai header plain text di setiap request — jangan pernah menaruh data sensitif (PII, token, password) di dalamnya. Header ini bisa bocor ke log, proxy, atau service pihak ketiga. Gunakan baggage hanya untuk metadata low-risk seperti identitas internal atau group A/B.
01Bit terakhir traceparent adalah trace_flags — bit ke-0 adalah sampled. Nilai 01 berarti span ini direkam dan diekspor; 00 berarti tidak. Ini yang dipakai propagasi untuk menginformasikan "trace ini di-sampling atau tidak" lintas service — fondasi keputusan sampling di episode 13.
Gejala paling umum: trace terlihat "terpotong" di backend — hanya terlihat satu service. Penyebab klasiknya:
traceparent.Kita atasi pola-pola ini lebih jauh di episode 15 saat membahas tracing lintas layanan di Express, Gin, dan Spring.
Pada episode 4 ini, kalian telah menguasai anatomi span dan mekanisme propagasi konteks.
Inti yang harus dibawa pulang:
traceparent + tracestate) menyambungkan trace lintas layanan; baggage membawa metadata ringan — jangan taruh PII di sana.Di episode 5 selanjutnya, kita akan membahas metrics: tipe, instruments & export — Counter, UpDownCounter, Gauge, Histogram, instrumen asinkron (observable), View/aggregation, serta perbedaan delta vs cumulative saat mengekspor ke backend. Sampai jumpa di episode 5!