Logging #
Log adalah catatan peristiwa yang terjadi dalam sistem — setiap request yang masuk, setiap error yang muncul, setiap transaksi yang diproses. Di lingkungan single server lama, kamu bisa SSH dan baca log langsung. Di cloud dengan ratusan instance yang datang dan pergi, aplikasi yang berjalan di container yang di-replace setiap deploy, dan microservices yang tersebar di banyak region — log harus dikumpulkan, diagregasi, dan dicari secara terpusat. Log yang dikelola dengan baik adalah hal pertama yang kamu buka saat terjadi insiden. Log yang tidak dikelola dengan baik adalah sumber frustrasi yang memperpanjang waktu pemulihan.
Mengapa Log Penting #
Log adalah satu-satunya sumber kebenaran tentang apa yang terjadi:
Saat terjadi error:
→ HTTP 500 dari mana? Kenapa? Siapa user-nya?
→ Tanpa log: tidak tahu, harus reproduce secara manual
→ Dengan log: langsung lihat stack trace, input yang menyebabkan error
Saat menginvestigasi insiden:
→ Kapan tepatnya masalah mulai?
→ Apakah ada pola (semua error dari satu user tertentu?
Semua dari satu region? Setelah deploy tertentu?)
→ Tanpa log: spekulasi dan ketidakpastian
→ Dengan log: timeline yang jelas, korelasi yang bisa diverifikasi
Untuk audit dan compliance:
→ Siapa mengakses data apa, kapan?
→ Perubahan konfigurasi apa yang dilakukan dan oleh siapa?
→ Log adalah bukti yang dibutuhkan untuk audit regulasi
Structured Logging vs Plain Text #
Ini adalah perbedaan yang berdampak besar pada kemampuan untuk mencari dan menganalisis log.
// ANTI-PATTERN: Plain text log (tidak terstruktur)
2024-01-15 10:23:45 ERROR Payment failed for user 12345 amount 150000
2024-01-15 10:23:46 INFO Processing order 67890 for user 12345
2024-01-15 10:23:47 WARN Retry attempt 2 for payment 99999
Masalah:
✗ Sulit di-parse secara programatik — format tidak konsisten
✗ Mencari "semua error payment di atas Rp 100.000" → susah
✗ Tidak bisa filter berdasarkan field tertentu
✗ Sulit disambungkan ke trace atau request ID lain
// BENAR: Structured log (JSON)
{
"timestamp": "2024-01-15T10:23:45.123Z",
"level": "ERROR",
"service": "payment-service",
"event": "payment_failed",
"user_id": "12345",
"amount": 150000,
"currency": "IDR",
"payment_method": "credit_card",
"error_code": "INSUFFICIENT_FUNDS",
"trace_id": "abc123xyz",
"duration_ms": 234
}
Keuntungan:
✓ Setiap field bisa di-query secara terpisah
✓ Agregasi: "hitung semua payment_failed per error_code"
✓ Filter: "tunjukkan semua log dengan user_id 12345"
✓ Korelasi: trace_id menghubungkan log dari service yang berbeda
✓ Mudah di-parse oleh log aggregation system
Field Standar yang Harus Ada di Setiap Log #
Field yang wajib ada:
timestamp: waktu kejadian (ISO 8601, UTC)
→ Bukan waktu log diterima server, tapi waktu kejadian
level: DEBUG | INFO | WARN | ERROR | FATAL
service: nama service yang menghasilkan log
message: deskripsi singkat kejadian
Field kontekstual yang sangat berguna:
trace_id: ID unik untuk satu request end-to-end
→ Hubungkan log dari berbagai service untuk satu request
request_id: ID unik per HTTP request
user_id: siapa pengguna yang terlibat (jika ada)
session_id: ID session pengguna
environment: prod | staging | dev
Field untuk error:
error_code: kode error yang machine-readable
error_msg: pesan error yang human-readable
stack_trace: stack trace lengkap (untuk ERROR dan FATAL)
Field untuk performa:
duration_ms: berapa lama operasi berlangsung
status_code: HTTP status code (untuk request log)
Log Levels — Gunakan dengan Benar #
Log level yang tepat membuat filtering menjadi bermakna:
DEBUG:
→ Detail teknis untuk debugging
→ Jangan aktifkan di production (volume sangat tinggi, biaya mahal)
→ Aktifkan sementara saat debugging masalah spesifik
Contoh: "Memulai koneksi ke database, host=db-primary, port=5432"
INFO:
→ Peristiwa normal yang penting untuk dipantau
→ Default level untuk production
Contoh: "Order 12345 berhasil dibuat oleh user 67890"
"Service started on port 8080"
WARN:
→ Sesuatu yang tidak normal tapi belum menyebabkan kegagalan
→ Bisa jadi indikator masalah yang akan datang
Contoh: "Database connection pool 85% full"
"API response time 2.3s, mendekati threshold 3s"
"Retry attempt 2/3 untuk payment 99999"
ERROR:
→ Operasi gagal tapi service masih bisa berjalan
→ Membutuhkan perhatian tapi tidak urgent
Contoh: "Payment gagal untuk order 12345: INSUFFICIENT_FUNDS"
"Gagal kirim email notifikasi ke user 67890"
FATAL:
→ Kegagalan kritis yang menyebabkan service berhenti
→ Butuh respons segera
Contoh: "Tidak bisa connect ke database setelah 10 retry"
"Konfigurasi kritis tidak ditemukan, service tidak bisa start"
// ANTI-PATTERN yang umum:
✗ Log ERROR untuk semua kondisi yang tidak diharapkan
→ WARN lebih tepat untuk sesuatu yang masih ditangani
✗ Log INFO untuk setiap baris kode
→ Volume terlalu tinggi, signal tenggelam dalam noise
✗ Tidak pernah log di level WARN
→ Kehilangan sinyal peringatan dini
Pengiriman Log ke Sistem Terpusat #
Di cloud, log tidak boleh hanya ada di disk lokal instance atau container. Instance bisa di-replace kapan saja — log yang hanya ada di disk lokal hilang bersamanya.
Pola Pengiriman Log (Twelve-Factor: write to stdout):
Aplikasi
│ write ke stdout/stderr
▼
Container Runtime / OS
│ capture stdout
▼
Log Agent (Fluentd, Fluent Bit, CloudWatch Agent)
│ collect, parse, enrich
▼
Log Aggregation Service
(CloudWatch Logs, Elasticsearch/OpenSearch,
Datadog, Grafana Loki, Splunk)
│
▼
Penyimpanan + Query + Alert
Aturan penting:
✓ Aplikasi hanya tulis ke stdout — tidak kelola file log sendiri
✓ Agent yang handle routing, parsing, enrichment
✓ Log aggregation di luar lifecycle container/instance
✓ Log tersedia bahkan setelah instance mati atau di-replace
Retensi Log dan Biaya #
Log tersimpan = biaya storage yang terus berjalan.
Strategi retensi yang tepat menyeimbangkan kebutuhan vs biaya:
Hot tier (query cepat): 7-30 hari
→ Log yang paling sering dikonsultasi saat debugging
→ Storage paling mahal
→ Query langsung dari UI
Warm tier (query lebih lambat): 30-90 hari
→ Untuk investigasi insiden yang lebih lama
→ Storage lebih murah
→ Masih bisa di-query
Archive / Cold: 90 hari - 7 tahun
→ Untuk compliance dan audit regulasi
→ Biaya sangat murah (object storage)
→ Restore sebelum bisa di-query
Contoh regulasi yang mempengaruhi retensi:
→ PCI-DSS: log minimal 1 tahun (3 bulan online)
→ HIPAA: 6 tahun
→ SOC 2: bervariasi
→ Cek regulasi yang berlaku untuk industri dan negara kamu
Cara mengurangi biaya log tanpa mengorbankan signal:
✓ Jangan log DEBUG di production
✓ Sampling untuk log volume tinggi yang low-value
(misalnya: health check hits — log 1 dari 100 saja)
✓ Compressed storage untuk archive
✗ Jangan hapus log ERROR dan WARN — ini terlalu berharga
Apa yang Tidak Boleh Ada di Log #
Log bisa menjadi sumber kebocoran data jika tidak hati-hati:
✗ Password dan credentials
Jangan log apapun dari request body yang mungkin berisi password
✗ Full credit card number atau CVV
PCI-DSS melarang ini secara eksplisit
Boleh log 4 digit terakhir saja: "****1234"
✗ Personal Identifiable Information (PII) lengkap
Nama lengkap + alamat + nomor telepon = PII
Log user_id saja, bukan data personal lengkap
✗ Access token, session token, API key
Token yang ada di log bisa digunakan untuk akses tidak sah
Mask atau truncate jika perlu log token untuk debugging
✗ Health information (untuk HIPAA)
Diagnosis, hasil tes, informasi medis — tidak boleh di log
tanpa enkripsi dan kontrol akses khusus
// BENAR: Log identifier, bukan data sensitif
✓ user_id: "u12345" (bukan nama lengkap)
✓ card_last4: "1234" (bukan nomor penuh)
✓ amount: 150000 (aman)
✓ email_hash: "sha256(email)" jika butuh korelasi email
Ringkasan #
- Structured logging (JSON) wajib di cloud — plain text tidak bisa di-query dan di-analisis secara efisien di sistem log terpusat.
- Timestamp, level, service, trace_id, dan message adalah field minimum — trace_id yang konsisten antar service memungkinkan korelasi request end-to-end.
- Gunakan log level dengan tepat — INFO untuk operasi normal, WARN untuk kondisi tidak normal yang belum gagal, ERROR untuk kegagalan yang terisolasi.
- Tulis ke stdout, biarkan platform yang routing — prinsip Twelve-Factor yang memastikan log tersedia di luar lifecycle container/instance.
- Retensi bertingkat untuk keseimbangan biaya vs kebutuhan — hot tier untuk debugging aktif, archive untuk compliance, lifecycle policy untuk otomasi.
- Jangan log data sensitif — password, nomor kartu, PII lengkap, dan token tidak boleh masuk ke log; log identifier saja.