Dalam 15 menit ke depan, kita akan merakit stack OpenTelemetry dari nol sampai berjalan mulus untuk membedah latensi mikrolayanan kita. Bayangkan malam-malam penuh tekanan saat dashboard monitoring menyala merah, sementara log di Nginx, PHP-FPM, dan Go backend saling tunjuk tanpa ada yang mau mengaku siapa biang keladi di balik request yang molor hingga 8 detik. Di sinilah distributed tracing menyelamatkan kewarasan kita, dan alih-alih membaca teori abstrak, mari kita langsung masuk ke dapur produksi dan meraciknya sendiri.
1. Menu Kita Hari Ini & Alat yang Perlu Disiapkan
Untuk membongkar akar masalah latensi ini, kita butuh bahan-bahan open-source kelas berat yang sudah teruji di medan perang produksi: Go dan Node.js untuk layanan mikrolayanan kita, OpenTelemetry Collector sebagai pengumpul data, Jaeger sebagai visualisator jejak (trace), serta sedikit sentuhan Nginx sebagai pintu gerbang reverse proxy. Pastikan Docker dan Docker Compose sudah terpasang rapi di mesin lokal atau staging Anda, karena kita akan menghidupkan seluruh ekosistem ini dalam hitungan menit.
[!TIP] Siapkan terminal yang nyaman dan secangkir kopi. Kita akan menulis beberapa baris kode instrumentasi lalu melihat langsung bagaimana trace mengalir secara real-time.
Sebelum kita menyalakan mesin, mari kita petakan dulu bagaimana aliran data ini nantinya akan berjalan melintasi batas-batas bahasa pemrograman.
2. Peta Jalan Singkat: Apa yang Sedang Kita Rakit
Bayangkan sebuah alur request tipikal: pengguna mengakses frontend web, yang kemudian melempar panggilan HTTP ke gateway berbasis Node.js, diteruskan ke backend core berkecepatan tinggi berbasis Go, sebelum akhirnya menghujam database Redis dan MySQL. Tanpa pelacak lintas layanan, mencari tahu mengapa request tersebut lambat sama dengan mencari jarum di tumpukan jerami digital.
[Client] ---> [Nginx Proxy] ---> [Node.js Gateway] ---> [Go Backend] ---> [Redis/MySQL]
| | |
+----------------------+-------------------+
|
v
[OpenTelemetry Collector]
|
v
[Jaeger UI (Trace)]
Langkah pertama yang harus kita bereskan adalah membangun fondasi environment dan orkestrasi penampung datanya agar siap menerima aliran telemetri dari mikrolayanan kita.
3. Langkah 1: Mempersiapkan Fondasi & Environment
Kita mulai dengan merangkai infrastruktur pengumpul data menggunakan Docker Compose. Buat file bernama docker-compose.yml di direktori kerja Anda. File ini akan menjalankan Jaeger backend dan OpenTelemetry Collector yang bertugas menerima, memproses, dan memuntahkan data trace ke layar analitik.
version: '3.8'
services:
jaeger:
image: jaegertracing/all-in-one:1.50
container_name: jaeger
environment:
- COLLECTOR_OTLP_ENABLED=true
ports:
- "16686:16686" # Jaeger UI
- "4317:4317" # OTLP gRPC receiver
- "4318:4318" # OTLP HTTP receiver
otel-collector:
image: otel/opentelemetry-collector:0.88.0
container_name: otel-collector
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
ports:
- "8888:8888" # Prometheus metrics exposed by the collector
- "4319:4319" # OTLP receiver alternative
depends_on:
- jaeger
Jalankan docker-compose up -d, lalu periksa apakah kontainer Jaeger sudah bisa diakses melalui http://localhost:16686. Jika antarmuka web Jaeger menyambut Anda dengan bersih, fondasi kita sudah kokoh berdiri. Dari sini, kita perlu mendefinisikan bagaimana Collector mengelola lalu lintas data tersebut.
4. Langkah 2: Meracik Konfigurasi Inti Tanpa Basa-basi
Collector OpenTelemetry butuh aturan main tentang dari mana data harus diambil dan ke mana ia harus dikirimkan. Buat file konfigurasi bernama otel-collector-config.yaml tepat di sebelah file compose tadi.
receivers:
otlp:
protocols:
grpc:
http:
exporters:
logging:
verbosity: detailed
otlp:
endpoint: "jaeger:4317"
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
exporters: [logging, otlp]
Konfigurasi di atas memerintahkan Collector untuk mendengarkan sinyal OTLP baik via gRPC maupun HTTP, mencetak detailnya ke log konsol lokal untuk keperluan debugging, lalu meneruskannya secara mulus ke backend Jaeger. Dengan infrastruktur pengumpul yang siap siaga, saatnya kita menyuntikkan kode instrumentasi ke dalam jantung mikrolayanan kita.
5. Langkah 3: Sentuhan Akhir Keamanan & Optimasi
Sekarang mari kita instrumen mikrolayanan kita. Kita mulai dari sisi Node.js (Gateway) yang menerima request pertama, lalu meneruskannya ke layanan Go (Backend). Buat file tracer.js di proyek Node.js Anda untuk mengaktifkan SDK OpenTelemetry:
'use strict';
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
const exporter = new OTLPTraceExporter({
url: 'http://localhost:4318/v1/traces',
});
const sdk = new NodeSDK({
resourceDetectors: [],
traceExporter: exporter,
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
process.on('SIGTERM', () => {
sdk.shutdown()
.then(() => console.log('Tracing terminated'))
.catch((error) => console.log('Error terminating tracing', error))
.finally(() => process.exit(0));
});
[!IMPORTANT] Pastikan Anda mengimpor dan menjalankan
tracer.jsini di baris paling atas dari file entry point aplikasi Node.js Anda (index.jsatauapp.js) sebelum modul HTTP atau Express dimuat.
Selanjutnya, mari beralih ke mikrolayanan Go kita. Di sinilah biasanya proses berat terjadi, mulai dari query database kompleks hingga pemrosesan payload besar. Berikut cuplikan inisialisasi OpenTelemetry di Go:
package main
import (
"context"
"log"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
googleGrpc "google.golang.org/grpc"
)
func InitTracer() (*sdktrace.TracerProvider, error) {
ctx := context.Background()
exporter, err := otlptracegrpc.New(ctx,
otlptracegrpc.WithInsecure(),
otlptracegrpc.WithEndpoint("localhost:4317"),
)
if err != nil {
return nil, err
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("core-backend-go"),
)),
)
otel.SetTracerProvider(tp)
return tp, nil
}
Dengan kode ini, setiap pemanggilan fungsi atau query HTTP keluar dari layanan Go akan otomatis menyisipkan header propagasi traceparent, sehingga Jaeger dapat merangkainya menjadi satu garis waktu yang utuh. Mari kitauji hasil kerja keras ini.
6. Tes Rasa: Memastikan Semuanya Berjalan Sempurna
Jalankan layanan Node.js dan Go Anda, lalu tembak endpoint API gateway menggunakan curl:
curl -i http://localhost:3000/api/v1/checkout
Perhatikan respons yang dikembalikan oleh server. Setelah request selesai, buka browser Anda dan arahkan ke http://localhost:16686. Pilih layanan node-gateway atau core-backend-go pada menu dropdown Service di Jaeger UI, lalu klik "Find Traces". Anda akan melihat diagram air terjun (waterfall chart) yang sangat informatif, menampilkan durasi milidetik dari setiap span, mempermudah kita mendeteksi persis di baris mana latensi menumpuk.
7. Pertolongan Pertama: Jika Terjadi Kendala Kecil
Jika ternyata trace tidak kunjung muncul di Jaeger UI, jangan panik. Pertama, cek log dari otel-collector menggunakan docker logs otel-collector. Jika Anda melihat pesan error koneksi ditolak (connection refused), pastikan port 4317 dan 4318 tidak sedang digunakan oleh aplikasi lain di host Anda. Kedua, pastikan variabel lingkungan atau endpoint eksportir di kode Node.js dan Go menunjuk ke alamat host yang tepat (jika dijalankan di luar kontainer, gunakan localhost, namun jika di dalam Docker network yang sama, gunakan nama service seperti jaeger atau otel-collector). Dengan penyesuaian kecil ini, pipeline telemetri Anda kini siap menghadapi badai trafik produksi apa pun.