BelajarKoding Logobelajarkoding

Platform belajar web development Indonesia. Artikel, cheat sheets, roadmap, dan code challenges untuk developer Indonesia.

Navigasi

  • Artikel
  • Cheat Sheets
  • Roadmap
  • Challenges
  • Pricing
  • Search

Produk Lain

  • JagoHermes
  • KelasClaude
  • KilatKoding
  • BelajarVibeCoding
  • JualanKoding

Support

  • Privacy Policy
  • Terms of Service
  • Email

© 2026 BelajarKoding. All rights reserved.

Galih PratamaBagian dari ekosistem Galih Pratama
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade

Daftar Isi

Konsep DasarApa Itu OpenTelemetryTiga Pilar ObservabilityKomponen OpenTelemetryTraces dan SpansTraceSpanSpan KindManual Instrumentation (Python)Setup DasarMembuat Span ManualSpan Attributes dan EventsNested SpanManual Instrumentation (JavaScript)Setup DasarMembuat Span ManualAuto-InstrumentationPython Auto-InstrumentationJavaScript Auto-InstrumentationContext PropagationApa Itu Context PropagationPropagator StandarW3C TraceContext HeaderInject dan Extract ManualPropagator ConfigurationBaggageApa Itu BaggageMenggunakan BaggageBaggage Header FormatMenambahkan Baggage ke Span AttributesMetricsMembuat dan Menggunakan MetricsTipe MetricHistogram dan Observable GaugeLogsOpenTelemetry LogsCollectorApa Itu OTel CollectorCollector ConfigurationMenjalankan Collector dengan DockerBackend: Jaeger dan TempoJaegerGrafana TempoSamplingMengapa SamplingKonfigurasi Sampler (Python)Glossary
ObservabilityOpenTelemetryMonitoring

OpenTelemetry Cheat Sheet

Referensi cepat OpenTelemetry. Traces, spans, metrics, logs, baggage, context propagation, auto dan manual instrumentation, OTLP exporter. Perfect buat developer yang mau observability di aplikasi Python dan JavaScript.

Python11 min read2.133 kata
Silakan login atau daftar untuk membaca cheat sheet ini.

Cheat sheet ini berisi panduan praktis OpenTelemetry (OTel), standar observability open-source untuk traces, metrics, dan logs. Cocok buat developer yang ingin menerapkan distributed tracing di aplikasi Python dan JavaScript dengan backend seperti Jaeger atau Grafana Tempo.

#Konsep Dasar

#Apa Itu OpenTelemetry

OpenTelemetry adalah proyek CNCF yang menyediakan standar, SDK, dan tool untuk menghasilkan dan mengekspor data telemetri (traces, metrics, logs) dari aplikasi. OTel membebaskan kamu dari vendor lock-in karena bisa dikirim ke backend apa pun.

#Tiga Pilar Observability

PilarFungsiContoh
TracesMelacak request melalui multiple serviceRequest dari API gateway ke database
MetricsData numerik agregatRequest count, memory usage, error rate
LogsEvent diskrit dengan timestamp"User 123 logged in"

#Komponen OpenTelemetry

KomponenFungsi
APIInterface yang dipakai di kode aplikasi
SDKImplementasi API yang mengumpulkan dan mengekspor data
Instrumentation LibrariesAuto-instrumentation untuk library populer (Flask, Express, PostgreSQL)
CollectorService proxy yang menerima, memproses, dan mengekspor telemetri
OTLPOpenTelemetry Protocol, format standar untuk transfer data

#Traces dan Spans

#Trace

Trace adalah rekaman perjalanan satu request melalui sistem terdistribusi. Trace terdiri dari multiple span yang membentuk tree.

plaintext
Trace: User checkout request
  +-- Span: HTTP GET /checkout (gateway)
       +-- Span: authenticate_user
       +-- Span: get_cart_items
       |    +-- Span: SELECT * FROM cart (database)
       +-- Span: process_payment
            +-- Span: POST /api/payment (external API)

#Span

Span adalah unit kerja tunggal dalam trace. Setiap span punya:

  • Trace ID: ID yang sama untuk semua span dalam satu trace
  • Span ID: ID unik untuk span ini
  • Parent Span ID: ID span parent (null untuk root span)
  • Operation name: Nama operasi (mis. "GET /api/users")
  • Start time dan end time: Durasi span
  • Attributes: Key-value metadata
  • Events: Timestamped log dalam span
  • Status: OK, ERROR, atau UNSET
  • Span Kind: SERVER, CLIENT, INTERNAL, PRODUCER, CONSUMER

