Mengelola log aplikasi dengan level yang benar, memakai Debug Toolbar selama development, dan membangun workflow untuk troubleshoot error 404 dan 500 tanpa panik.

Di episode 14 aplikasi kalian mulai dilengkapi cache dan semakin "nyata". Semakin nyata, semakin banyak juga yang bisa rusak: 404 misterius, 500 tanpa penjelasan, atau bug yang hanya muncul di produksi. Di episode 15 ini kita mempersenjatai kalian dengan dua alat utama: logging untuk mencatat jejak, dan debugging untuk menemukan sumber masalah.
Mengapa ini penting? Karena pengalaman men-debug tanpa log seperti mencari jarum di tumpukan jerami dengan lampu mati. Log yang baik adalah single source of truth saat aplikasi bermasalah — dan ini salah satu keterampilan yang paling membedakan junior dan senior developer.
Konfigurasi di app/Config/Logger.php:
public $threshold = 5;
public $handlers = [
'CodeIgniter\Log\Handlers\FileHandler' => [
'handles' => ['critical', 'alert', 'emergency', 'debug', 'error', 'warning', 'notice', 'info'],
'fileExtension' => 'log',
'filePermissions' => 0644,
],
];$threshold menentukan level minimum yang ditulis:
| Level | Nilai | Kegunaan |
|---|---|---|
emergency | 1 | Sistem tidak berfungsi |
alert | 2 | Perlu tindakan segera |
critical | 3 | Kondisi kritis |
error | 4 | Error runtime, perlu diperbaiki |
warning | 5 | Sesuatu tidak beres tapi tidak fatal |
notice | 6 | Kejadian normal tapi penting |
info | 7 | Informasi umum |
debug | 8 | Detail debugging |
Log tersimpan di writable/logs/ dengan nama berformat tanggal (log-2026-08-16.log).
log_message('info', 'User {email} melakukan login', ['email' => $email]);
log_message('error', 'Gagal memproses pembayaran untuk order #{id}', ['id' => $orderId]);
log_message('debug', 'Query time: {ms} ms', ['ms' => round($elapsed * 1000, 2)]);CodeIgniter mendukung placeholder {key} yang diisi dari array data — ini struktur log yang rapi dan mudah dibaca. Outputnya:
INFO - 2026-08-16 09:15:03 --> User arman@devvnull.test melakukan login
ERROR - 2026-08-16 09:15:04 --> Gagal memproses pembayaran untuk order #12345Tip
Log info/debug untuk jejak audit, error/warning untuk masalah yang harus diwaspadai. Jangan log data sensitif (password, token, data kartu). Dan gunakan placeholder — bukan string concat — agar nilai bisa di-escape dengan benar.
Debug Toolbar adalah dashboard waktu nyata untuk development — menampilkan query database, lama render, request, dan session. Aktif otomatis saat CI_ENVIRONMENT = development:
CI_ENVIRONMENT = developmentToolbar menampilkan tab: Timers (waktu request), Queries (semua query + waktu eksekusi), Request (headers, input), Session, Route, dan Views. Ini alat paling cepat untuk melihat query mana yang lambat atau berapa kali query dijalankan berulang.
$start = microtime(true);
// ... proses berat
$elapsed = (microtime(true) - $start) * 1000;
log_message('debug', 'Proses berat butuh {ms} ms', ['ms' => round($elapsed, 2)]);Warning
Debug Toolbar tidak boleh aktif di produksi — ia menambahkan overhead dan membocorkan informasi internal (query, session, path). Ia hanya muncul saat CI_ENVIRONMENT = development. Pastikan produksi memakai production (detail di episode 16).
404 berarti route tidak ditemukan. Alur pengecekan:
php spark routesphp spark routes.posts/(:num) tidak cocok dengan posts/abc — gunakan (:any) atau ubah pattern.app.baseURL di .env — jika salah, URL yang dihasilkan framework ikut salah.Penyebab 404 paling umum di awal belajar: lupa route ((:segment) vs (:num)), typo nama controller, atau baseURL tidak berakhiran /.
500 = error server. Tidak ada output, tapi pasti ada jejak:
tail -f writable/logs/log-$(date +%F).logAlur pengecekan:
writable/logs/ — error tercatat di sana.app.displayErrors = true di .env (development) untuk melihat detail.Kebiasaan senior: error 500 selalu punya log. Jika log kosong, periksa level $threshold dan pastikan handler menulis file dengan benar.
Sebarkan log di titik penting — bukan untuk membanjiri, tapi untuk jejak:
public function attempt(): \CodeIgniter\HTTP\RedirectResponse
{
$email = $this->request->getPost('email');
log_message('info', 'Percobaan login: {email}', ['email' => $email]);
$user = (new UserModel())->where('email', $email)->first();
if ($user === null || ! password_verify($this->request->getPost('password'), $user['password'])) {
log_message('warning', 'Login gagal: {email}', ['email' => $email]);
return redirect()->back()->with('error', 'Email atau password salah');
}
log_message('info', 'Login sukses: {email}', ['email' => $email]);
session()->regenerate();
session()->set([
'logged_in' => true,
'user_id' => $user['id'],
'role' => $user['role'],
]);
return redirect()->to('/dashboard');
}Dengan log ini, percobaan login gagal berulang (indikasi brute force) bisa terdeteksi dari writable/logs/ — yang akan kita otomasikan dengan rate limiting di episode 19.
Logger.php; log tersimpan di writable/logs/.log_message(level, msg, data) dengan placeholder {key}.php spark routes, placeholder, baseURL, namespace.writable/logs/ (prod).Inti yang harus dibawa pulang:
Di episode 16 selanjutnya kita akan membahas environment & deployment config — membedakan .env dev vs produksi, mengatur display errors off, serta praktik deploy ke shared hosting dan VPS. Aplikasi kalian siap meninggalkan laptop!