Nilai Sebenarnya Grafana Ada di Sini
Dashboard metrik memberi tahu bahwa ada masalah. Log memberi tahu apa yang terjadi. Trace memberi tahu di mana waktunya habis. Grafana adalah satu-satunya tempat ketiganya bisa dijelajahi dengan time range yang sama.
- Alert berbunyi: p99 checkout melewati 3 detik.
- Buka dashboard, lihat lonjakan mulai 14:32.
- Anotasi menunjukkan deploy pada 14:30. Tersangka pertama.
- Klik satu titik pada grafik โ exemplar โ trace request yang lambat.
- Trace menunjukkan 2,8 detik dihabiskan di satu kueri database.
- Dari span itu, klik ke log Loki yang punya
trace_idsama. - Log menunjukkan kueri tanpa indeks pada kolom baru dari deploy tadi.
Tujuh langkah, tanpa SSH ke satu server pun. Inilah yang perlu dikonfigurasi di bab ini.
LogQL โ Cukup untuk Dipakai Sehari-hari
// 1. stream selector โ WAJIB, dan wajib selektif
{layanan="ledger", env="produksi"}
// 2. filter baris
{layanan="ledger"} |= "error" // mengandung
{layanan="ledger"} != "healthcheck" // tidak mengandung
{layanan="ledger"} |~ "timeout|refused" // regex
{layanan="ledger"} !~ "debug.*" // regex negatif
// 3. parser โ ekstrak field dari baris
{layanan="ledger"} | json // log JSON
{layanan="ledger"} | logfmt // format key=value
{layanan="ledger"} | pattern " - - <_> \" <_>\""
{layanan="ledger"} | regexp "durasi=(?P[0-9.]+)"
// 4. filter label hasil parsing
{layanan="ledger"} | json | status >= 500 | durasi > 1.5
// 5. format keluaran
{layanan="ledger"} | json | line_format "{{.method}} {{.uri}} -> {{.status}}"
// 6. metrik dari log โ inilah yang membuat Loki kuat
sum by (status) (rate({layanan="ledger"} | json [5m]))
sum(count_over_time({layanan="ledger"} |= "error" [5m]))
quantile_over_time(0.95,
{layanan="ledger"} | json | unwrap durasi [5m]) by (route)Setiap kombinasi label unik di Loki membuat stream terpisah, dan setiap stream punya chunk sendiri. Label seperti trace_id, user_id, atau request_id akan menciptakan jutaan stream dan melumpuhkan Loki.
โ {layanan="api", trace_id="abc123", user_id="4821"}
โ
{layanan="api", env="produksi", level="error"}
lalu cari trace_id di dalam ISI baris: |= "abc123"Filosofi Loki: index kecil, isi baris di-scan. Label hanya untuk hal berkardinalitas rendah; semua yang bervariasi tinggi tetap di dalam teks log dan dicari lewat filter.
Derived Fields: Dari Log Melompat ke Trace
datasources:
- name: Loki
uid: loki-utama
type: loki
access: proxy
url: http://loki:3100
jsonData:
maxLines: 1000
derivedFields:
- name: TraceID
matcherRegex: 'trace_id=(\w+)'
url: '${__value.raw}'
datasourceUid: tempo-utama
urlDisplayLabel: 'Lihat trace'
- name: OrderID
matcherRegex: 'order_id=(\w+)'
url: 'https://admin.internal/pesanan/${__value.raw}'Hasilnya: setiap baris log yang mengandung trace_id=abc123 mendapat tombol "Lihat trace" yang langsung membuka Tempo.
Exemplar: Dari Metrik Melompat ke Trace
Exemplar adalah contoh request yang dilekatkan pada sebuah sampel histogram, lengkap dengan trace_id. Ia muncul sebagai titik kecil berlian pada grafik.
global:
scrape_interval: 15s
storage:
exemplars:
max_exemplars: 100000 # WAJIB, default 0 = fitur matijsonData:
exemplarTraceIdDestinations:
- name: trace_id
datasourceUid: tempo-utama
urlDisplayLabel: 'Lihat trace'Di sisi aplikasi, exemplar harus ikut diekspos โ pada client Prometheus modern ini berarti mengaktifkan format OpenMetrics dan menyertakan trace_id saat mencatat observasi histogram.
Trace to Logs dan Logs to Metrics
datasources:
- name: Tempo
uid: tempo-utama
type: tempo
access: proxy
url: http://tempo:3200
jsonData:
tracesToLogsV2:
datasourceUid: loki-utama
spanStartTimeShift: '-5m'
spanEndTimeShift: '5m'
tags: [{ key: 'service.name', value: 'layanan' }]
filterByTraceID: true
filterBySpanID: false
tracesToMetrics:
datasourceUid: prom-utama
spanStartTimeShift: '-2m'
spanEndTimeShift: '2m'
tags: [{ key: 'service.name', value: 'layanan' }]
queries:
- name: 'Request rate layanan ini'
query: 'sum(rate(http_requests_total{layanan="$${__tags.layanan}"}[5m]))'
serviceMap:
datasourceUid: prom-utama
nodeGraph:
enabled: trueSebuah span berlangsung 300 ms, tetapi log yang relevan mungkin tercatat beberapa detik sebelum atau sesudahnya. Tanpa pergeseran waktu, pencarian log yang dipicu dari span sering mengembalikan nol hasil dan orang menyimpulkan "korelasinya tidak jalan".
Correlations: Menghubungkan Data Source Apa Pun
Fitur Correlations membuat aturan lompatan yang lebih umum daripada derived fields โ dari data source apa pun ke data source apa pun, dengan variabel yang diambil dari hasil kueri.
Sumber : Prometheus, field "instance"
Target : Loki
Kueri : {instance="${instance}"} |= "error"
Label : "Log dari instance ini"Explore Split View โ Alat Investigasi Utama
Tekan Split di Explore untuk membuka dua panel bersebelahan dengan time range tersinkron: metrik di kiri, log di kanan. Menggeser rentang di satu sisi menggeser keduanya. Dalam praktik, inilah tempat sebagian besar debugging benar-benar terjadi โ bukan di dashboard.
Log Panel di Dashboard
{
"type": "logs",
"title": "Error terbaru โ $layanan",
"datasource": { "type": "loki", "uid": "loki-utama" },
"targets": [{
"refId": "A",
"expr": "{layanan=~\"$layanan\", env=\"$env\"} | json | level=\"error\"",
"maxLines": 100
}],
"options": {
"showTime": true,
"wrapLogMessage": true,
"prettifyLogMessage": true,
"enableLogDetails": true,
"dedupStrategy": "exact",
"sortOrder": "Descending"
}
}dedupStrategy sangat berguna: exact melipat baris identik yang berulang, sehingga satu error yang terjadi 5.000 kali tidak menenggelamkan yang lain.