#Span Kind

KindArti
SERVERMenerima request (HTTP server, RPC server)
CLIENTMengirim request (HTTP client, RPC client)
INTERNALOperasi internal dalam service
PRODUCERMengirim pesan ke queue
CONSUMERMenerima pesan dari queue

#Manual Instrumentation (Python)

#Setup Dasar

python
# requirements.txt: opentelemetry-api, opentelemetry-sdk,
# opentelemetry-exporter-otlp
 
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.resources import Resource
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
 
# Konfigurasi resource (identitas service)
resource = Resource.create({
    "service.name": "checkout-service",
    "service.version": "1.0.0",
    "deployment.environment": "production",
})
 
# Setup tracer provider
provider = TracerProvider(resource=resource)
processor = BatchSpanProcessor(
    OTLPSpanExporter(endpoint="http://localhost:4317", insecure=True)
)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
 
# Ambil tracer
tracer = trace.get_tracer(__name__)

#Membuat Span Manual

python
from opentelemetry import trace
 
tracer = trace.get_tracer(__name__)
 
# Cara 1: context manager
with tracer.start_as_current_span("process_order") as span:
    span.set_attribute("order.id", "12345")
    span.set_attribute("order.amount", 99.99)
    # Kode yang di trace
    result = do_work()
 
# Cara 2: manual start dan end
span = tracer.start_span("calculate_total")
try:
    span.set_attribute("items.count", 5)
    total = calculate(items)
    span.set_attribute("total.amount", total)
    span.set_status(trace.Status(trace.StatusCode.OK))
except Exception as e:
    span.record_exception(e)
    span.set_status(trace.Status(trace.StatusCode.ERROR, str(e)))
finally:
    span.end()

#Span Attributes dan Events

python
with tracer.start_as_current_span("database_query") as span:
    # Attributes: metadata key-value
    span.set_attribute("db.system", "postgresql")
    span.set_attribute("db.statement", "SELECT * FROM users WHERE id = $1")
    span.set_attribute("db.operation", "SELECT")
    span.set_attribute("net.peer.name", "db.example.com")
 
    # Events: log dalam span
    span.add_event("Query started", {
        "query.id": "q_001",
        "timestamp": "2024-01-01T10:00:00Z"
    })
 
    result = execute_query()
 
    span.add_event("Query completed", {
        "rows_returned": len(result)
    })

#Nested Span

Span child otomatis terhubung ke span parent yang sedang aktif (current span).

python
def handle_request():
    with tracer.start_as_current_span("handle_request") as parent:
        # Span ini otomatis menjadi child dari "handle_request"
        authenticate()
 
        # Span ini juga child dari "handle_request"
        process_data()
 
def authenticate():
    with tracer.start_as_current_span("authenticate"):
        # Span "authenticate" adalah child dari "handle_request"
        verify_token()
 
def verify_token():
    with tracer.start_as_current_span("verify_token"):
        # Span "verify_token" adalah child dari "authenticate"
        pass

#Manual Instrumentation (JavaScript)

#Setup Dasar

javascript
// npm install @opentelemetry/api @opentelemetry/sdk-node
// @opentelemetry/exporter-trace-otlp-grpc
 
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
 
const sdk = new NodeSDK({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'checkout-service',
    [SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0',
  }),
  traceExporter: new OTLPTraceExporter({
    url: 'http://localhost:4317',
  }),
});
 
sdk.start();
 
// Graceful shutdown
process.on('SIGTERM', () => {
  sdk.shutdown()
    .then(() => console.log('Tracing terminated'))
    .catch((error) => console.error('Error terminating tracing', error))
    .finally(() => process.exit(0));
});

#Membuat Span Manual

javascript
const opentelemetry = require('@opentelemetry/api');
const tracer = opentelemetry.trace.getTracer('my-app');
 
// Cara 1: manual
const span = tracer.startSpan('process_order');
span.setAttribute('order.id', '12345');
span.setAttribute('order.amount', 99.99);
 
