Sertifikat di chapter sebelumnya mengunci percakapan; log mencatat apa yang lewat di balik pintu itu. Dua berkas inilah sumber data paling murah di server kita: access log mencatat setiap permintaan yang dilayani — siapa, meminta apa, kapan, dan berhasil atau tidak — sementara error log menampung keluhan sang server sendiri. Membaca keduanya adalah keterampilan inti admin: diagnosa gangguan, ukur trafik, dan deteksi penyusup semuanya berawal dari sini. Paket nginx tidak terpasang di lingkungan latihan, jadi kita memakai fixture access.log berisi sepuluh baris trafik fiktif, lalu menganalisisnya dengan pipeline awk-sort-uniq yang persis sama dengan yang dipakai di server produksi.
Anatomi Access Log Format Combined #
Nginx bawaannya menulis access log dengan format combined — format warisan yang juga dipakai Apache sehingga alat analisisnya bisa dipertukarkan. Analisisnya tidak butuh server yang hidup — cukup berkasnya:
cat access.logOutput yang Dihasilkan:
192.0.2.10 - budi [15/Jan/2026:08:12:01 +0700] "GET / HTTP/1.1" 200 2048 "https://cari.example.com/" "Mozilla/5.0 (X11; Linux x86_64)"
192.0.2.24 - - [15/Jan/2026:08:15:44 +0700] "GET /produk.html HTTP/1.1" 200 1536 "-" "curl/8.14.1"
192.0.2.10 - - [15/Jan/2026:09:02:19 +0700] "GET /favicon.ico HTTP/1.1" 404 512 "-" "Mozilla/5.0 (X11; Linux x86_64)"
198.51.100.7 - siti [15/Jan/2026:09:14:37 +0700] "GET /kontak.html HTTP/1.1" 200 1024 "-" "Mozilla/5.0 (X11; Linux x86_64)"
192.0.2.24 - - [15/Jan/2026:09:45:02 +0700] "GET /css/utama.css HTTP/1.1" 404 312 "-" "Mozilla/5.0 (X11; Linux x86_64)"
192.0.2.10 - budi [15/Jan/2026:10:05:50 +0700] "POST /pesan HTTP/1.1" 500 768 "https://toko.example.com/produk.html" "Mozilla/5.0 (X11; Linux x86_64)"
203.0.113.5 - - [15/Jan/2026:10:22:11 +0700] "GET / HTTP/1.1" 200 2048 "-" "Wget/1.25.0"
192.0.2.24 - - [15/Jan/2026:10:48:39 +0700] "GET /produk-lama.html HTTP/1.1" 404 512 "-" "Mozilla/5.0 (X11; Linux x86_64)"
198.51.100.7 - - [15/Jan/2026:11:03:26 +0700] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64)"
192.0.2.10 - budi [15/Jan/2026:11:37:58 +0700] "GET /tentang.html HTTP/1.1" 200 896 "https://cari.example.com/" "Mozilla/5.0 (X11; Linux x86_64)"Mari kita bedah baris pertama, kolom demi kolom:
192.0.2.10— alamat IP klien; ini pengisi utama kolom “siapa”.-— hasil ident protokol ident lawas (RFC 1413); hampir selalu kosong.budi— nama user dari HTTP authentication;-berarti permintaan tanpa login.[15/Jan/2026:08:12:01 +0700]— waktu lokal server beserta offset zona waktunya."GET / HTTP/1.1"— baris permintaan: method, path, dan versi protokol.200— kode status balasan, bahasa bersama dari Chapter Web Server .2048— jumlah byte isi balasan yang terkirim ke klien."https://cari.example.com/"— referer, halaman asal tautan;-berarti diketik langsung."Mozilla/5.0 ..."— user-agent, pengenal program klien — dari browser sungguhan sampaicurldanWget.
Siapa Paling Rajin: Top IP dan Jam Sibuk #
Pertanyaan klasik pertama adalah dari mana trafik datang. Pipeline sort + uniq -c menghitung kemunculan tiap IP lalu mengurutkannya; awk tinggal memetik kolom yang ditanya:
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -3
awk '{print substr($4,14,2)}' access.log | sort | uniq -cOutput yang Dihasilkan:
4 192.0.2.10
3 192.0.2.24
2 198.51.100.7
2 08
3 09
3 10
2 11Mari kita bedah baris demi baris:
- Baris 1 (
awk '{print $1}'):awkmemecah tiap baris berdasarkan spasi;$1adalah IP klien — satu-satunya yang kita butuhkan (dasar-dasarawkdibedah di Chapter awk ). sort | uniq -c:sortmengelompokkan baris sama bersebelahan — syarat kerjauniq— laluuniq -cmenghitung tiap kelompok.sort -rn | head -3: diurutkan menurun menurut angka lalu dipotong tiga teratas. Di data kita,192.0.2.10menyumbang 4 dari 10 permintaan — sinyal untuk memeriksa apakah IP itu pengunjung setia atau bot yang perlu dibatasi.- Baris 4 (
substr($4,14,2)): kolom waktu seperti[15/Jan/2026:08:12:01dipotong mulai karakter ke-14 sepanjang 2 — persis posisi dua digit jamnya, lalu dihitung per jam. Hasilnya menunjukkan pukul 09 dan 10 sebagai jam tersibuk: beban server tidak merata sepanjang hari.
Sebaran Status dan Daftar 404 #
Pertanyaan klasik kedua: seberapa sering permintaan gagal, dan gagal di mana. Kode status tinggal di kolom $9, dan jalur yang diminta di $7:
awk '{print $9}' access.log | sort | uniq -c | sort -rn
awk '$9 == 404 {print $7}' access.logOutput yang Dihasilkan:
5 200
3 404
1 500
1 304
/favicon.ico
/css/utama.css
/produk-lama.htmlMari kita bedah baris demi baris:
- Baris 1: pola yang sama dengan penghitungan IP, kolomnya ditukar ke
$9— lima200sehat, tiga404, satu304, satu500. - Baris 2 (
awk '$9 == 404'):awkjuga menyaring — hanya baris yang statusnya tepat404yang dicetak kolom$7-nya (path-nya). Memilih berdasarkan kolom seperti ini lebih aman daripadagrep " 404 ", yang ikut menangkap angka 404 di kolom byte atau user-agent. - Hasilnya: daftar path yang hilang siap ditindak — tautan rusak diperbaiki, berkas dilupakan diunggah ulang, atau URL lama dipasangi pengalihan.
304bukan masalah (cache klien masih berlaku), sedangkan500padaPOST /pesanadalah satu-satunya kegagalan sisi server — baris itulah yang menuntun kita ke error log.
Error Log dan Tingkat Keparahannya #
Access log mencatat nasib permintaan; error log mencatat sebabnya, lengkap dengan tingkat keparahan dari debug hingga emerg. Directive error_log /var/log/nginx/error.log warn; berarti hanya kejadian level warn ke atas yang dicatat. Berikut contoh tampilan satu barisnya:
2026/01/15 10:05:50 [error] 1234#1234: *7 open() "/var/www/toko/favicon.ico" failed (2: No such file or directory), client: 192.0.2.10, server: toko.example.com, request: "GET /favicon.ico HTTP/1.1", host: "toko.example.com"Formatnya tetap konsisten: tanggal dan waktu, [error] sebagai tingkatnya, 1234#1234 yaitu PID worker dan thread yang melapor, lalu pesannya beserta konteks — client pelakunya, server dan host situs tempat kejadian, serta request yang memicunya. Nomor *7 adalah koneksi keberapa dalam worker itu. Tingkatan yang perlu kita tanggapi juga berbeda-beda: error (operasi gagal, seperti berkas tak ada) layak dicermati, crit dan alert (misalnya kehabisan worker atau disk) adalah keadaan darurat, sementara warn biasanya informatif.
Format Kustom dan Rotasi Log #
Kedua format bawaan itu bisa kita ringkas sendiri dengan directive log_format, lalu dipasangkan per situs lewat access_log:
log_format ringkas '$remote_addr [$time_local] "$request" $status';
access_log /var/log/nginx/toko.access.log ringkas;Variabel seperti $remote_addr dan $status adalah bahasa yang sama dengan yang dipakai server block di Chapter nginx
. Format lebih ramping berarti berkas lebih kecil dan pembacaan lebih cepat — pilihan yang masuk akal untuk trafik tinggi, dengan kompromi kehilangan detail referer dan user-agent.
Berkas log yang tumbuh tanpa batas akhirnya memenuhi disk, dan server yang kehabisan disk adalah server yang tumbang diam-diam. Karena itu rotasi adalah bagian tak terpisahkan dari pengelolaan log — memindahkan berkas lama, mengompresnya, lalu menghapus yang tertua. Di Debian, pekerjaan itu dijalankan logrotate lewat berkas /etc/logrotate.d/nginx dengan isi tipikal begini:
/var/log/nginx/*.log {
daily
rotate 14
compress
missingok
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 "$(cat /var/run/nginx.pid)"
endscript
}Artinya: rotasi harian, simpan 14 generasi, kompres yang lama, dan sinyal USR1 menyuruh nginx membuka berkas baru tanpa restart — pembahasan lengkap mekanisme logrotate ada di Chapter Log dan Log Rotation
.
Log menjawab “apa yang terjadi di server”; perawatan rutin memastikan hal buruk tidak menumpuk sampai terjadi. Kita tutup section dengan disiplin jangka panjang di Chapter Server Maintenance .
Referensi lanjut: dokumentasi modul log Nginx
untuk directive log_format dan access_log, serta panduan log Apache
untuk format sejawatnya.