dick/logmanager
A Laravel package for managing application log files without SSH: browse, search, filter, download, and clear logs from your app or admin panel. Simple configuration and a clean API make everyday log inspection and troubleshooting quick.
dick/logmanager is a small, single-purpose package: it drops a web UI into your Laravel app that lists the files in storage/logs, lets you preview a file in the browser, download it, and delete it. There is no log parsing, no search index, no tailing — it is a file browser for logs. Treat it as an internal ops convenience, not a log platform.
Minimal steps:
composer require dick/logmanager
On Laravel 5.5+ the service provider is auto-discovered. On older versions add it manually:
// config/app.php
'providers' => [
// ...
Dick\LogManager\LogManagerServiceProvider::class,
],
Publish the config so you can control the route and the middleware protecting it:
php artisan vendor:publish --provider="Dick\LogManager\LogManagerServiceProvider"
The config typically exposes three things: the route prefix, the middleware stack applied to the routes, and the directory being browsed (usually storage_path('logs')). Set the middleware before you visit the route for the first time — out of the box these routes are often unauthenticated.
Where to look first, in this order:
config/logmanager.php (or whatever the publish tag produces) — route, middleware, path.src/ — the controller is usually a few dozen lines; read it fully before deploying. You need to know exactly what it will delete and what path it resolves.php artisan route:list | grep -i log — confirms the actual URI and route names, which are easy to guess wrong.First real use case: point a browser at the route on staging, confirm you can see laravel.log, preview it, download it to attach to a bug ticket, then delete it. Do this before you ever enable it on production.
Lock it down at the route level. This is the pattern that matters. Never rely on "nobody knows the URL."
// config/logmanager.php
return [
'route' => 'admin/logs',
'middleware' => ['web', 'auth', 'can:viewLogs'],
'path' => storage_path('logs'),
];
// app/Providers/AuthServiceProvider.php
Gate::define('viewLogs', function ($user) {
return $user->hasRole('super-admin');
});
Scope it to non-production environments if the app is internet-facing:
'middleware' => array_filter([
'web',
'auth',
app()->environment('production') ? 'can:viewLogs' : null,
]),
Wire it into the admin panel you already have. If you run Backpack, Nova, Filament or a hand-rolled admin, don't invent a second navigation. Add a plain link to the log route:
// Backpack sidebar_content.blade.php
<li><a href="{{ url(config('logmanager.route')) }}"><i class="la la-file-text"></i> Logs</a></li>
Daily channel fits this package best. With LOG_CHANNEL=daily you get one file per day (laravel-2024-05-01.log), which makes the file list meaningful and makes deletion safe — you delete a closed file rather than the one currently being written.
Use it as the "attach the log to the ticket" tool. The download button is the highest-value button in the package. A workflow that works well: reproduce the bug, download the log, attach it to the ticket, then delete the file so the next reproduction starts clean.
Keep destructive actions manual. Don't script against this package's routes. For automated retention use Laravel's own commands (log:clear) or a find storage/logs -mtime +14 -delete cron instead — the UI is for humans doing one-off triage.
Override rather than fork. Publish the views to change branding/layout, and if you need a behaviour change (e.g. a "clear file" button, or masking secrets before preview), subclass the controller and re-register the routes in your own RouteServiceProvider with the package's route names. That survives a composer update better than editing vendor/.
../). If it constructs a path from user input without basename(), patch it.www-data) needs read access to storage/logs. Files created by a CLI php artisan run under a different user can be readable by you locally and invisible to the web UI. chmod -R g+r storage/logs plus a shared group is the usual fix.: > storage/logs/laravel.log or move it) and preview a slice. If you need to actually read large logs, use less, grep, or a proper log viewer.php artisan route:cache, confirm the log route still resolves and still carries your middleware. Packages that register routes in a boot() guarded by a closure can behave differently once cached.php artisan config:clear after editing the published config; a stale bootstrap/cache/config.php is the classic "my middleware change did nothing" cause.composer.json, vendor-audit it once, and know your exit path. The drop-in modern replacements are opcodesio/log-viewer (search, tail, level filters, actively maintained) and rap2hpoutre/laravel-log-viewer (single-file, minimal, same spirit as this one). Migrating is a route change, not a refactor — which is a good reason to keep everything referencing config('logmanager.route') rather than hardcoding URLs.APP_KEY, tokens, and passwords before rendering — genuinely worth doing if non-admins will ever see the page).How can I help you explore Laravel packages today?