Aplikasi di production tidak pernah berhenti menghasilkan jejak: setiap request, job, dan exception menulis baris ke log — dan baris-baris itu tumbuh tanpa henti sampai disk penuh atau justru terlalu jarang dibaca sampai insiden lolos tanpa diketahui. Bab operasional ini melengkapi pemahaman kita di Monitoring Application Errors dengan sudut pandang production: rotasi agar log tidak memakan disk, alert yang datang sendiri ketika error muncul, health check yang dipantau dari luar, dan sedikit disiplin tentang metrik apa yang benar-benar layak diawasi.
Rotasi Log: Dua Lapis Pertahanan #
Lapis pertama ada di dalam aplikasi: channel daily. Dengan mengarahkan .env ke driver ini, Laravel membuat berkas baru setiap hari dengan nama bertanggal dan menghapus arsip lama otomatis sesuai LOG_DAILY_DAYS:
LOG_CHANNEL=daily
LOG_DAILY_DAYS=14Setelah aplikasi menulis beberapa baris log, isi storage/logs/ di sandbox kita:
ls storage/logs/Output yang Dihasilkan:
laravel-2026-10-13.logSatu berkas per hari, retensi 14 hari — disk steady state dan pencarian insiden cukup tahu tanggalnya. Perilaku channel ini dibanding saudaranya sudah dibedah di Log Channels .
Lapis kedua berada di level sistem operasi: logrotate. Layanan ini penting justru karena menangani log di luar kendali Laravel — error log PHP-FPM, access log Nginx, output worker dari supervisor. Contoh tampilan konfigurasi /etc/logrotate.d/tokobudi:
/var/www/tokobudi/storage/logs/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
su www-data www-data
}Enam arahan di atas berarti: periksa harian, simpan 14 generasi, jangan marah bila berkas tidak ada, kompres generasi lama, dan lakukan semuanya sebagai user www-data agar kepemilikan berkas konsisten dengan aplikasi.
Alert Error yang Datang Sendiri #
Log menunggu dibaca; alert menghampiri kita. Mekanismenya sudah disiapkan framework lewat callback reportable() — setiap exception yang dilaporkan bisa kita umpan ke notification. Kita bangun versi produksinya nyata. Pertama, notification class ringkas:
namespace App\Notifications;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Throwable;
class ErrorKritis extends Notification
{
public function __construct(public Throwable $exception)
{
}
public function via(object $notifiable): array
{
return ['mail'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('[Tokobudi] Error produksi: '.class_basename($this->exception))
->line('"'.$this->exception->getMessage().'"')
->line('Lokasi: '.$this->exception->getFile().':'.$this->exception->getLine());
}
}Kedua, pemasangannya di bootstrap/app.php lewat withExceptions():
use App\Notifications\ErrorKritis;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Notification;
use Throwable;
->withExceptions(function (Exceptions $exceptions): void {
$exceptions->reportable(function (Throwable $e): void {
Notification::route('mail', '[email protected]')
->notify(new ErrorKritis($e));
});
})Untuk mengujinya, cukup satu route yang melempar exception dan satu curl:
curl -s -o /dev/null -w 'GET /boom: HTTP %{http_code}\n' http://127.0.0.1:8018/boomOutput yang Dihasilkan:
GET /boom: HTTP 500Email alertnya sendiri mendarat di log karena sandbox memakai MAIL_MAILER=log — di production dengan SMTP nyata, pesan yang sama tiba di inbox tim dalam hitungan detik:
[2026-10-13 22:52:19] local.DEBUG: From: Laravel <[email protected]>
To: [email protected]
Subject: [Tokobudi] Error produksi: RuntimeException
"Sinkronisasi stok ke gudang gagal: koneksi timeout."
Lokasi: /home/z/my-project/work/sandboxes/w16-a/routes/web.php:14Channel mail di sini hanya salah satu pilihan. Channel slack bawaan mengirim webhook ke workspace tim, sedangkan Telegram cukup dibungkus satu Http client POST ke bot webhook — pokoknya satu tujuan: exception kritis tidak menunggu seseorang kebetulan membuka log.
Health Check dan Uptime dari Luar #
Endpoint /up yang sudah kita kenal adalah kontrak paling sederhana untuk dunia luar: 200 berarti hidup, 503 berarti tidak. Pemeriksaannya sebatas satu curl:
curl -s -o /dev/null -w 'GET /up: HTTP %{http_code} dalam %{time_total}s\n' http://127.0.0.1:8018/upOutput yang Dihasilkan:
GET /up: HTTP 200 dalam 0.087083sYang tidak bisa dilakukan curl dari server sendiri adalah mendeteksi server mati total — karena curl-nya ikut mati. Untuk itu ada layanan uptime eksternal semacam UptimeRobot atau Better Stack: daftarkan https://tokobudi.example.com/up, dan layanan tersebut memanggil URL itu dari mesin mereka setiap beberapa menit, lalu mengirim alert ketika status berubah. Karena /up dikecualikan dari maintenance mode (terbukti di chapter sebelumnya bahwa down membuat / menjawab 503 sementara /up tetap 200), pemantau tidak ikut panik saat deploy terjadwal.
Metrik yang Layak Diawasi #
Alert per error bagus untuk insiden tunggal, tetapi kesehatan aplikasi dibaca dari tren. Empat angka berikut layak ditempel di dasbor mana pun:
| Metrik | Mengapa penting | Sumber data |
|---|---|---|
| Laju error per jam | Lonjakan dari baseline menandai rilis bermasalah | Hitung baris ERROR di log harian |
| Waktu respons p95 | Rata-rata menyembunyikan request termuat | Access log Nginx atau APM |
| Ruang disk | Log dan backup adalah pemakan diam-diam | df -h via cron |
| Kedalaman antrean | Job menumpuk = worker kewalahan | Tabel jobs di database |
Angka absolutnya kurang berarti tanpa pembanding — lima error per jam mungkin normal untuk Toko Budi dan bencana untuk aplikasi lain. Kenali baseline dulu, baru pasang ambang di atasnya.
Untuk volume yang lebih besar, php artisan pail (paket bawaan sandbox ini) mengikuti log secara live seperti tail -f, sementara agregasi terpusat semacam Papertrail mengumpulkan log banyak server ke satu tempat lewat channel stderr atau syslog — keduanya opsi lanjutan dari pola channel yang sudah dibahas di Log Channels
, dan dokumentasi resminya ada di dokumentasi Logging
.
Log kini terpelihara dan kesalahan mengejar kita, bukan sebaliknya. Seluruh pengetahuan ini tinggal dirangkai menjadi satu urutan rilis yang bisa diulang tanpa mikir — tugas Deployment Workflow .