Looking to hire Laravel developers? Try LaraJobs

laravel-sluice maintained by sluice

Description
Sluice aggregates logs, exceptions, and events from across your Laravel application into a single controlled stream — filterable, searchable, and chronologically sane.
Last update
2026/04/07 00:35 (dev-main)
License
Downloads
0

Comments
comments powered by Disqus

What It Actually Does

Sluice reads logs from places you point it at and displays them on a single page, sorted by time. It does not replace your logging stack. It sits next to it and gives you one place to look when something goes wrong.

Out of the box, it can read from:

  • Local log fileslaravel.log, rotated daily logs, or any text file with timestamps. Supports Laravel's standard format, plain text, and a config-driven custom regex parser for arbitrary formats (nginx, syslog, etc.).
  • Database tables — Query any table in your database and map its columns to timeline events. Works with the package's own sluice_logs table or any existing table you already have.
  • AWS CloudWatch Logs — Pull events from any CloudWatch log group (Lambda, ECS, EC2). Requires aws/aws-sdk-php.
  • S3 log files — Download and parse log files from S3 buckets (CloudFront access logs, ALB logs, etc.). Requires aws/aws-sdk-php.
  • HTTP/REST APIs — Fetch JSON from any API endpoint and map the response into timeline events. Uses Laravel's built-in HTTP client.

It also includes a built-in logger that can write structured events to a database table, a log file, or both. This is optional — you can use Sluice purely as a reader if you already have logs elsewhere.

What it does NOT do

  • It does not automatically discover every log source in your application. You tell it where to look via the config file.
  • It does not natively integrate with Telescope, Horizon, Sentry, Flare, or Bugsnag. If those tools expose a REST API or write to a file/database, you can point Sluice at them using the HTTP or database source types — but there are no pre-built connectors.
  • It is not a replacement for dedicated error tracking services. It is a single-pane view of what happened and when.

Features

Feature Details
Multi-source aggregation Merge file + database + remote sources into one timeline
Config-driven sources Define sources in config/sluice.php — labels, icons, colors, parsing rules
Custom format parsing Config-defined regex patterns to parse any log format without writing code
Smart grouping Repeated identical entries within a time window collapse into x N badges
Level filtering Filter by debug / info / warning / error / critical / security
Text search Server-side search across all sources + client-side instant filter
Source toggles Show/hide individual sources with checkboxes
JSON export Download filtered timeline as JSON for external analysis
Built-in logger Optional: log to DB, file, or both via a clean facade API
Exception capture Optional: automatically capture exceptions from Laravel's reporting pipeline
Frontend error capture Dedicated table and logger for JavaScript errors
Batch logging Efficient bulk insert for high-throughput scenarios
Custom layouts Use the built-in standalone UI or embed into your app's Blade layout
JSON API Optional REST endpoints for headless/external dashboard integration
CLI commands 5 Artisan commands: view, filter, export, log, and cleanup from the terminal
Flexible auth 4 authorization strategies: Gate, callback, env variable, or open access
Laravel 10+ Works with Laravel 10, 11, and 12

Installation

1. Require the package

composer require sluice/laravel-sluice

The service provider auto-registers via Laravel's package discovery.

2. Publish the config

php artisan vendor:publish --tag=sluice-config

This creates config/sluice.php where you define your sources.

3. (Optional) Run the migration

Only needed if you want database-backed logging via the built-in logger:

php artisan vendor:publish --tag=sluice-migrations
php artisan migrate

This creates two tables:

  • sluice_logs — structured log entries
  • sluice_frontend_errors — frontend JavaScript error capture

4. (Optional) Publish views for customization

php artisan vendor:publish --tag=sluice-views

Views are copied to resources/views/vendor/sluice/.

5. Set up authorization

The dashboard supports 4 authorization strategies. Choose one:

Strategy 1: Laravel Gate (recommended)

// In AuthServiceProvider (Laravel 10) or AppServiceProvider (Laravel 11+)
use Illuminate\Support\Facades\Gate;

Gate::define('view-sluice', function ($user) {
    return $user->hasRole('developer');  // Your logic here
});

Strategy 2: Callback (no Gate needed)

// In config/sluice.php
'auth_gate' => null,
'auth_callback' => fn($user) => in_array($user->email, ['admin@example.com']),

Strategy 3: Environment variable (simple on/off)

// In config/sluice.php
'auth_gate' => null,
'auth_env' => 'SLUICE_ACCESS',
SLUICE_ACCESS=true

Strategy 4: Open to all authenticated users

// In config/sluice.php
'auth_gate' => null,
'auth_callback' => null,
'auth_env' => null,

6. Visit the dashboard

https://yourapp.com/sluice

Configuration

All configuration lives in config/sluice.php. Key sections:

Defining Log Sources

Sources are the heart of the package. Each source tells Sluice where to find logs and how to display them.

File Sources

