backpack/logmanager
Backpack LogManager is a Laravel admin panel add-on for browsing, searching, and managing application log files directly from Backpack. It gives developers a convenient UI to preview logs, filter entries, and quickly diagnose issues without SSH.
Install the addon alongside a working Backpack admin:
composer require backpack/logmanager
php artisan vendor:publish --provider="Backpack\LogManager\LogManagerServiceProvider"
Add the menu entry so it appears in the sidebar (Backpack 6 uses addMenuContent):
php artisan backpack:add-menu-content "<x-backpack::menu-item title='Logs' icon='la-terminal' :link=\"backpack_url('log')\" />"
The default route is /admin/log, protected by Backpack's admin middleware. That is your first usable endpoint — log in as an admin user, hit it, and you should see a listing of every *.log in storage/logs.
Where to look first:
config/backpack/logmanager.php — this is the only config surface. Check it for the storage path, the route prefix, and any enable/disable flags before doing anything custom.vendor/backpack/logmanager/src/app/Http/Controllers/LogController.php — read this before you try to extend. It is small and shows exactly which methods (index, preview, download, delete) map to routes.vendor/backpack/logmanager/resources/views/ — the Blade views are publishable and are where 90% of real customization happens.First use case: give non-engineers (support, ops) read access to the current laravel.log through the admin panel without SSH. That is the primary value — it is a thin, well-scoped wrapper around glob('storage/logs/*.log') plus readfile/unlink.
Version pinning per Backpack major. This package's API changed across backpacks v4/v5/v6. If you're on Backpack 6, use the latest (v6+); for older projects you must use ^4.0 or ^5.0. Add it to composer.json with the major constraint rather than letting require float — the menu integration syntax (add_menu_content vs addMenuContent, Blade components vs plain views) differs.
Gating by permission, not just admin. Out of the box every Backpack admin user sees every log. In a real app, wrap the menu item and route in the Backpack permission manager:
// in a service provider or route override
Route::middleware(['web', 'admin', 'can:view-logs'])->group(function () {
Route::get('admin/log', [\Backpack\LogManager\app\Http\Controllers\LogController::class, 'index']);
// ...
});
Or simpler: conditionally render the menu item with @can('view-logs') inside the menu template.
Environment separation of log viewers. Do not expose this in production to all admins. A common pattern is to only register the route/service provider when ! app()->isProduction() or when config('backpack.logmanager.enabled') is true, and flip that flag per environment via .env. Logs can contain tokens, PII, and SQL with passwords — treat the viewer as a sensitive surface.
Log rotation workflow. Pair this addon with daily channel logging (LOG_CHANNEL=daily), which produces laravel-YYYY-MM-DD.log. The index view then becomes a natural date browser. Add a scheduled cleanup so storage/logs does not accumulate forever:
// app/Console/Kernel.php
$schedule->command('log:clear')->daily();
// or just: $schedule->call(fn () => collect(glob(storage_path('logs/*.log')))->each->delete())->weekly();
Custom views for large files. The built-in preview loads the full file. For anything over a few MB, publish the views and swap in a tail-style reader:
php artisan vendor:publish --tag=backpack-logmanager-views
Then in the published preview.blade.php use a streaming tail:
$lines = array_slice(file($path), -500);
Download as escape hatch. The download route is the cleanest way to hand a log to an external tool (Splunk, grep) without giving shell access. Link to it from your own admin dashboards if you have custom ops tooling.
Multi-tenant / per-user logs. If your app writes per-user logs (e.g., storage/logs/user-{id}.log), the default glob will show every file to every admin. Fork the index action or publish a custom controller to filter the glob result by auth()->user()->can(...). This is the single most common reason people outgrow the package.
storage/logs is hardcoded-ish. The listing uses storage_path('logs'), not a fully configurable path in most versions. If your logs live elsewhere (S3, /var/log), you must fork the controller — publishing config does not move the directory in older releases.config('backpack.logmanager.allow_delete') (and the view's delete button) if you want read-only for some roles. There is no trash.laravel.log will OOM the admin request. If you ever see a 500 on the preview route, that is why — rotate logs and/or publish views with fseek/SplFileObject.NOASSERTION. Treat this as "read the LICENSE file in the repo before shipping commercially" — Backpack's addons are typically MIT, but NOASSERTION in composer metadata means the tool could not classify it. Verify.composer show backpack/logmanager against composer show backpack/crud.admin middleware group exists. If you renamed Backpack's admin prefix from admin to something else (config('backpack.base.route_prefix')), the published routes will not resolve — you need to republish the provider or override routes.www-data (or your PHP-FPM user) must be able to read storage/logs. If the delete button 500s, it is almost always a write-permission issue on the directory, not a package bug.{!! !!}, you reintroduce XSS via user-controlled log content. Always {{ }} when rendering log lines.require in a package you publish. It is an app-level addon, not a library dependency — add it to require-dev or the app's require only, never to a package's require.php artisan route:list | grep log should show admin/log, admin/log/{file}/preview, etc. If they are missing, the service provider was not auto-discovered (composer dump-autoload after install fixes this).How can I help you explore Laravel packages today?