Logging & Monitoring

Logging & Monitoring

Bitnesia • Aug 30, 2026 81 •EN

Studi kasus Bab 18 berakhir dengan audit-server.sh yang sudah berjalan otomatis lewat cron maupun systemd timer, tanpa perlu dipicu manual lagi. Tapi ada satu pertanyaan yang belum terjawab tuntas di sana: begitu job terjadwal itu berjalan sendiri di tengah malam tanpa ada Sysadmin yang menonton, bagaimana cara memastikan ia benar-benar berhasil, atau tahu persis di mana ia gagal kalau ternyata bermasalah? Jawabannya ada di dua kebiasaan yang saling melengkapi: logging, mencatat jejak apa yang terjadi dan kapan, serta monitoring, memeriksa kondisi sistem secara proaktif dan membandingkannya dengan ambang batas yang wajar. Bab ini membahas cara membaca log bawaan sistem lewat journalctl dan /var/log, cara membuat log sendiri yang layak dipakai di script produksi, menyusun script monitoring dasar untuk disk, service, dan koneksi, lalu ditutup studi kasus menggabungkan semuanya jadi satu dashboard status server yang tampil langsung di terminal. Pola log dan exit status yang dibangun di bab ini jadi fondasi langsung untuk Bab 20, tempat kondisi "bermasalah" yang terdeteksi di sini diubah jadi notifikasi otomatis lewat email, Telegram, atau Slack.

19.1 Membaca dan Memproses Log Server

Linux modern punya dua sumber log utama yang saling melengkapi: systemd journal, basis data log terstruktur yang dikelola systemd-journald dan diakses lewat journalctl, serta log berbasis file teks klasik di /var/log yang sudah ada jauh sebelum systemd populer. Sysadmin yang paham cara menggali informasi dari keduanya jauh lebih cepat menemukan akar masalah dibanding yang cuma mengandalkan salah satunya.

19.1.1 journalctl: Query Log Systemd Journal

Bab 18.1.4 dan 18.3.2 sempat memakai journalctl -u dan -f sekadar untuk memverifikasi job terjadwal. Sub-bab ini membahas opsi journalctl yang lebih luas untuk kebutuhan investigasi log sehari-hari.

journalctl -p err -b
journalctl -k
journalctl --since "1 hour ago" --until "now"
journalctl -u nginx.service -n 50 -r

Opsi -p (priority) menyaring log berdasarkan tingkat keparahan mengikuti delapan level standar syslog: emerg, alert, crit, err, warning, notice, info, dan debug, dari yang paling parah ke paling ringan. Menuliskan satu level saja, seperti -p err di atas, menampilkan pesan pada level itu atau yang lebih parah, jadi -p err otomatis ikut menampilkan crit dan alert juga. Opsi -b (boot) membatasi hasil ke sesi boot saat ini saja, atau -b -1 untuk boot sebelumnya, berguna saat menyelidiki kenapa server sempat restart sendiri semalam. -k (kernel) menyaring khusus pesan dari kernel, setara dmesg tapi dengan seluruh kemampuan filter journalctl. --since dan --until menerima format waktu yang cukup fleksibel sesuai dokumentasi man 7 systemd.time, termasuk frasa relatif seperti "1 hour ago", bukan cuma --since today yang sudah dipakai di Bab 18. -n 50 membatasi jumlah baris seperti tail, dan -r (reverse) menampilkan yang terbaru lebih dulu.

Versi systemd yang cukup baru (237 ke atas, sudah lama jadi standar di distro modern) juga mendukung -g untuk mencari pola teks langsung tanpa perlu menyalurkannya lewat grep secara terpisah.

journalctl -u nginx.service -g "connection refused"

Untuk output yang perlu diproses lebih lanjut oleh tool lain, -o json-pretty mencetak tiap entri log sebagai objek JSON lengkap dengan seluruh field metadatanya (PID, unit, prioritas, dan seterusnya), jauh lebih mudah diparsing terprogram dibanding format teks bebas bawaan.

journalctl -u nginx.service -o json-pretty -n 1

Satu jebakan yang sering ditemui pengguna baru: journal tidak selalu tersimpan permanen. Sesuai man 5 journald.conf, opsi Storage= yang default-nya auto berarti log tersimpan persisten di /var/log/journal kalau direktori itu memang ada, atau sebaliknya cuma tersimpan sementara di /run/log/journal dan hilang begitu server reboot. Sebagian distro (misalnya Ubuntu Server dan Fedora) sudah menyediakan direktori itu sejak instalasi awal sehingga persisten secara default, sementara distro atau image minimal lain kadang tidak. Cek dulu isi /etc/systemd/journald.conf server yang dikelola alih-alih berasumsi salah satunya; kalau memang perlu diaktifkan manual, cukup buat direktorinya dan biarkan systemd-tmpfiles mengatur permission-nya.

sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal

Journal yang persisten juga butuh dijaga ukurannya supaya tidak menghabiskan disk; journalctl --disk-usage mencetak total ruang yang dipakai saat ini, dan --vacuum-time=2weeks atau --vacuum-size=500M memangkas entri lama sesuai batas waktu atau ukuran yang ditentukan.

journalctl --disk-usage
sudo journalctl --vacuum-time=2weeks

Kalau journalctl cuma menampilkan sebagian log disertai pesan hint seputar izin akses grup, itu tandanya user yang login belum tergabung di grup systemd-journal. Jalankan lewat sudo untuk sementara, atau tambahkan user itu ke grup tersebut (sudo usermod -aG systemd-journal nama_user, konsisten dengan pola usermod -aG dari Bab 17.3.3) supaya bisa membaca log tanpa perlu hak root penuh setiap kali.

19.1.2 /var/log dan Log Berbasis File Klasik

Sebelum systemd-journald ada, dan masih berdampingan dengannya sampai sekarang di banyak server, layanan syslog seperti rsyslog atau syslog-ng menulis log ke file teks biasa di /var/log. Nama file dan isinya cukup bervariasi antar distro, jadi jangan berasumsi satu nama berlaku di mana saja.

FileDistroIsi
/var/log/syslogDebian/Ubuntu (butuh rsyslog terpasang)Log sistem umum, campuran berbagai service
/var/log/messagesRHEL/CentOS/FedoraSetara syslog, log sistem umum
/var/log/auth.logDebian/UbuntuLog otentikasi: login, sudo, percobaan akses SSH
/var/log/secureRHEL/CentOS/FedoraSetara auth.log

Banyak distro modern, terutama image minimal atau container, sekarang tidak memasang rsyslog sama sekali dan cukup mengandalkan journalctl saja, sehingga file-file di atas mungkin tidak ada. Cek dulu keberadaannya lewat systemctl status rsyslog atau sekadar ls /var/log sebelum berasumsi salah satu file itu pasti ada. Selain log sistem umum, kebanyakan aplikasi server juga menulis log sendiri di subdirektori khusus, misalnya /var/log/nginx/ untuk web server Nginx atau /var/log/mysql/ untuk MySQL/MariaDB, mengikuti konvensi masing-masing package.

Membaca file-file ini memakai tool yang sudah dibahas di Bab 2.3: tail -f untuk mengikuti log baru secara real-time, atau less +F yang punya kemampuan serupa sekaligus tetap bisa di-scroll bebas begitu mode follow-nya dihentikan lewat Ctrl+C.

tail -f /var/log/nginx/error.log
less +F /var/log/auth.log

Log lama yang sudah di-rotate (topik yang dibahas lebih dalam di 19.2.4) biasanya dikompresi jadi .gz. zgrep dan zcat, varian grep dan cat yang bisa membaca isi file gzip langsung tanpa perlu diekstrak manual lebih dulu, jadi kebiasaan yang jauh lebih praktis dibanding gunzip satu-satu.

zgrep "Failed password" /var/log/auth.log.2.gz

19.1.3 Filter dan Ekstraksi Log dengan grep dan awk

grep (Bab 9.2) dan awk (Bab 11) adalah dua tool utama menyaring log jadi informasi yang benar-benar relevan, baik untuk output journalctl maupun file teks biasa di /var/log.

journalctl -u nginx.service --since today | grep -i "error"

Pola menyalurkan (pipe) journalctl ke grep -i ini sangat umum dipakai untuk mempersempit ribuan baris log jadi sekadar baris yang mengandung kata kunci tertentu, tidak peduli besar-kecil huruf. Untuk log bergaya syslog klasik, formatnya cukup konsisten: bulan tanggal jam:menit:detik hostname proses[pid]: pesan, sehingga awk bisa mengekstrak kolom tertentu saja tanpa perlu membaca seluruh baris.

awk '{print $1, $2, $3, $5}' /var/log/auth.log | tail -n 20