'sources' => [
    'laravel' => [
        'type'    => 'file',
        'label'   => 'Laravel Log',
        'icon'    => 'bi-file-earmark-code',
        'badge'   => 'bg-danger',
        'enabled' => true,
        'paths'   => ['laravel.log'],
        'format'  => 'laravel',
    ],
],

File Formats:

Format Description
laravel Standard Laravel log format: [2026-04-06 12:00:00] production.ERROR: ...
plain Line-based, detects level from keywords (ERROR, WARNING, etc.)
custom Config-defined regex patterns for timestamp, level, and message extraction

Database Sources

'activity' => [
    'type'             => 'database',
    'label'            => 'Activity Logs',
    'icon'             => 'bi-database',
    'badge'            => 'bg-primary',
    'enabled'          => true,
    'table'            => 'activity_logs',
    'timestamp_column' => 'created_at',
    'mapping'          => [
        'level'   => 'log_level',
        'title'   => 'event_type',
        'message' => 'message',
        'context' => 'context',
        'user_id' => 'user_id',
    ],
    'filters' => [
        'search_columns' => ['event_type', 'message'],
        'level_column'   => 'log_level',
    ],
],

Remote Sources (CloudWatch, S3, HTTP)

See the commented examples in config/sluice.php for CloudWatch, S3, and HTTP source configurations.

Exception Capture

Sluice can optionally hook into Laravel's exception reporting pipeline. When enabled, any exception that Laravel reports is automatically written to the Sluice timeline with the exception class, message, file, line, and a truncated stack trace.

// In config/sluice.php
'capture_exceptions' => true,

Or via environment variable:

SLUICE_CAPTURE_EXCEPTIONS=true

This uses Laravel's MessageLogged event, so it captures anything that passes through report() or Log::error() with an exception in the context. Built-in dedup prevents the same exception from flooding the timeline.


Using the Built-in Logger

Via Facade

use Sluice\LaravelSluice\Facades\Sluice;

Sluice::info('user_login', 'User logged in successfully', ['ip' => '1.2.3.4'], $userId);
Sluice::warning('rate_limit', 'API rate limit approaching', ['current' => 95, 'max' => 100]);
Sluice::error('payment_failed', 'Stripe charge declined', ['charge_id' => 'ch_xxx'], $userId);
Sluice::critical('database_down', 'Primary database connection lost');
Sluice::security('brute_force', 'Multiple failed login attempts', ['attempts' => 15], $userId);

Via Dependency Injection

use Sluice\LaravelSluice\Logging\TimelineLogger;

class PaymentController extends Controller
{
    public function __construct(
        protected TimelineLogger $logger
    ) {}

    public function charge(Request $request)
    {
        $this->logger->info('payment_initiated', 'Processing payment', [
            'amount' => $request->amount,
        ], auth()->id());
    }
}

Frontend Error Logging

Sluice::frontendError(
    message: 'TypeError: Cannot read property "x" of undefined',
    type: 'javascript',
    stack: $stackTrace,
    source: 'https://app.example.com/js/app.js',
    line: 42,
    column: 15,
    url: 'https://app.example.com/dashboard',
    context: ['browser' => 'Chrome 120'],
    userId: auth()->id()
);

Batch Logging

Sluice::batch([
    ['event_type' => 'page_view', 'message' => '/dashboard', 'log_level' => 'info'],
    ['event_type' => 'page_view', 'message' => '/settings', 'log_level' => 'info'],
], $userId);

CLI Commands

All commands work without a web server.

php artisan sluice:show                          # View timeline in terminal
php artisan sluice:show --days=3 --level=error   # Filter by time and level
php artisan sluice:show --json | jq '.'          # Pipe JSON output

php artisan sluice:stats                         # Aggregate statistics
php artisan sluice:stats --json                  # Stats as JSON

php artisan sluice:export                        # Export to JSON file
php artisan sluice:export --days=14 --level=error --output=errors.json

php artisan sluice:log deploy_complete "Deployed v2.3.1 to production"
php artisan sluice:log disk_space_low "Disk at 92%" --level=warning

php artisan sluice:clear                         # Archive entries older than 90 days
php artisan sluice:clear --days=30 --delete      # Permanently delete

Schedule cleanup:

$schedule->command('sluice:clear --days=90 --force')->monthly();

JSON API

Optional REST endpoints, disabled by default.

// config/sluice.php
'api' => [
    'enabled'    => true,
    'prefix'     => 'api/sluice',
    'middleware' => ['api', 'auth:sanctum'],
],
Method Endpoint Description
GET /api/sluice Full timeline with stats
GET /api/sluice/stats Aggregate statistics only
GET /api/sluice/sources Source metadata
GET /api/sluice/export Downloadable JSON export

All endpoints accept: ?days=, ?limit=, ?level=, ?search=, ?sources=


Extending Sluice

Sluice is designed to be extended through configuration and, when needed, through new source driver classes. If the five built-in source types (file, database, cloudwatch, s3, http) don't cover your use case, you can write a custom source driver.

Writing a Custom Source Driver

