Echo dan var_dump menghilang bersama proses yang menampilkannya — besok pagi, saat bug muncul lagi di produksi, tidak ada saksi yang tersisa. Logging menyelesaikannya: pesan ditulis ke file (atau tujuan lain) yang bertahan melewati umur request, siap dibaca saat investigasi. Laravel memakai Monolog di bawah layar dan menyembunyikannya di balik facade Log yang sederhana, dengan seluruh perilaku yang dikendalikan satu file: config/logging.php. Pada chapter ini kita tulis log pertama kita, bedah file konfigurasi itu bagian demi bagian, lalu buktikan tiga perilaku penting — penyaringan level, penanganan deprecation, dan emergency logger — dengan output asli dari sandbox.
Menulis Log Pertama #
Facade Log menyediakan satu method per level: debug, info, warning, error, critical, alert, emergency. Setiap method menerima pesan plus array konteks bebas:
use Illuminate\Support\Facades\Log;
Log::info('Budi masuk ke halaman dashboard.');
Log::warning('Sisa stok buku tinggal 2.', ['produk' => 'Buku "Belajar Laravel"', 'gudang' => 'Bandung']);
Log::error('Gagal menyambung ke layanan kurir.', ['layanan' => 'kurir-api', 'percobaan' => 1]);Output yang Dihasilkan (storage/logs/laravel.log):
[2026-10-13 19:53:13] local.INFO: Budi masuk ke halaman dashboard.
[2026-10-13 19:53:13] local.WARNING: Sisa stok buku tinggal 2. {"produk":"Buku \"Belajar Laravel\"","gudang":"Bandung"}
[2026-10-13 19:53:13] local.ERROR: Gagal menyambung ke layanan kurir. {"layanan":"kurir-api","percobaan":1} Anatomi satu baris log: timestamp, nama channel (local — diambil dari APP_ENV), level, pesan, lalu konteks sebagai JSON. Saat request berjalan lewat PHPUnit, prefix-nya menjadi testing. karena environment berubah.
Anatomi config/logging.php #
File konfigurasi logging terdiri dari empat bagian utama:
'default' => env('LOG_CHANNEL', 'stack'),
'deprecations' => [
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
'trace' => env('LOG_DEPRECATIONS_TRACE', false),
],
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => explode(',', (string) env('LOG_STACK', 'single')),
'ignore_exceptions' => false,
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'replace_placeholders' => true,
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'max_files' => env('LOG_DAILY_DAYS', 14),
'replace_placeholders' => true,
],
// ... channel lainnya
],Baris pertama yang perlu diperhatikan adalah 'default'. Nilai .env bawaan adalah LOG_CHANNEL=stack, dan channel stack sendiri diisi dari LOG_STACK=single. Artinya: secara default, log mengalir ke satu channel single — file storage/logs/laravel.log. Kata “stack” di sini bukan keharusan; kita bebas mengubah kedua variabel itu untuk mengarah ke daily, syslog, atau gabungan keduanya. Perbedaan antar channel dibahas tuntas di chapter Log Channels
.
Level: Menyaring yang Masuk Log #
Setiap channel punya ambang level. Pesan dengan level di bawah ambang tidak pernah ditulis — fitur yang berguna agar log produksi tidak penuh debug. Kita buktikan dengan channel ad-hoc bermata tirai warning (dibuat lewat Log::build, dibahas di chapter berikutnya):
$ketat = Log::build([
'driver' => 'single',
'path' => storage_path('logs/ketat.log'),
'level' => 'warning',
]);
$ketat->info('Baris INFO di channel level warning.');
$ketat->warning('Baris WARNING lolos filter.');Output yang Dihasilkan (storage/logs/ketat.log):
[2026-10-13 19:53:21] local.WARNING: Baris WARNING lolos filter. Baris INFO lenyap sebelum menyentuh disk. Urutan level dari rendah ke tinggi: debug < info < notice < warning < error < critical < alert < emergency. Nilai LOG_LEVEL=debug di .env berarti semua level lolos — cocok untuk pengembangan, terlalu ramai untuk produksi.
Channel Deprecations #
PHP dan package lama sering memancarkan peringatan deprecation (“fitur ini akan dihapus di versi berikutnya”). Secara bawaan LOG_DEPRECATIONS_CHANNEL=null — peringatan itu dibuang ke channel null yang tidak menulis apa pun. Saat kita bersiap upgrade versi, arahkan saja ke channel sungguhan:
config()->set('logging.deprecations.channel', 'single');
trigger_error('Fungsi ambilKutipanLama() sudah usang.', E_USER_DEPRECATED);
Log::info('Setelah deprecation di atas, baris info berikutnya.');Output yang Dihasilkan:
[2026-10-13 19:53:21] local.WARNING: Fungsi ambilKutipanLama() sudah usang. in /tmp/tlog2.php on line 27
[2026-10-13 19:53:21] local.INFO: Setelah deprecation di atas, baris info berikutnya. Deprecation kini tercatat sebagai WARNING lengkap dengan lokasi pemanggilnya — persis yang dibutuhkan untuk menginventarisasi kode usang sebelum upgrade.
Emergency Logger #
Apa yang terjadi jika konfigurasi log kita rusak — misalnya LOG_CHANNEL menunjuk channel yang tidak didefinisikan? Laravel menolak mati sunyi: LogManager menangkap kegagalan pembuatan channel, lalu membuat emergency logger yang menulis langsung ke storage/logs/laravel.log:
config()->set('logging.default', 'kanal-tak-dikenal');
Log::info('Baris ini seharusnya tidak pernah sampai ke channel manapun.');Output yang Dihasilkan:
[2026-10-13 19:53:28] laravel.EMERGENCY: Unable to create configured logger. Using emergency logger. {"exception":"[object] (InvalidArgumentException(code: 0): Log [kanal-tak-dikenal] is not defined. at ..."}
[2026-10-13 19:53:28] laravel.INFO: Baris ini seharusnya tidak pernah sampai ke channel manapun. Dua hal patut dicermati: pesan EMERGENCY menjelaskan penyebab kegagalan (channel tak dikenal), dan pesan asli tetap terselamatkan. Perhatikan juga nama channel berubah menjadi laravel — tanda khas emergency logger. Detail lengkap opsi konfigurasi tersedia di dokumentasi Logging
. Dengan peta konfigurasi di tangan, kita siap berkeliling ke koleksi channel yang tersedia — itu topik chapter Log Channels
.