Chapter sebelumnya menunjukkan cara menemukan sumber daya yang jenuh — tetapi angka load atau persentase memori tidak pernah menceritakan mengapa. Jawabannya tersimpan di log: setiap service yang gagal start, setiap koneksi yang ditolak, setiap proses yang dibunuh OOM killer meninggalkan baris berstempel waktu. Menguasai monitoring log berarti menguasai tiga keterampilan: menyaring jutaan baris menjadi puluhan yang relevan, mengikuti log yang tumbuh secara langsung, dan mengorelasikan stempel waktu dengan keluhan pengguna. Chapter ini melatih ketiganya, lalu menutup dengan rotasi log yang menjaga file tetap ramping.
Log sebagai Jejak Diagnosis #
Metrik dan log saling melengkapi: metrik menjawab apa yang jenuh, log menjawab mengapa dan sejak kapan. Di sistem dengan systemd, pintu masuk utamanya adalah journalctl -u nginx -f — flag -u nginx membatasi ke unit nginx, flag -f (follow) membuat journalctl terus mencetak baris baru saat jurnal bertambah; opsi lengkapnya terdokumentasi di journalctl(1)
. Berikut contoh tampilannya saat upstream database bermasalah:
Jan 15 08:03:02 server-kantor nginx[1204]: *1 connect() failed (111: Connection refused) while connecting to upstream
Jan 15 08:03:11 server-kantor nginx[1204]: *1 upstream timed out (110: Connection timed out) while reading response header
Jan 15 08:03:40 server-kantor nginx[1204]: *1 no live upstreams while connecting to upstreamDi server tanpa jurnal, jalur klasiknya adalah file teks: /var/log/syslog menampung pesan semua sumber, /var/log/auth.log mencatat percobaan login, dan aplikasi kerap menulis log sendiri seperti /var/log/nginx/error.log. Format dan rotasinya sudah kita bedah di chapter Logs dan Log Rotation
; fokus kali ini adalah cara membacanya saat insiden berlangsung.
Menyaring Error dengan grep #
Log yang tumbuh cepat membuat mata tidak bisa lagi memindai manual — itu pekerjaan grep. Pola yang paling sering dipakai untuk berburu masalah adalah grep -iE 'error|fail|critical' app.log: flag -i mengabaikan besar-kecil huruf (aplikasi menulis ERROR, Error, dan error secara tidak konsisten), sedangkan -E mengaktifkan extended regex sehingga tanda | berarti “atau”. Hasilnya: semua baris yang memuat salah satu dari tiga kata kunci itu. Semua opsi penyaringannya dirinci di grep(1)
.
Praktik: Menyisir Log Aplikasi #
File app.log di bundle materi ini berisi sepuluh baris log web server dengan timestamp ISO 8601 — gabungan baris normal (INFO), peringatan (WARN), dan kegagalan (ERROR):
2026-01-15T08:00:03Z INFO server web menyala di port 8080
2026-01-15T08:00:04Z INFO koneksi database siap
2026-01-15T08:02:41Z INFO GET /api/pesanan 200 (12 ms)
2026-01-15T08:03:02Z ERROR gagal koneksi ke database: connection refused
2026-01-15T08:03:05Z ERROR retry koneksi database gagal (percobaan 1)
2026-01-15T08:03:08Z ERROR retry koneksi database gagal (percobaan 2)
2026-01-15T08:03:11Z WARN antrean request menumpuk setelah error: 47 item
2026-01-15T08:03:40Z INFO koneksi database pulih
2026-01-15T08:04:02Z INFO GET /api/pesanan 200 (15 ms)
2026-01-15T08:05:00Z INFO backup harian selesaiKita mulai dengan saringan paling kasar — semua baris yang berbau masalah:
grep -iE 'error|fail|critical' app.logOutput yang Dihasilkan:
2026-01-15T08:03:02Z ERROR gagal koneksi ke database: connection refused
2026-01-15T08:03:05Z ERROR retry koneksi database gagal (percobaan 1)
2026-01-15T08:03:08Z ERROR retry koneksi database gagal (percobaan 2)
2026-01-15T08:03:11Z WARN antrean request menumpuk setelah error: 47 itemEmpat baris lolos: tiga ERROR dan satu WARN — baris ke-7 lolos karena isi pesannya memuat kata “error” meski levelnya WARN, bukti bahwa -i menyaring isi baris, bukan levelnya. Untuk sekadar menghitung, grep -c bekerja tanpa mencetak barisnya:
grep -c 'ERROR' app.log
grep -ci 'error' app.logOutput yang Dihasilkan:
3
4Angka pertama menghitung ERROR persis (huruf besar semua), angka kedua menghitung versi case-insensitive yang juga menangkap baris WARN tadi. Selisih satu di antara keduanya adalah pengingat bahwa pilihan flag menentukan hasil saringan.
Keluhan pengguna biasanya datang dengan jam: “sekitar jam 8 tadi web lambat”. Korelasi timestamp berarti memotong log hanya ke jendela waktu itu — pekerjaan yang pas untuk awk, karena timestamp ISO 8601 terurut secara leksikografis sehingga bisa dibandingkan sebagai teks:
awk '$1 >= "2026-01-15T08:03" && $1 < "2026-01-15T08:04"' app.logOutput yang Dihasilkan:
2026-01-15T08:03:02Z ERROR gagal koneksi ke database: connection refused
2026-01-15T08:03:05Z ERROR retry koneksi database gagal (percobaan 1)
2026-01-15T08:03:08Z ERROR retry koneksi database gagal (percobaan 2)
2026-01-15T08:03:11Z WARN antrean request menumpuk setelah error: 47 item
2026-01-15T08:03:40Z INFO koneksi database pulihMari kita bedah baris demi baris dari saringan ini:
$1:awkmemisah tiap baris berdasarkan spasi, jadi$1adalah kolom pertama — timestamp lengkap2026-01-15T08:03:02Z.$1 >= "2026-01-15T08:03": karena formatnya seragam, perbandingan teks>=setara dengan perbandingan waktu — semua baris pada menit 08:03 ke atas lolos.&& $1 < "2026-01-15T08:04": batas atas eksklusif memotong tepat sebelum menit 08:04, menghasilkan jendela satu menit penuh.- Tanpa aksi
{...}: pola tanpa blok aksi membuatawkmencetak seluruh baris yang cocok — bentuk ringkas dari{print $0}.
Hasilnya lima baris yang bercerita runtut: koneksi ditolak pukul 08:03:02, dua retry gagal, antrean menumpuk, lalu database pulih pukul 08:03:40. Kronologi inilah yang tidak diberikan metrik — dan untuk melihat sisa log setelah perbaikan, tail -n 3 menampilkan tiga baris terakhir:
tail -n 3 app.logOutput yang Dihasilkan:
2026-01-15T08:03:40Z INFO koneksi database pulih
2026-01-15T08:04:02Z INFO GET /api/pesanan 200 (15 ms)
2026-01-15T08:05:00Z INFO backup harian selesaiMengikuti Log yang Tumbuh #
Saat insiden masih berlangsung, kita tidak menyaring file yang sudah selesai bertumbuh — kita mengikutinya. Perintah tail -f /var/log/syslog mencetak sepuluh baris terakhir lalu terus mengalirkan baris baru saat file bertambah; hentikan dengan Ctrl-C. Pasangannya di jurnal adalah journalctl -f, dan journalctl -u nginx -f menggabungkan keduanya: batasan unit plus mode mengikuti.
Satu kelemahan tail -f muncul saat logrotate bekerja: file diganti nama, tail -f tetap mencengkeram file lama yang sekarang arsip. Variannya tail -F mengikuti nama — begitu file baru muncul dengan nama yang sama, tail -F berpindah ke file baru itu; kedua flag ini didokumentasikan di tail(1)
. Perilaku rotasi ini dibahas tuntas di chapter Logs dan Log Rotation
.
Log memberi kita kronologi mengapa sistem melambat. Pertanyaan berikutnya bersifat pencegahan: bagaimana memastikan satu proses yang rusak tidak melahap seluruh sistem — topik resource limits di chapter berikutnya.