A source driver is a class that fetches log events from some external system and returns them as a Laravel Collection of normalized event arrays. Look at the existing drivers in src/Sources/ for the pattern:

  1. Create a class in src/Sources/ (e.g., RedisSource.php).
  2. Implement a static isAvailable() method that returns false if required dependencies are missing.
  3. Implement a fetch() method that accepts a source key, start date, level filter, search filter, and limit, and returns a Collection of normalized event arrays.
  4. Add a new elseif branch in TimelineService::getTimeline() for your new type.
  5. Add a config block in config/sluice.php with 'type' => 'your_type'.

The normalized event array structure:

[
    'source'       => 'source_key',
    'level'        => 'error',                // debug|info|warning|error|critical|security
    'timestamp'    => Carbon::instance(),
    'icon'         => 'bi-file-text',
    'badge_class'  => 'bg-danger',
    'source_badge' => 'bg-primary',
    'title'        => 'Source: ERROR',
    'subtitle'     => 'First 200 chars...',
    'details'      => ['key' => 'value'],
    'user_id'      => 42,                     // nullable
    'group_count'  => 1,
    'group_key'    => 'md5_hash',
]

Contributing New Source Drivers

If you build a source driver that could be useful to others, please consider submitting it as a pull request. The things we would most like to see community drivers for:

  • Redis — Read from Redis streams or pub/sub channels
  • Telescope — Read from Telescope's database tables (for projects that use both)
  • Sentry/Bugsnag/Flare — Fetch recent issues via their REST APIs
  • Elasticsearch/OpenSearch — Query log indices
  • Kafka — Consume from Kafka topics
  • Docker/container logs — Read from Docker's JSON log files
  • Systemd journal — Read from journalctl output

To submit a driver:

  1. Fork the repository
  2. Add your source class to src/Sources/
  3. Add the corresponding type handling in TimelineService::getTimeline()
  4. Add a commented example config block in config/sluice.php
  5. Include a brief section in this README under "Remote Sources"
  6. Submit a PR with a description of what the driver connects to and any required dependencies

We will review and merge drivers that follow the existing patterns: graceful degradation when dependencies are missing, config-driven setup, and no hard requirements on external packages.


Architecture

sluice/laravel-sluice
+-- config/
|   +-- sluice.php                       -- All configuration
+-- database/migrations/
|   +-- create_sluice_tables.php         -- Optional DB tables
+-- resources/views/
|   +-- timeline.blade.php               -- Main page
|   +-- _sidebar.blade.php               -- Filter sidebar
|   +-- _timeline_content.blade.php      -- Timeline events
+-- routes/
|   +-- web.php                          -- Web dashboard routes
|   +-- api.php                          -- JSON API routes
+-- src/
    +-- SluiceServiceProvider.php
    +-- Console/Commands/                -- sluice:show, :stats, :export, :log, :clear
    +-- Facades/Sluice.php               -- Facade
    +-- Http/Controllers/
    |   +-- SluiceController.php         -- Web dashboard
    |   +-- Api/SluiceApiController.php  -- JSON API
    +-- Http/Middleware/SluiceAccess.php  -- Auth (4 strategies)
    +-- Listeners/ExceptionListener.php  -- Optional exception capture
    +-- Logging/TimelineLogger.php       -- Dual-driver logger
    +-- Models/                          -- Eloquent models
    +-- Sources/                         -- CloudWatch, S3, HTTP drivers
    +-- Services/TimelineService.php     -- Core aggregation engine

Security

  • The dashboard requires authentication (auth middleware) by default.
  • Access is controlled by 4 configurable authorization strategies.
  • The SLUICE_ENABLED env variable disables the package entirely.
  • Individual interfaces can be toggled independently: web_enabled, api.enabled, cli.enabled.
  • All request() calls are CLI-safe.

Recommended Production Setup

SLUICE_ENABLED=true
SLUICE_LOGGER_DRIVER=database
SLUICE_CAPTURE_EXCEPTIONS=true
Gate::define('view-sluice', fn($user) => $user->hasRole('developer'));

Quick Start

Minimal setup — just view your laravel.log:

composer require sluice/laravel-sluice
php artisan vendor:publish --tag=sluice-config
Gate::define('view-sluice', fn($user) => $user->hasRole('admin'));

Visit /sluice.

Full setup — database logging + exception capture + API:

composer require sluice/laravel-sluice
php artisan vendor:publish --tag=sluice-config
php artisan vendor:publish --tag=sluice-migrations
php artisan migrate
SLUICE_CAPTURE_EXCEPTIONS=true
SLUICE_API_ENABLED=true
use Sluice\LaravelSluice\Facades\Sluice;

Sluice::info('order_placed', 'Order #1234 placed', ['total' => 99.99], $user->id);

Contributing

Pull requests are welcome, especially for new source drivers. See the "Extending Sluice" section above for guidance on the expected structure.

Please open an issue first if you want to discuss a significant change before investing time in implementation.


License

MIT License. See LICENSE for details.