Log viewer
daravel_log_viewer menyajikan sebuah halaman, dari aplikasi Anda, yang
membaca file log-nya: entri terbaru lebih dulu, bisa difilter berdasarkan
level atau teks, stack trace tinggal satu klik, dan entri baru muncul saat
ditulis. File dibaca dari ujungnya, sehingga entri terakhir dari file
500 MB kembali dalam waktu kurang dari satu milidetik, dengan memori yang
sama seperti file kecil.
dartisan pub:add log-viewer
pub:add menambahkan dependency, pemanggilan .withLogViewer() di bawah
(tanpa middleware: tambahkan sebelum halaman ini dipakai di luar local),
dan pengaturan LOG_VIEWER_* ke .env.example. Dengan
dart pub add daravel_log_viewer, daftarkan sendiri:
// bootstrap/app.dart
import 'package:daravel_log_viewer/daravel_log_viewer.dart';
Application createApp() => Application.configure(basePath: basePath)
.withLogViewer(middleware: ['auth', 'can:view-logs'])
// ...
.create();
Halamannya ada di /log-viewer (LOG_VIEWER_PATH, atau
withLogViewer(path: '/admin/logs')). Halaman ini membaca folder tempat channel
log harian menulis (LOG_PATH, storage/logs), jadi tulis log ke file:
LOG_STACK=console,daily
Siapa yang boleh melihat#
Log mengungkap banyak hal tentang sebuah aplikasi. Di luar
APP_ENV=local dan testing, viewer menjawab 403 sampai withLogViewer
diberi middleware, misalnya auth dan sebuah gate:
// bootstrap/policies.dart
gate.define('view-logs', (user, args) => user is User && user.isAdmin);
LOG_VIEWER_ENABLED=false mematikannya (404) di mana pun.
Yang ditampilkan#
- File. Semua file
.logdi folder tersebut, terbaru lebih dulu, beserta ukurannya; filedaravel-YYYY-MM-DD.logdari Daravel danlaravel.logdari aplikasi Laravel yang berbagi server sama-sama terbaca. - Entri. Waktu, level, pesan; satu klik menampilkan context (sebagai JSON), error, dan stack trace, dengan frame aplikasi ditonjolkan dibanding frame framework dan SDK.
- Level dan pencarian. Chip level (
emergencysampaidebug) dan pencarian di seluruh isi entri: request id, user id, nama class exception. - Live. Entri baru muncul saat ditulis, lewat server-sent events, dengan filter yang sama.
- Entri lama. Halaman berikutnya mundur menelusuri file tanpa membacanya dari awal.
Daravel menulis satu objek JSON per baris (time, level, channel,
message, context, error, trace); Laravel menulis baris Monolog
([2026-10-28 08:00:00] production.ERROR: ...) diikuti stack trace.
Keduanya terbaca. Baris yang bukan kedua format itu ditampilkan apa
adanya.
Data rahasia#
Logger sudah mengganti nilai key LOG_REDACT saat entri ditulis. Viewer
juga menyembunyikan, sebelum entri keluar dari server, nilai key
LOG_VIEWER_MASK_KEYS (default password, secret, token,
authorization, cookie, api_key, app_key, credit_card, dicocokkan
sebagai bagian dari key, tanpa membedakan huruf besar-kecil): di context
pada kedalaman berapa pun, dan di teks seperti password=...,
"token": "...", atau Authorization: ....
Halaman ini tidak memuat apa pun dari host lain: script dan style-nya
inline, diizinkan oleh nonce baru di Content-Security-Policy yang tidak
mengizinkan apa pun selain itu, dan teks log selalu disisipkan sebagai
teks, tidak pernah sebagai HTML. Nama file harus file .log yang langsung
berada di folder tersebut: path, .., file tersembunyi, dan link yang
keluar dari folder dijawab 404.
Pengaturan#
| Variabel | Default | |
|---|---|---|
LOG_VIEWER_ENABLED |
true |
false menjawab 404 |
LOG_VIEWER_PATH |
/log-viewer |
URL halaman |
LOG_VIEWER_DIRECTORY |
LOG_PATH |
folder file log |
LOG_VIEWER_PER_PAGE |
50 |
entri per halaman, maksimal 500 |
LOG_VIEWER_ALLOW_DOWNLOAD |
true |
tombol Download |
LOG_VIEWER_ALLOW_DELETE |
false |
tombol Delete (request DELETE) |
LOG_VIEWER_MASK_KEYS |
lihat di atas | key yang nilainya disembunyikan |
LOG_VIEWER_MAX_SCAN_MB |
64 |
seberapa banyak isi file yang dibaca satu halaman terfilter sebelum menawarkan untuk lanjut |
API#
Halaman ini memakai endpoint JSON di bawah path-nya, yang juga bisa dipakai tool lain (di balik middleware yang sama):
GET /log-viewer/api/files |
daftar file, terbaru lebih dulu |
GET /log-viewer/api/entries?file=&levels=error,warning&search=&before= |
satu halaman entri, terbaru lebih dulu, dan next, nilai before untuk halaman yang lebih lama |
GET /log-viewer/api/tail?file=&levels=&search= |
event entry lewat server-sent events |
GET /log-viewer/api/download?file= |
file-nya |
DELETE /log-viewer/api/files?file= |
menghapus file (bila diizinkan) |
File besar#
bench/bin/log_viewer_bench.dart (build AOT, Windows 11, Dart 3.13.4):
| File | 50 entri terbaru | Pencarian yang tidak menemukan apa pun (membaca 64 MB) | Puncak memori |
|---|---|---|---|
| 100 MB | 0,8 ms | 1,2 s | 17 MB |
| 500 MB | 0,6 ms | 0,9 s | 17 MB |
Angka memori adalah puncak seluruh proses, termasuk runtime. Membaca satu halaman atau mengikuti file hanya menyimpan satu blok 64 KB dan satu entri setiap saat.