Log yang tidak pernah dibaca siapa-siapa hanyalah kuburan teks — kegagalan sistem terbesar bukan exception-nya, melainkan exception yang dibiarkan tidak diketahui selama tiga hari sampai pelanggan menelepon. Monitoring membalik arah informasi: alih-alih kita mengecek log, log dan health check yang datang kepada kita. Pada chapter penutup section ini kita susun lapisan pemantauan yang realistis untuk aplikasi Laravel: endpoint /up bawaan, pemeriksaan log terjadwal dengan exit code, kebersihan rotasi log, hingga pola alerting dan kapan layanan eksternal seperti Sentry layak diundang.
Endpoint Health /up #
Sejak Laravel 11, aplikasi baru otomatis punya health check di /up — terdaftar di bootstrap/app.php lewat health: '/up'. Endpoint ini menjawab 200 saat aplikasi hidup dan 503 saat database atau dependency kritis tidak terjangkau, sehingga layanan uptime (uptime monitor, load balancer, Kubernetes probe) cukup memanggil satu URL. Kita uji dengan development server dan curl:
php artisan serve --host=127.0.0.1 --port=8017curl -s -o /dev/null -w 'HTTP %{http_code} dalam %{time_total}s\n' http://127.0.0.1:8017/up
curl -s http://127.0.0.1:8017/up | grep -oE '<h2[^>]*>[^<]*</h2>'Output yang Dihasilkan:
HTTP 200 dalam 0.083362s
<h2 class="text-xl font-semibold text-gray-900">Application up</h2>Responsenya halaman kecil bertuliskan “Application up” dan “HTTP request received.” — kontennya untuk manusia, kode statusnya untuk mesin. Yang membuatnya istimewa: /up dikecualikan dari mode maintenance, terbukti saat kita mengaktifkan php artisan down dan membandingkan dua URL:
curl -s -o /dev/null -w 'GET /up: HTTP %{http_code}\n' http://127.0.0.1:8017/up
curl -s -o /dev/null -w 'GET /: HTTP %{http_code}\n' http://127.0.0.1:8017/Output yang Dihasilkan:
GET /up: HTTP 200
GET /: HTTP 503Seluruh aplikasi menolak pengguna dengan 503, tetapi health check tetap 200 — karena pemantau justru perlu tahu bahwa server hidup walau sedang maintenance. Ini menjelaskan daftar except pada penanda storage/framework/down dari chapter Custom Error Pages
.
Pemeriksaan Log Terjadwal #
Health check tahu aplikasi hidup, tetapi tidak tahu aplikasi sehat — error bisa menumpuk diam-diam di log sementara /up tetap 200. Lapisan kedua kita adalah command kecil yang menghitung baris ERROR pada log harian:
namespace App\Console\Commands;
use Illuminate\Console\Command;
class CheckErrorLogs extends Command
{
protected $signature = 'logs:check-errors {--hari=1 : Jumlah hari log yang diperiksa}';
protected $description = 'Hitung baris ERROR pada log harian terbaru';
public function handle(): int
{
$hari = max(1, (int) $this->option('hari'));
$jumlahError = 0;
$fileDiperiksa = [];
for ($i = 0; $i < $hari; $i++) {
$tanggal = now()->subDays($i)->format('Y-m-d');
$path = storage_path("logs/laravel-{$tanggal}.log");
if (! is_file($path)) {
continue;
}
$fileDiperiksa[] = "laravel-{$tanggal}.log";
$jumlahError += (int) preg_match_all('/\] \w+\.ERROR:/', file_get_contents($path));
}
$daftar = count($fileDiperiksa) > 0 ? implode(', ', $fileDiperiksa) : '(tidak ada file log)';
$this->line("File diperiksa : {$daftar}");
$this->line("Baris ERROR : {$jumlahError}");
return $jumlahError > 0 ? self::FAILURE : self::SUCCESS;
}
}Pada log harian berisi empat baris uji (dua di antaranya ERROR), command ini dijalankan nyata:
php artisan logs:check-errors --hari=1Output yang Dihasilkan:
File diperiksa : laravel-2026-10-13.log
Baris ERROR : 2Exit code-nya 1 (FAILURE) karena ditemukan error — bukan kecelakaan, melainkan desain: command yang gagal saat ada masalah bisa dipakai scheduler, cron, maupun pipeline CI sebagai sinyal. Kita daftarkan ke jadwal di routes/console.php:
use Illuminate\Support\Facades\Schedule;
Schedule::command('logs:check-errors --hari=1')->dailyAt('06:00');php artisan schedule:listOutput yang Dihasilkan:
0 6 * * * php artisan logs:check-errors --hari=1 Next Due: 10 hours from nowSetiap pagi pukul 06:00, scheduler menjalankan pemeriksaan tanpa campur tangan manusia. Dengan satu server cron php artisan schedule:run di sistem, seluruh jadwal ini hidup sendiri — detail penjadwalan dibahas di dokumentasi Scheduling
.
Rotasi dan Kebersihan Log #
Monitoring hanya nyaman jika log terawat. Dua kebiasaan yang harus menempel: pertama, channel daily dengan LOG_DAILY_DAYS yang realistis (default 14 hari) sehingga file lama dihapus otomatis dan disk tidak menipis perlahan; kedua, angka error yang wajar per hari — baseline — supaya command di atas bisa ditingkatkan menjadi ambang (misalnya gagal hanya jika melewati 50 error). Lonjakan dari 5 ke 300 baris adalah sinyal insiden; angka absolut tanpa pembanding bukan apa-apa.
Pola Alerting dan Layanan Eksternal #
Command terjadwal tahu ada error; alerting memberi tahu orangnya. Callback reportable() dari chapter Exception Reporting
adalah tempat kodenya: di dalam callback, panggil Log::channel('slack') atau Notification class untuk mengirim pesan saat exception kritis muncul — cukup satu blok if agar tim mendapat pesan dalam hitungan detik, bukan besok pagi. Untuk kebutuhan yang lebih serius, layanan seperti Sentry menawarkan pengelompokan error, deduplikasi, peta release, dan notification berjenjang; integrasinya berjalan lewat mekanisme reportable yang sama. Terakhir, uptime check dari luar (ping /up setiap menit dari service eksternal) melindungi dari kegagalan yang tidak sempat menulis log: server mati total.
Dengan ini rangkaian error handling dan logging kita utuh: exception ditangkap dan dirender dengan sopan, dilaporkan dengan konteks, log tersusun di channel yang sesuai, dan pemantauan berdiri di pintu depan. Filosofi akhirnya sederhana — gagal itu pasti, yang bisa kita pilih adalah gagal secara terhormat: terlihat, tercatat, dan cepat diketahui.