Kodeloka
  1. Kodeloka
  2. Kelas OpenTelemetry
  3. Materi

1 · Fondasi · Modul 2 dari 8

Instrumentasi Otomatis & Manual

Memasang instrumentasi tanpa mengubah kode, lalu menambahkan span sendiri di tempat yang memang penting.

Mulai dari Instrumentasi Otomatis

Instrumentasi otomatis membungkus pustaka populer — kerangka kerja HTTP, klien basis data, klien pesan — dan menghasilkan span tanpa perubahan kode aplikasi. Ini titik awal yang benar karena langsung memberi gambaran utuh sebelum satu baris pun ditulis.

# Node.js
npm install @opentelemetry/auto-instrumentations-node
node --require @opentelemetry/auto-instrumentations-node/register app.js

# Python
pip install opentelemetry-distro opentelemetry-instrumentation
opentelemetry-bootstrap -a install
opentelemetry-instrument python app.py

# Java — agen tanpa perubahan kode sama sekali
java -javaagent:opentelemetry-javaagent.jar -jar aplikasi.jar
⚠️ Go tidak memiliki instrumentasi otomatis penuh

Karena Go dikompilasi statis tanpa mekanisme penambalan saat runtime, pendekatan agen seperti pada Java tidak tersedia. Instrumentasi Go dilakukan dengan membungkus handler dan klien secara eksplisit menggunakan paket otelhttp, otelgrpc, dan sejenisnya. Rencanakan usaha lebih besar untuk layanan Go.

Menyiapkan SDK

import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc";
import { resourceFromAttributes } from "@opentelemetry/resources";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";

const sdk = new NodeSDK({
    resource: resourceFromAttributes({
        "service.name": "layanan-pesanan",
        "service.version": "2.4.1",
        "deployment.environment": "produksi"
    }),
    traceExporter: new OTLPTraceExporter({ url: "http://collector:4317" }),
    instrumentations: [getNodeAutoInstrumentations()]
});

sdk.start();

process.on("SIGTERM", () => {
    sdk.shutdown().finally(() => process.exit(0));
});
🚫 Tanpa shutdown yang rapi, span terakhir hilang

Prosesor batch menahan span di memori sampai batas waktu atau ukuran batch tercapai. Bila proses berhenti tanpa shutdown(), seluruh isi buffer lenyap — dan justru span-span itulah yang paling dibutuhkan, karena berkaitan dengan momen aplikasi bermasalah atau dimatikan. Selalu pasang penangan SIGTERM.

Menambahkan Span Sendiri

import { trace, SpanStatusCode } from "@opentelemetry/api";

const tracer = trace.getTracer("layanan-pesanan", "2.4.1");

async function prosesPesanan(pesanan) {
    return tracer.startActiveSpan("proses-pesanan", async (span) => {
        try {
            span.setAttribute("pesanan.id", pesanan.id);
            span.setAttribute("pesanan.jumlah_item", pesanan.item.length);
            span.setAttribute("pesanan.total", pesanan.total);

            await validasi(pesanan);
            span.addEvent("validasi-selesai");

            const hasil = await bayar(pesanan);
            span.setAttribute("pembayaran.penyedia", hasil.penyedia);

            span.setStatus({ code: SpanStatusCode.OK });
            return hasil;
        } catch (e) {
            span.recordException(e);
            span.setStatus({ code: SpanStatusCode.ERROR, message: e.message });
            throw e;
        } finally {
            span.end();                    // WAJIB, apa pun yang terjadi
        }
    });
}
🚫 Span yang tidak pernah di-end adalah kebocoran memori

Span aktif tetap tersimpan di memori sampai ditutup. Bila jalur galat melewati span.end(), span menumpuk seiring waktu hingga proses kehabisan memori — dan trace-nya tidak pernah terkirim sehingga masalahnya tak terlihat di backend. Selalu letakkan end() pada blok finally.

startActiveSpan versus startSpan

// startActiveSpan — span menjadi induk otomatis bagi span di dalamnya
tracer.startActiveSpan("induk", (span) => {
    panggilFungsiLain();       // span di sini otomatis menjadi anak
    span.end();
});

// startSpan — TIDAK masuk konteks aktif
const span = tracer.startSpan("terpisah");
panggilFungsiLain();           // span di sini TIDAK menjadi anak
span.end();
⚠️ Trace yang terputus biasanya berasal dari pilihan ini

Gejalanya khas: span muncul di backend tetapi sebagai trace terpisah tanpa induk, sehingga rangkaian permintaan terpecah-pecah. Penyebab paling umum adalah pemakaian startSpan ketika yang dibutuhkan startActiveSpan. Penyebab kedua adalah konteks yang hilang saat melintasi antrean callback atau pekerjaan latar.

Atribut yang Layak Ditambahkan

Berguna     ID entitas, nama penyewa, jenis paket langganan,
            varian uji A/B, versi klien, hasil keputusan bisnis,
            jumlah item, ukuran hasil, status cache

Hindari     seluruh badan permintaan, sandi, token, data pribadi,
            nomor kartu, isi respons berukuran besar
⚠️ Atribut ikut terkirim ke backend pihak ketiga

Telemetri sering dikirim ke layanan SaaS dengan kendali akses yang berbeda dari basis data produksi. Data pribadi yang masuk sebagai atribut span berpindah ke sana dan tersimpan berbulan-bulan. Perlakukan atribut seperti log: sunting field sensitif sebelum ditambahkan, atau bersihkan di Collector dengan prosesor attributes.