Perintah di atas mencetak ulang cuma bulan, tanggal, jam, dan nama proses (kolom kelima, karena kolom keempat biasanya hostname) dari 20 baris terakhir, memangkas isi pesan yang panjang supaya lebih gampang dipindai sekilas. Kombinasi awk dengan pola pencarian, bukan cuma nomor kolom, juga berguna untuk menyaring baris berdasarkan isi sambil tetap tidak peduli besar-kecil huruf, sesuatu yang tidak bisa dilakukan grep -i sekaligus dengan pemrosesan kolom.

awk 'tolower($0) ~ /error|failed/' /var/log/syslog

19.2 Membuat Log Sendiri untuk Script

Script yang dijadwalkan otomatis lewat cron atau systemd timer dari Bab 18 gagal diam-diam adalah salah satu situasi paling menjengkelkan buat Sysadmin, ditemukan berhari-hari kemudian saat efeknya sudah terlanjur menumpuk. Kebiasaan menulis log sendiri di dalam script, bukan cuma mengandalkan echo polos ke layar, adalah investasi kecil yang sangat menghemat waktu debugging di kemudian hari.

19.2.1 Level Log dan Format Pesan

Log yang berguna butuh dua hal minimal: level yang menandai seberapa penting pesan itu, dan timestamp yang menandai kapan persis kejadiannya. Empat level yang lazim dipakai di script Bash, dari yang paling ringan sampai paling serius, adalah DEBUG (detail teknis, cuma relevan saat menelusuri bug), INFO (penanda progres normal, misalnya "backup dimulai"), WARN (sesuatu yang tidak wajar tapi belum menghentikan proses), dan ERROR (operasi gagal total). Format satu baris yang konsisten memudahkan pencarian nanti lewat grep.

[2026-08-31 02:00:01] [INFO] Backup dimulai
[2026-08-31 02:00:45] [WARN] Ukuran backup lebih besar dari biasanya
[2026-08-31 02:01:02] [ERROR] Gagal menyalin ke server tujuan

19.2.2 Fungsi Logging Reusable

Menulis pola printf lengkap dengan timestamp berulang-ulang di banyak tempat gampang membuat format-nya jadi tidak konsisten seiring waktu. Membungkusnya jadi satu fungsi, mengikuti kebiasaan Bab 8, jauh lebih rapi dan gampang diubah formatnya di satu tempat saja kalau suatu saat diperlukan.

LOG_FILE="/var/log/backup-harian/backup.log"

log() {
    local level="$1"
    shift
    local pesan="$*"
    local waktu
    waktu=$(date '+%Y-%m-%d %H:%M:%S')
    printf '[%s] [%s] %s\n' "$waktu" "$level" "$pesan" >> "$LOG_FILE"
    if [[ "$level" == "ERROR" ]]; then
        printf '[%s] [%s] %s\n' "$waktu" "$level" "$pesan" >&2
    fi
}

log INFO "Backup dimulai"
log ERROR "Gagal menyalin ke server tujuan"

shift di baris kedua fungsi (Bab 12.1) membuang argumen pertama (level), menyisakan seluruh argumen berikutnya untuk digabung jadi satu pesan lewat "$*", sehingga pemanggilan log INFO "Backup dimulai" tidak perlu membungkus pesannya kalau memang sudah satu string, tapi tetap fleksibel menerima beberapa kata terpisah. Pesan level ERROR sengaja dikirim dua kali, sekali ke file log lewat >> (Bab 5.3) dan sekali lagi ke stderr lewat >&2, supaya kegagalan tetap terlihat langsung di terminal kalau script dijalankan manual, sekaligus tetap tercatat permanen kalau dijalankan otomatis lewat cron. Pastikan direktori LOG_FILE sudah dibuat dan permission-nya sesuai user yang menjalankan script (mkdir -p dan chown dari Bab 17.3.2), karena fungsi ini akan gagal diam-diam kalau direktorinya belum ada atau usernya tidak punya izin tulis.

19.2.3 Mengirim Log ke Syslog/Journal dengan logger

Alternatif dari menyimpan log ke file sendiri adalah mengirimnya langsung ke syslog/journal lewat logger, utilitas bagian dari util-linux yang tersedia default di hampir semua distro Linux. Keuntungannya, log itu otomatis ikut tersimpan di infrastruktur logging terpusat yang sudah ada, tanpa perlu mengurus file dan rotasinya sendiri.

logger -t backup-harian "Backup dimulai"
logger -p local0.warning -t backup-harian "Ukuran backup lebih besar dari biasanya"

