Di artikel sebelumnya, kita sudah membahas observability sebagai cara untuk memahami kondisi sistem dari luar, dan OpenTelemetry sebagai standar untuk menghasilkan telemetry data seperti traces, metrics, dan logs.

Namun setelah aplikasi menghasilkan trace, muncul pertanyaan berikutnya:

Di mana trace itu dilihat?
Bagaimana cara membaca perjalanan sebuah request?
Bagaimana kita tahu service mana yang lambat, error, atau menyebabkan bottleneck?

Di sinilah Jaeger mulai berguna.

Jaeger adalah salah satu tool distributed tracing yang membantu kita melihat perjalanan request di dalam sistem terdistribusi. Kalau sebuah request melewati API gateway, backend service, database, cache, message queue, atau service lain, Jaeger membantu memvisualisasikan alur tersebut dalam bentuk trace yang bisa dibaca manusia.

Recap Singkat: Dari Observability ke OpenTelemetry

Observability membantu kita menjawab pertanyaan seperti:

  • apa yang sedang terjadi di sistem?
  • kenapa request ini lambat?
  • service mana yang error?
  • dependency mana yang menjadi bottleneck?
  • apakah masalah terjadi di aplikasi, network, database, atau service lain?

OpenTelemetry berperan sebagai standar dan toolkit untuk mengumpulkan telemetry data dari aplikasi. Dengan OpenTelemetry, aplikasi bisa menghasilkan trace, metric, dan log dalam format yang lebih konsisten.

Tetapi OpenTelemetry sendiri bukan dashboard utama untuk membaca trace. OpenTelemetry lebih sering berperan sebagai instrumentation layer dan telemetry pipeline. Untuk membaca trace secara visual, kita membutuhkan tracing backend seperti Jaeger.

Masalah yang Coba Diselesaikan Jaeger

Di sistem sederhana, debugging biasanya masih relatif mudah. Kita bisa membuka log aplikasi, melihat error, lalu memperbaiki bagian yang bermasalah.

Namun di sistem modern, satu request sering melewati banyak komponen.

Contohnya:

User
→ API Gateway
→ Auth Service
→ Backend Service
→ Database
→ External Payment API
→ Message Queue
→ Worker

Jika request lambat, kita tidak bisa langsung tahu penyebabnya hanya dari satu log.

Bisa jadi masalahnya ada di database query. Bisa jadi external API lambat. Bisa jadi worker queue penuh. Bisa jadi service internal butuh waktu lama memproses data. Bisa juga request gagal karena dependency di tengah jalan.

Jaeger membantu menjawab pertanyaan seperti:

  • request ini melewati service apa saja?
  • service mana yang paling lama?
  • span mana yang error?
  • dependency mana yang menyebabkan latency?
  • apakah bottleneck terjadi konsisten atau hanya sesekali?

Tanpa distributed tracing, kita sering hanya tahu bahwa request lambat. Dengan Jaeger, kita bisa melihat bagian mana yang sebenarnya membuat request itu lambat.

Apa Itu Jaeger?

Jaeger adalah distributed tracing platform yang digunakan untuk mengumpulkan, menyimpan, dan menampilkan trace dari aplikasi atau service.

Dengan Jaeger, kita bisa melihat satu request sebagai sebuah trace. Di dalam trace tersebut, ada beberapa span yang merepresentasikan pekerjaan kecil yang terjadi selama request diproses.

Contoh span:

  • menerima HTTP request
  • memanggil database
  • memanggil service lain
  • publish message ke queue
  • menjalankan proses di worker
  • menerima response dari external API

Setiap span memiliki durasi, metadata, dan relasi dengan span lain. Relasi inilah yang membuat kita bisa melihat struktur request secara utuh.

Secara sederhana:

Trace = perjalanan lengkap sebuah request
Span  = bagian kecil dari pekerjaan di dalam request tersebut

Konsep Dasar yang Perlu Dipahami

Trace

Trace adalah representasi perjalanan satu request dari awal sampai akhir.

Misalnya user membuka halaman invoice. Request tersebut mungkin melewati frontend, backend, database, dan payment service. Semua perjalanan itu bisa tergabung dalam satu trace.

Trace membantu kita melihat big picture dari sebuah request.

Span

Span adalah unit pekerjaan di dalam trace.

Jika trace adalah perjalanan lengkap, maka span adalah checkpoint di sepanjang perjalanan itu.

Contoh span:

  • span untuk HTTP request
  • span untuk database query
  • span untuk call ke service lain
  • span untuk proses validasi
  • span untuk publish event

Setiap span biasanya memiliki waktu mulai, waktu selesai, durasi, dan metadata.

Parent-child Span

Span bisa memiliki hubungan parent-child.

Contohnya, span utama adalah request ke backend service. Di dalamnya ada child span untuk query database dan call ke external API.

Relasi ini membantu kita memahami urutan dan dependency antar operasi.

Contoh sederhananya:

POST /payments
├── validate request
├── get user from database
├── insert payment record
├── call payment provider
└── publish payment.created event

Dari struktur seperti ini, kita bisa memahami apa saja yang terjadi di dalam satu request tanpa harus membuka banyak log secara manual.

Tags atau Attributes

Tags atau attributes adalah metadata tambahan pada span.

Contoh:

  • HTTP method
  • HTTP status code
  • endpoint
  • database statement
  • service name
  • error message
  • environment

Metadata ini penting karena membantu kita melakukan filtering dan debugging.

Misalnya, kita ingin mencari semua trace dengan status code 500, atau semua trace yang terjadi pada service tertentu. Attribute seperti ini membuat proses investigasi menjadi jauh lebih cepat.

Duration dan Latency