try {
  opentelemetry.context.with(
    opentelemetry.trace.setSpan(opentelemetry.context.active(), span),
    () => {
      const result = doWork();
      span.addEvent('Order processed', { 'result.status': 'success' });
    }
  );
  span.setStatus({ code: opentelemetry.SpanStatusCode.OK });
} catch (error) {
  span.recordException(error);
  span.setStatus({
    code: opentelemetry.SpanStatusCode.ERROR,
    message: error.message,
  });
} finally {
  span.end();
}
 
// Cara 2: helper function
async function tracedOperation(name, fn, attributes = {}) {
  return tracer.startActiveSpan(name, async (span) => {
    Object.entries(attributes).forEach(([key, value]) => {
      span.setAttribute(key, value);
    });
    try {
      const result = await fn();
      span.setStatus({ code: opentelemetry.SpanStatusCode.OK });
      return result;
    } catch (error) {
      span.recordException(error);
      span.setStatus({
        code: opentelemetry.SpanStatusCode.ERROR,
        message: error.message,
      });
      throw error;
    } finally {
      span.end();
    }
  });
}
 
// Penggunaan
await tracedOperation('fetch_user', async () => {
  const response = await fetch('https://api.example.com/user/123');
  return response.json();
}, { 'user.id': '123' });

#Auto-Instrumentation

#Python Auto-Instrumentation

OTel menyediakan package auto-instrumentation yang otomatis membuat span untuk library populer tanpa mengubah kode aplikasi.

bash
# Install instrumentation packages
pip install opentelemetry-distro
opentelemetry-bootstrap -a install
 
# Jalankan aplikasi dengan auto-instrumentation
opentelemetry-instrument \
  --service_name checkout-service \
  --exporter_otlp_endpoint http://localhost:4317 \
  --resource_attributes deployment.environment=production \
  python app.py

Auto-instrumentation otomatis men-trace:

  • HTTP frameworks: Flask, Django, FastAPI, Tornado
  • HTTP clients: requests, urllib3, aiohttp
  • Database: psycopg2, pymysql, redis, SQLAlchemy
  • Messaging: kafka-python, pika (RabbitMQ)
  • AWS SDK: boto3

#JavaScript Auto-Instrumentation

javascript
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
 
const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({ url: 'http://localhost:4317' }),
  instrumentations: [getNodeAutoInstrumentations({
    // Nonaktifkan instrumentation tertentu
    '@opentelemetry/instrumentation-fs': { enabled: false },
  })],
});
 
sdk.start();
 
// Jalankan dengan: node -r ./tracing.js app.js

#Context Propagation

#Apa Itu Context Propagation

Context propagation adalah mekanisme meneruskan trace context (trace ID, span ID, baggage) antar service lewat header HTTP atau metadata. Ini yang membuat distributed tracing bekerja.

#Propagator Standar

PropagatorHeaderKeterangan
W3C TraceContexttraceparent, tracestateStandar W3C, direkomendasikan
B3 (Zipkin)X-B3-TraceId, X-B3-SpanId, dllKompatibel dengan Zipkin
Jaegeruber-trace-idFormat Jaeger native

#W3C TraceContext Header

plaintext
traceparent: 00-{trace-id}-{span-id}-{trace-flags}

Contoh:

plaintext
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01

#Inject dan Extract Manual

python
from opentelemetry import trace, propagate
from opentelemetry.propagators.composite import CompositePropagator
 
# Inject context ke headers (di sisi client)
headers = {}
propagate.inject(headers)
# headers sekarang berisi traceparent, tracestate, dll
 
# Kirim headers ke service berikutnya
response = requests.post("https://api.example.com/data", headers=headers)
 
# Extract context dari headers (di sisi server)
context = propagate.extract(request_headers)
# Lanjutkan trace dengan context ini

#Propagator Configuration

python
from opentelemetry.propagate import set_global_textmap
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
from opentelemetry.baggage.propagation import W3CBaggagePropagator
 
# Composite propagator (W3C TraceContext + Baggage)
set_global_textmap(CompositePropagator([
    TraceContextTextMapPropagator(),
    W3CBaggagePropagator(),
]))

#Baggage

#Apa Itu Baggage

Baggage adalah mekanisme untuk meneruskan key-value data antar service tanpa membuat span. Berguna untuk data seperti user ID, tenant ID, atau feature flags yang perlu tersedia di seluruh rantai request.

#Menggunakan Baggage

python
from opentelemetry import baggage
 
