Skip to main content

Laravel Package

cliqthemes/log-lens mounts the Log Lens dashboard and JSON API inside an existing Laravel app. It's a thin adapter over cliqthemes/log-lens-core; all parsing, storage, and API logic lives in the core engine. Package README: the adapter's README.

Requirements

PHP 8.2+ and Laravel 10, 11, 12, or 13.

Install

composer require cliqthemes/log-lens

php artisan vendor:publish --tag=log-lens-assets # to public/vendor/log-lens
php artisan vendor:publish --tag=log-lens-config # optional to config/log-lens.php

The service provider is auto-discovered and the UI assets ship pre-built, so no Node build is needed. Visit /log-lens - but read Authorization first, since access is open in local by default.

Authorization

Full guide: Access control (Laravel) covers every method with copy-paste examples (email allowlists, roles, permissions, gates, middleware, and the kill-switch).

Access is gated on every route - no API key in Laravel mode; the host app's auth is the source of truth. Default: open in local, denied elsewhere. Restrict with any one of:

// 1. Auth callback (AppServiceProvider::boot) - the usual choice
use LogLens\Laravel\LogLens;
LogLens::auth(fn ($request) => $request->user() !== null); // require login
LogLens::auth(fn ($request) => $request->user()?->hasRole('admin') ?? false);
LogLens::auth(fn ($request) => $request->user()?->can('view-logs') ?? false);

// 2. A Laravel Gate (used when no callback is set)
Gate::define('viewLogLens', fn ($user) => $user?->can('view-logs') ?? false);

// 3. Middleware - add 'auth' to config('log-lens.middleware') to redirect guests to login

The local default allows an unauthenticated browser tab. Register a callback (option 1) to require login even in local. See Security.

This gate is all-or-nothing: can this request reach Log Lens at all. A separate, optional layer — log-lens.identity — controls what someone can do once inside (owner/editor/viewer, per application) and who a status change or tag edit is attributed to; see Roles & assignment. Without it, everyone the gate admits gets log-lens.default-role, which is owner out of the box.

Configuration

config/log-lens.php:

KeyDefaultPurpose
enabledenv('LOG_LENS_ENABLED', true)false unregisters the routes entirely (kill-switch).
route_prefixlog-lensURI prefix for the dashboard + API.
middleware['web']Route middleware for the dashboard + API (the gate is always appended).
receiver-middleware[]Middleware for the two self-authenticating receivers ({prefix}/ingest, {prefix}/linear-webhook), which are mounted outside middleware and the gate.
rootstorage_path('log-lens')Where the SQLite DB and logs//processed//sources/ live.
identitynullMaps the host user onto a Log Lens role, per application. See Roles & assignment.
default-roleenv('LOG_LENS_DEFAULT_ROLE', 'owner')Role for an authenticated host user when identity is unset. owner means the access gate is the access control — lower it to editor/viewer if the gate admits a broad audience.
assignable-usersnullWho an issue in the current application can be assigned to. See Roles & assignment.
core(defaults)Engine settings passed to cliqthemes/log-lens-core (severities, limits, retention, database driver, ...). core.auth.token is empty in Laravel mode.

Artisan

php artisan log-lens:import storage/logs --app=default
php artisan log-lens:sync --app=default # all connectors
php artisan log-lens:sync --app=default --connector=2

Schedule log-lens:sync in the console kernel for continuous connector ingestion.

CSRF and custom headers

Routes run through the web middleware group, which enforces CSRF. This is handled automatically: the dashboard reads Laravel's XSRF-TOKEN cookie and sends it back as the X-XSRF-TOKEN header on every request, so writes (status changes, tags, process logs, delete, connectors) work out of the box. Session auth is carried by the cookie as usual.

If you mount Log Lens behind a custom auth guard that needs an extra header (e.g. a bearer token), set request_headers in config/log-lens.php — an array of header => value, or a callable given the request. Log Lens injects them so the SPA sends them with every API call:

'request_headers' => ['Authorization' => 'Bearer '.config('services.logs.token')],
// or dynamic:
'request_headers' => fn ($request) => ['Authorization' => 'Bearer '.$request->user()?->apiToken],

How it works

The provider registers one route at the prefix. Requests without an api parameter return the SPA shell (assets served from public/vendor/log-lens, built with base /vendor/log-lens/); requests with one are translated into a LogLensRequest and passed to the core Kernel, whose LogLensResponse becomes a Laravel JSON response. See Architecture.