Salah satu kekuatan distributed tracing adalah melihat durasi setiap span.

Dari sini, kita bisa tahu bagian mana yang paling banyak memakan waktu. Kadang total request lambat bukan karena aplikasi utama lambat, tetapi karena dependency eksternal membutuhkan waktu terlalu lama.

Misalnya:

POST /payments                 2000ms
├── validate request              5ms
├── get user from database       30ms
├── insert payment record        40ms
├── call payment provider      1800ms
├── publish payment event        20ms
└── return response               5ms

Dari contoh ini, bottleneck paling jelas ada di call payment provider, bukan di database atau application logic utama.

Bagaimana Jaeger Bekerja di Arsitektur Modern

Secara sederhana, alurnya seperti ini:

Application
→ OpenTelemetry SDK
→ OpenTelemetry Collector
→ Jaeger
→ Jaeger UI

Aplikasi menghasilkan trace melalui instrumentation. Instrumentation ini bisa dibuat manual atau otomatis menggunakan OpenTelemetry SDK.

Data trace kemudian dikirim ke OpenTelemetry Collector. Collector bertugas menerima, memproses, dan meneruskan telemetry data ke backend tertentu.

Salah satu backend yang bisa menerima trace tersebut adalah Jaeger.

Setelah trace masuk ke Jaeger, kita bisa membukanya melalui Jaeger UI untuk melihat detail request, durasi span, error, dan hubungan antar service.

Jaeger dan OpenTelemetry: Hubungannya Apa?

OpenTelemetry dan Jaeger sering muncul dalam percakapan yang sama, tetapi keduanya punya peran yang berbeda.

OpenTelemetry berperan sebagai standar instrumentation dan telemetry pipeline.

Jaeger berperan sebagai tracing backend dan UI untuk membaca trace.

Dengan kata lain:

OpenTelemetry menghasilkan dan mengirim trace.
Jaeger menyimpan dan menampilkan trace.

Dalam setup modern, aplikasi tidak harus mengirim trace langsung ke Jaeger. Lebih fleksibel jika aplikasi mengirim trace ke OpenTelemetry Collector terlebih dahulu, lalu Collector meneruskan trace ke Jaeger.

Pendekatan ini membuat sistem lebih mudah diubah. Jika suatu hari tracing backend ingin diganti, aplikasi tidak perlu banyak berubah. Cukup ubah konfigurasi di Collector.

Contoh Sederhana Alur Request

Bayangkan sebuah request untuk membuat transaksi pembayaran.

POST /payments

Request tersebut mungkin berjalan seperti ini:

API Service
→ validate request
→ check user
→ create payment record
→ call payment provider
→ publish event
→ return response

Di Jaeger, perjalanan ini bisa terlihat sebagai satu trace dengan beberapa span:

POST /payments
├── validate request
├── get user from database
├── insert payment record
├── call payment provider
├── publish payment.created event
└── return response

Jika request membutuhkan 2 detik, Jaeger bisa membantu menunjukkan bagian mana yang paling lama.

Tanpa tracing, kita mungkin hanya melihat log bahwa request lambat. Dengan Jaeger, kita bisa melihat di mana lambatnya.

Inilah alasan kenapa distributed tracing sangat membantu di sistem yang punya banyak dependency.

Kapan Jaeger Sangat Membantu?

Jaeger sangat berguna ketika sistem mulai memiliki banyak service atau dependency.

Contoh situasi:

  • debugging latency antar microservice
  • mencari bottleneck pada request tertentu
  • memahami dependency antar service
  • menganalisis error yang terjadi di tengah request flow
  • membandingkan performa sebelum dan setelah perubahan deployment
  • memahami alur request yang sudah terlalu kompleks untuk dibaca hanya dari log

Jaeger bukan pengganti log atau metric. Jaeger melengkapi keduanya.

Metric membantu melihat pola secara agregat. Log membantu membaca detail event. Trace membantu memahami perjalanan request.

Ketiganya saling melengkapi dalam observability.

Hal yang Perlu Diperhatikan Saat Menggunakan Jaeger

Jaeger sangat membantu, tetapi ada beberapa hal yang perlu diperhatikan.

Pertama, tracing bisa menghasilkan data yang banyak. Jika semua request selalu ditrace tanpa sampling, storage dan biaya bisa meningkat.

Kedua, instrumentation harus dirancang dengan masuk akal. Terlalu sedikit span membuat trace kurang berguna. Terlalu banyak span membuat trace sulit dibaca.

Ketiga, metadata pada span harus informatif tetapi tidak boleh membocorkan data sensitif. Hindari menyimpan token, password, personal data, atau payload sensitif sebagai attribute.

Keempat, service name harus konsisten. Jika nama service berubah-ubah, trace akan sulit difilter dan dianalisis.

Kelima, Jaeger akan jauh lebih berguna jika trace context ikut diteruskan antar service. Jika context propagation tidak berjalan, trace bisa terpecah dan sulit dibaca sebagai satu alur request yang utuh.

Penutup

Jaeger membantu membuat distributed tracing menjadi lebih mudah dibaca.

Jika OpenTelemetry adalah cara aplikasi menghasilkan dan mengirim telemetry data, maka Jaeger adalah tempat kita melihat perjalanan request secara visual.

Dengan Jaeger, kita bisa memahami service mana yang terlibat, operasi mana yang lambat, dan dependency mana yang berpotensi menyebabkan masalah.

Di tahap awal, tujuan menggunakan Jaeger bukan untuk membuat sistem observability yang sempurna. Tujuannya adalah membuat debugging menjadi lebih jelas.

Karena dalam sistem terdistribusi, masalah terbesar sering bukan hanya error-nya, tetapi tidak tahu di mana error itu benar-benar terjadi.