Opsi -t (tag) menandai sumber pesan supaya gampang disaring belakangan, dan -p menentukan facility.priority mengikuti skema level syslog yang sama seperti dibahas di 19.1.1. Pesan yang dikirim lewat logger langsung muncul di journalctl, disaring lewat tag yang sama persis dengan yang dipakai di opsi -t.

journalctl -t backup-harian

Pendekatan mana yang dipilih, file log sendiri atau logger ke syslog, tergantung kebutuhan: file log sendiri lebih cocok untuk laporan panjang dan terstruktur (seperti output audit-server.sh dari Bab 17.4), sedangkan logger lebih cocok untuk pesan singkat bergaya event yang memang ingin muncul berdampingan dengan log service lain di journal yang sama.

19.2.4 Rotasi Log dengan logrotate

File log yang dibuat sendiri lewat fungsi log() di 19.2.2 akan terus bertambah besar tanpa batas kalau dibiarkan begitu saja, berpotensi menghabiskan disk persis seperti kasus yang dibahas di Bab 17.1.3. logrotate, tool standar yang sudah terpasang default di hampir semua distro Linux, menangani ini secara otomatis lewat file konfigurasi di /etc/logrotate.d/.

sudo nano /etc/logrotate.d/backup-harian
/var/log/backup-harian/backup.log {
    weekly
    rotate 4
    compress
    missingok
    notifempty
    create 0640 root root
}

weekly menentukan frekuensi rotasi, rotate 4 menyimpan maksimal empat file lama sebelum yang tertua dihapus, compress mengompresi file yang sudah dirotasi jadi .gz (bisa langsung dibaca lewat zgrep dari 19.1.2), missingok mencegah logrotate berhenti dengan error kalau file log-nya kebetulan belum ada, notifempty melewati rotasi kalau file-nya masih kosong, dan create 0640 root root membuat file log baru dengan permission dan kepemilikan tertentu setelah rotasi, memakai notasi permission yang sama seperti Bab 17.3.2. Perlu dicatat, logrotate sendiri bukan daemon yang berjalan terus, melainkan dipicu berkala lewat cron.daily atau systemd timer bernama logrotate.timer yang sudah terpasang bersama paketnya, konsisten dengan mekanisme penjadwalan yang sudah dibahas tuntas di Bab 18.

Uji konfigurasi baru tanpa menunggu jadwalnya lewat opsi -d (debug, hanya simulasi tanpa mengubah apa pun) atau -f (force, benar-benar menjalankan rotasi saat itu juga).

sudo logrotate -d /etc/logrotate.d/backup-harian
sudo logrotate -f /etc/logrotate.d/backup-harian

19.3 Script Monitoring Sederhana: Cek Disk, Cek Service, dan Cek Koneksi

Kalau logging soal mencatat apa yang sudah terjadi, monitoring soal memeriksa kondisi terkini secara aktif dan membandingkannya dengan batas yang dianggap wajar. Sub-bab ini membangun tiga pemeriksaan dasar secara terpisah dulu, sebelum digabung jadi satu dashboard di studi kasus 19.4.

19.3.1 Cek Disk dengan Ambang Batas

Pola ini mirip cek_disk di studi kasus Bab 17.4.2, tapi disederhanakan untuk satu filesystem spesifik saja.

PERSEN=$(df -h / --output=pcent | tail -n 1 | tr -d ' %')
if (( PERSEN >= 80 )); then
    echo "PERINGATAN: filesystem root sudah $PERSEN%"
fi

tr -d ' %' (Bab 9.4) membuang spasi dan tanda persen dari output df --output=pcent, menyisakan angka murni yang aman dibandingkan lewat (( )). Pendekatan ini cukup untuk satu filesystem; untuk memeriksa semua filesystem sekaligus, pola while read lengkap dari Bab 17.4.2 tetap jadi pilihan yang lebih tepat.

19.3.2 Cek Status Service dengan systemctl

systemctl menyediakan tiga subperintah query khusus yang dirancang untuk dipakai langsung di dalam kondisi script, tanpa perlu mem-parsing output systemctl status yang formatnya panjang: is-active, is-enabled, dan is-failed. Ketiganya mencetak status singkat ke stdout sekaligus mengembalikan exit status 0 kalau kondisinya terpenuhi, cocok langsung dipakai di if.

if systemctl is-active --quiet nginx; then
    echo "nginx aktif"
else
    echo "PERINGATAN: nginx tidak aktif"
fi