# Set baggage di service A
ctx = baggage.set_baggage("user.id", "user_123")
ctx = baggage.set_baggage("tenant.id", "acme_corp", context=ctx)
ctx = baggage.set_baggage("feature.beta", "true", context=ctx)
 
# Propagate context ini ke panggilan berikutnya
# Baggage otomatis ikut lewat header otel-baggage (atau baggage)
 
# Di service B, baca baggage
user_id = baggage.get_baggage("user.id")  # "user_123"
tenant_id = baggage.get_baggage("tenant.id")  # "acme_corp"

#Baggage Header Format

plaintext
baggage: user.id=user_123,tenant.id=acme_corp,feature.beta=true

#Menambahkan Baggage ke Span Attributes

python
from opentelemetry import trace, baggage
 
with tracer.start_as_current_span("handle_request") as span:
    # Copy semua baggage ke span attributes untuk visibility
    entries = baggage.get_all()
    for key, value in entries.items():
        span.set_attribute(f"baggage.{key}", value)

#Metrics

#Membuat dan Menggunakan Metrics

python
from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
 
# Setup meter provider
exporter = OTLPMetricExporter(endpoint="http://localhost:4317", insecure=True)
reader = PeriodicExportingMetricReader(exporter, export_interval_millis=10000)
provider = MeterProvider(metric_readers=[reader])
metrics.set_meter_provider(provider)
 
meter = metrics.get_meter("my-app", "1.0.0")
 
# Counter: monotonically increasing
request_counter = meter.create_counter(
    name="http_requests_total",
    description="Total HTTP requests",
    unit="1"
)
 
# Penggunaan
request_counter.add(1, {"http.method": "GET", "http.status": "200"})

#Tipe Metric

TipeDeskripsiContoh
CounterNilai yang hanya naikTotal request count
UpDownCounterNilai naik atau turunActive connections
HistogramDistribusi nilai dalam bucketRequest latency
Observable CounterCounter dari external sourceCPU time
GaugeNilai sesaatMemory usage

#Histogram dan Observable Gauge

python
# Histogram: ukur distribusi latency
request_duration = meter.create_histogram(
    name="http_request_duration_seconds",
    description="HTTP request duration in seconds",
    unit="s"
)
 
# Record latency
request_duration.record(0.142, {"http.method": "GET", "http.route": "/api/users"})
 
# Observable Gauge: laporkan nilai sesaat
import psutil
 
def cpu_usage_callback(options):
    yield metrics.Observation(psutil.cpu_percent() / 100, {"host": "server-01"})
 
meter.create_observable_gauge(
    name="system_cpu_usage",
    callbacks=[cpu_usage_callback],
    description="CPU usage ratio",
    unit="1"
)

#Logs

#OpenTelemetry Logs

OTel logs dirancang untuk berkorelasi dengan traces. Log bisa dikaitkan dengan span yang sedang aktif secara otomatis.

python
import logging
from opentelemetry import trace
from opentelemetry._logs import set_logger_provider
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
 
# Setup logger provider
logger_provider = LoggerProvider()
set_logger_provider(logger_provider)
logger_provider.add_log_record_processor(
    BatchLogRecordProcessor(OTLPLogExporter(endpoint="http://localhost:4317", insecure=True))
)
 
# Attach ke Python logging
handler = LoggingHandler(level=logging.INFO)
logging.getLogger().addHandler(handler)
 
# Sekarang log otomatis dikirim ke OTel backend dengan trace context
logger = logging.getLogger(__name__)
 
with tracer.start_as_current_span("checkout"):
    logger.info("Processing checkout", extra={"order.id": "12345"})
    # Log ini otomatis dikaitkan dengan span "checkout"

#Collector

#Apa Itu OTel Collector

Collector adalah service proxy yang menerima telemetri dari aplikasi, memproses (filter, transform, batch), dan mengekspor ke backend. Memakai collector memisahkan aplikasi dari backend.

plaintext
App --OTLP--> Collector --OTLP--> Jaeger
                          --OTLP--> Tempo
                          --OTLP--> Prometheus
                          --OTLP--> Datadog

#Collector Configuration

yaml
# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318
 
processors:
  batch:
    timeout: 5s
    send_batch_size: 1000
  memory_limiter:
    check_interval: 1s
    limit_mib: 512
  filter:
    error_mode: ignore
    traces:
      span:
        - 'attributes["http.route"] == "/health"'
  resource:
    attributes:
      - key: deployment.environment
        value: production
        action: upsert
 