Opsi --quiet menekan output teksnya karena di sini yang dibutuhkan cuma exit status-nya, bukan tampilan status di layar. Perintah query ini tidak butuh hak akses root sama sekali, beda dengan start/stop/restart dari Bab 18.3.2 yang mengubah kondisi service. Perlu diingat, nama unit service kerap berbeda antar distro persis seperti kasus cron/crond di Bab 18.1.4; misalnya service SSH bernama ssh di Debian/Ubuntu tapi sshd di RHEL/Fedora/Arch, jadi selalu sesuaikan nama unit-nya dengan distro server yang dikelola.

19.3.3 Cek Koneksi Dasar dengan ping

Untuk kebutuhan dashboard sederhana di 19.4, cukup dipastikan dulu apakah sebuah host masih bisa dijangkau lewat jaringan, sebelum menyelidiki lebih jauh apakah service tertentu di host itu yang bermasalah.

if ping -c 1 -W 2 8.8.8.8 &> /dev/null; then
    echo "Konektivitas OK"
else
    echo "PERINGATAN: tidak ada respons dari host"
fi

-c 1 membatasi cuma satu paket ping yang dikirim, dan -W 2 membatasi waktu tunggu maksimal 2 detik sebelum dianggap gagal; output-nya dibuang seluruhnya ke /dev/null lewat &> (Bab 5.3) karena yang dibutuhkan cuma exit status-nya. Satu catatan penting soal portabilitas: makna satuan -W ini berbeda antar implementasi, di ping bawaan Linux (paket iputils) satuannya detik seperti contoh di atas, sedangkan di ping bawaan macOS/BSD satuannya milidetik. Perbedaan detail semacam ini, beserta tool jaringan lain seperti curl untuk mengecek endpoint HTTP/API dan ss untuk melihat koneksi aktif, dibahas jauh lebih dalam di Bab 22; sub-bab ini sengaja cukup memakai ping paling dasar sebagai satu komponen kecil dashboard status server.

19.4 Studi Kasus: Dashboard Status Server Sederhana di Terminal

Studi kasus penutup ini menggabungkan fungsi log() dari 19.2.2 dengan tiga pemeriksaan dari 19.3 jadi satu script dashboard-server.sh yang menampilkan kondisi server secara ringkas dan menyegarkan tampilannya berkala, mirip htop tapi khusus untuk ringkasan status, bukan daftar proses.

19.4.1 Rancangan Dashboard

Script menerima empat opsi lewat getopts mengikuti pola baku Bab 12.2.3: -i untuk interval refresh dalam detik (default 5), -s untuk daftar nama service yang dicek, dipisah spasi dalam satu string, -H untuk host tujuan pengecekan koneksi, dan -o untuk lokasi file log. Setiap anomali yang terdeteksi (disk penuh, service mati, host tidak merespons) dicatat lewat fungsi log() dengan level WARN, sehingga riwayatnya tetap tersimpan meski tampilan di layar sudah tertimpa refresh berikutnya. Script berhenti bersih saat ditekan Ctrl+C lewat trap sederhana; mekanisme trap yang lebih lengkap untuk cleanup dibahas tuntas di Bab 25.2.

19.4.2 Implementasi Script

#!/bin/bash

INTERVAL=5
LOG_FILE="dashboard-server.log"
SERVICES=("ssh" "cron")
HOST="8.8.8.8"

usage() {
    printf 'Pemakaian: %s [-i interval] [-s "svc1 svc2"] [-H host] [-o file_log]\n' "$0" >&2
    exit 1
}

while getopts ":i:s:H:o:h" opt; do
    case "$opt" in
        i) INTERVAL="$OPTARG" ;;
        s) read -ra SERVICES <<< "$OPTARG" ;;
        H) HOST="$OPTARG" ;;
        o) LOG_FILE="$OPTARG" ;;
        h) usage ;;
        :) echo "Error: opsi -$OPTARG butuh sebuah argumen" >&2; exit 1 ;;
        \?) echo "Error: opsi tidak dikenal: -$OPTARG" >&2; exit 1 ;;
    esac
done

log() {
    local level="$1"
    shift
    local waktu
    waktu=$(date '+%Y-%m-%d %H:%M:%S')
    printf '[%s] [%s] %s\n' "$waktu" "$level" "$*" >> "$LOG_FILE"
}

cek_disk() {
    local persen
    persen=$(df -h / --output=pcent | tail -n 1 | tr -d ' %')
    printf '=== Disk (/) ===\n'
    if (( persen >= 80 )); then
        printf '[PERINGATAN] root filesystem %s%%\n' "$persen"
        log WARN "Disk root sudah $persen%"
    else
        printf '[OK]         root filesystem %s%%\n' "$persen"
    fi
}

cek_service() {
    printf '\n=== Status Service ===\n'
    local svc
    for svc in "${SERVICES[@]}"; do
        if systemctl is-active --quiet "$svc"; then
            printf '[OK]         %s aktif\n' "$svc"
        else
            printf '[PERINGATAN] %s tidak aktif\n' "$svc"
            log WARN "Service $svc tidak aktif"
        fi
    done
}

cek_koneksi() {
    printf '\n=== Koneksi ke %s ===\n' "$HOST"
    if ping -c 1 -W 2 "$HOST" &> /dev/null; then
        printf '[OK]         host %s merespons\n' "$HOST"
    else
        printf '[PERINGATAN] host %s tidak merespons\n' "$HOST"
        log WARN "Host $HOST tidak merespons ping"
    fi
}

trap 'printf "\nDashboard dihentikan.\n"; exit 0' INT

while true; do
    clear
    printf 'Dashboard Status Server - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')"
    printf -- '----------------------------------------\n'
    cek_disk
    cek_service
    cek_koneksi
    printf '\nRefresh tiap %s detik. Tekan Ctrl+C untuk keluar.\n' "$INTERVAL"
    sleep "$INTERVAL"
done

Opsi -s memakai read -ra SERVICES <<< "$OPTARG", memanfaatkan here-string (<<<), bentuk redirection yang menyalurkan sebuah string langsung sebagai input tanpa perlu file atau pipe terpisah. Dikombinasikan dengan -a pada read, string yang dipisah spasi itu langsung terpecah jadi elemen-elemen array SERVICES (Bab 4.1), menggantikan nilai default ("ssh" "cron") kalau opsi -s diberikan. Nilai default itu sendiri sengaja memakai ssh, bukan sshd, mengikuti penamaan di Debian/Ubuntu seperti disinggung di 19.3.2; sesuaikan lewat -s "sshd cron" kalau server yang dikelola berbasis RHEL/Fedora. Loop utama di bagian akhir memakai while true dari Bab 7.2 dipadukan clear dan sleep, pola standar untuk tampilan yang menyegarkan diri sendiri secara berkala di terminal.

19.4.3 Verifikasi dan Penjadwalan

Beri izin eksekusi lalu jalankan dengan opsi default lebih dulu untuk memastikan tampilannya sudah sesuai harapan.

chmod +x dashboard-server.sh
./dashboard-server.sh

Uji juga skenario "bermasalah" secara sengaja, misalnya menghentikan sementara salah satu service yang dicek (ingat mengaktifkannya lagi setelah selesai menguji) atau menunjuk ke host yang sengaja tidak eksis, supaya baris [PERINGATAN] benar-benar teruji muncul, bukan cuma diasumsikan bekerja.

./dashboard-server.sh -H 203.0.113.1 -i 3
tail -f dashboard-server.log

203.0.113.1 di atas sengaja diambil dari blok 192.0.2.0/24, 198.51.100.0/24, dan 203.0.113.0/24 yang dicadangkan khusus untuk dokumentasi menurut RFC 5737, aman dipakai sebagai contoh tanpa risiko tidak sengaja mengganggu host produksi milik pihak lain. Perhatikan tail -f dashboard-server.log di baris kedua, dijalankan di sesi terminal terpisah, untuk memastikan setiap [PERINGATAN] yang tampil di dashboard benar-benar ikut tercatat lewat fungsi log().

Dashboard interaktif seperti ini cocok dipakai saat Sysadmin sedang aktif memantau server, misalnya selama deployment berlangsung (Bab 21), tapi jelas tidak realistis dibiarkan menyala di satu sesi terminal selamanya untuk pemantauan sehari-hari. Bagian pengecekan (cek_disk, cek_service, cek_koneksi) dan pola log-nya bisa dipisah dari bagian tampilan dan dijadwalkan lewat cron atau systemd timer persis seperti audit-server.sh di Bab 18.4, sehingga hasilnya tersimpan berkala tanpa perlu terminal yang terus terbuka. Bab 20 melanjutkan tepat dari titik ini: entri log WARN yang selama ini cuma tersimpan diam di file, diubah jadi notifikasi yang aktif dikirim ke email, Telegram, atau Slack begitu kondisi bermasalah terdeteksi.