exporters:
  otlp/jaeger:
    endpoint: jaeger:4317
    tls:
      insecure: true
  prometheus:
    endpoint: 0.0.0.0:8889
  loki:
    endpoint: http://loki:3100/loki/api/v1/push
 
service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch, filter]
      exporters: [otlp/jaeger]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [prometheus]
    logs:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [loki]

#Menjalankan Collector dengan Docker

bash
docker run -p 4317:4317 -p 4318:4318 \
  -v $(pwd)/otel-collector-config.yaml:/etc/otelcol/config.yaml \
  otel/opentelemetry-collector-contrib:latest

#Backend: Jaeger dan Tempo

#Jaeger

Jaeger adalah distributed tracing backend open-source dari CNCF.

bash
# Jalankan Jaeger all-in-one untuk development
docker run -d --name jaeger \
  -p 16686:16686 \
  -p 4317:4317 \
  -p 4318:4318 \
  jaegertracing/all-in-one:latest
 
# UI tersedia di http://localhost:16686

#Grafana Tempo

Tempo adalah tracing backend dari Grafana Labs, dirancang untuk skala besar dengan object storage.

yaml
# tempo.yaml (minimal config)
server:
  http_listen_port: 3200
distributor:
  receivers:
    otlp:
      protocols:
        grpc:
          endpoint: 0.0.0.0:4317
storage:
  trace:
    backend: local
    local:
      path: /tmp/tempo/blocks
bash
docker run -d -p 3200:3200 -p 4317:4317 \
  -v $(pwd)/tempo.yaml:/etc/tempo.yaml \
  grafana/tempo:latest -config.file=/etc/tempo.yaml

#Sampling

#Mengapa Sampling

Pada traffic tinggi, merekam semua trace mahal. Sampling memilih subset trace untuk direkam.

Tipe SamplingCara Kerja
AlwaysOnRekam semua trace
AlwaysOffJangan rekam trace sama sekali
TraceIDRatioBasedRekam persentase berdasarkan trace ID
ParentBasedIkuti keputusan sampler parent (head-based)
OTLP (tail-based)Sampling di Collector berdasarkan trace lengkap

#Konfigurasi Sampler (Python)

python
from opentelemetry.sdk.trace.sampling import (
    TraceIdRatioBased, ParentBased, ALWAYS_ON
)
 
sampler = ParentBased(root=TraceIdRatioBased(rate=0.1))  # 10% sampling
provider = TracerProvider(resource=resource, sampler=sampler)

#Glossary

  • Trace: Rekaman perjalanan satu request melalui sistem terdistribusi.
  • Span: Unit kerja tunggal dalam trace, dengan start time, end time, dan metadata.
  • Span Context: Identitas span (trace ID, span ID, trace flags).
  • Context Propagation: Meneruskan trace context antar service lewat header.
  • Baggage: Key-value data yang dipropagate antar service tanpa span.
  • Instrumentation: Kode yang menghasilkan telemetri (span, metric, log).
  • Auto-Instrumentation: Instrumentation otomatis untuk library populer tanpa ubah kode.
  • OTLP (OpenTelemetry Protocol): Protokol standar untuk transfer data telemetri.
  • Collector: Service proxy yang menerima, memproses, dan mengekspor telemetri.
  • Exporter: Komponen yang mengirim telemetri ke backend.
  • Resource: Metadata yang mendeskripsikan entity yang dipantau (service name, version).
  • Attributes: Key-value metadata pada span, metric, atau log.
  • Events: Timestamped log dalam span.
  • Span Kind: Klasifikasi span (SERVER, CLIENT, INTERNAL, PRODUCER, CONSUMER).
  • Jaeger: Distributed tracing backend open-source dari CNCF.
  • Tempo: Tracing backend dari Grafana Labs.
  • Sampling: Memilih subset trace untuk direkam demi efisiensi.
  • Propagator: Komponen yang melakukan inject dan extract context.
  • W3C TraceContext: Standar propagasi trace context lewat header traceparent.
  • Semantic Conventions: Konvensi penamaan attribute standar OTel (mis. http.method, db.system).

Baca Cheat Sheet Lengkap

Login atau daftar akun gratis untuk membaca cheat sheet ini.

LoginDaftar Gratis
Share: