PHPackages                             digitaldev-lx/log-hole - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Admin Panels](/categories/admin)
4. /
5. digitaldev-lx/log-hole

ActiveLibrary[Admin Panels](/categories/admin)

digitaldev-lx/log-hole
======================

A modern Laravel logging package with multi-driver database support, web dashboard, and PHP attributes for declarative logging.

v3.0.0(1mo ago)213MITPHPPHP ^8.4CI passing

Since Oct 26Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/digitaldev-lx/log-hole)[ Packagist](https://packagist.org/packages/digitaldev-lx/log-hole)[ GitHub Sponsors](https://github.com/DigitalDevLx)[ RSS](/packages/digitaldev-lx-log-hole/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (6)Dependencies (24)Versions (9)Used By (0)

[![laravel-eupago-repo-banner](https://camo.githubusercontent.com/7b3701aded3239bd687b980e7399ead9975630feaf93ee7b9822fd5cc77b4ef6/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f62616e6e6572732f3539333738353535382f313637313139343635372f3135303078353030)](https://camo.githubusercontent.com/7b3701aded3239bd687b980e7399ead9975630feaf93ee7b9822fd5cc77b4ef6/68747470733a2f2f7062732e7477696d672e636f6d2f70726f66696c655f62616e6e6572732f3539333738353535382f313637313139343635372f3135303078353030)

Laravel LogHole
===============

[](#laravel-loghole)

LogHole is a modern, flexible Laravel logging package with multi-driver database support. Designed for seamless integration with Laravel's Log facade, it provides a web dashboard for browsing logs, an Artisan command for CLI access, and PHP 8.2+ attributes for declarative method-level logging.

[![Latest version](https://camo.githubusercontent.com/1647e33deaef6c9f9a9700cb7e261b4fb22c94e97e9af794b45d0ce7dfd46ca6/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652f6469676974616c6465762d6c782f6c6f672d686f6c653f7374796c653d666c61742d737175617265)](https://github.com/digitaldev-lx/log-hole/releases)[![GitHub license](https://camo.githubusercontent.com/4c4f65b83428caf2605955e61f4972e2d8b4280db71d876672b23e89b1edf485/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6469676974616c6465762d6c782f6c6f672d686f6c653f7374796c653d666c61742d737175617265)](https://github.com/digitaldev-lx/log-hole/blob/master/LICENSE)

---

Features
--------

[](#features)

- Custom Monolog database channel that stores logs in a configurable DB table
- Multi-driver support: MySQL, MariaDB (auto-detected), PostgreSQL, SQLite, SQL Server
- Web dashboard at `/log-hole` with Tailwind CSS v3 and Alpine.js (dark/light mode, filters, stats, auto-refresh)
- Artisan command `log-hole:tail` to query and purge logs from the CLI
- PHP 8.2+ attribute `#[Loggable]` for declarative method and class-level logging via middleware
- LogLevel enum with color-coded badges and Monolog conversion
- Strategy Pattern architecture with `LogDriverInterface` for extensibility

---

Requirements
------------

[](#requirements)

ReleasePHPLaravel2.0.0&gt;= 8.210.x, 11.x1.x&gt;= 8.210.x**Supported databases:** MySQL, MariaDB, PostgreSQL, SQLite, SQL Server

---

Installation
------------

[](#installation)

Install the package via Composer:

```
composer require digitaldev-lx/log-hole
```

Publish the configuration file:

```
php artisan vendor:publish --tag="log-hole-config"
```

Run the migration to create the `logs_hole` table:

```
php artisan migrate
```

---

Configuration
-------------

[](#configuration)

After publishing, the configuration file is located at `config/log-hole.php`:

```
return [
    'database' => [
        'driver' => 'custom',
        'via' => DigitalDevLx\LogHole\Channels\DatabaseChannel::class,
        'level' => env('LOG_LEVEL', 'debug'),
        'table' => 'logs_hole',
    ],

    // Database connection to use for logs (null = default connection)
    'connection' => env('LOG_HOLE_DB_CONNECTION', null),

    // Emails of users authorized to access the dashboard (empty = open access)
    'authorized_users' => [],

    // Route prefix for the dashboard
    'dashboard_route' => 'log-hole',

    // Number of logs per page in the dashboard
    'per_page' => 25,

    // Auto-refresh the dashboard every 5 seconds
    'auto_refresh' => false,
];
```

### Setting up the log channel

[](#setting-up-the-log-channel)

Add the LogHole database channel to your `config/logging.php`:

```
'channels' => [
    // ... other channels

    'database' => config('log-hole.database'),
],
```

Then set the channel as your default (or use it alongside other channels):

**Option A - Set as default channel in `.env`:**

```
LOG_CHANNEL=database
```

**Option B - Use as part of a stack:**

```
'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['single', 'database'],
    ],

    'database' => config('log-hole.database'),
],
```

**Option C - Log to the database channel on demand:**

```
use Illuminate\Support\Facades\Log;

Log::channel('database')->info('This goes to the database');
```

### Using a different database connection

[](#using-a-different-database-connection)

If you want logs stored in a different database, set the environment variable:

```
LOG_HOLE_DB_CONNECTION=mysql_logs
```

Make sure the connection is defined in `config/database.php` and the migration has run on that connection.

---

Usage
-----

[](#usage)

### Logging via the Log facade

[](#logging-via-the-log-facade)

```
use Illuminate\Support\Facades\Log;

// If 'database' is your default channel
Log::info('User logged in', ['user_id' => 1]);
Log::error('Payment failed', ['order_id' => 42, 'reason' => 'timeout']);
Log::warning('Disk space running low');

// Or target the database channel explicitly
Log::channel('database')->debug('Debug info', ['context' => 'value']);
```

All standard log levels are supported: `emergency`, `alert`, `critical`, `error`, `warning`, `notice`, `info`, `debug`.

---

PHP Attributes
--------------

[](#php-attributes)

LogHole provides the `#[Loggable]` PHP attribute for declarative logging on controller methods and classes. When the LogHole middleware is active, annotated actions are automatically logged after the request is handled.

### Setup the middleware

[](#setup-the-middleware)

#### Laravel 11.x

[](#laravel-11x)

In `bootstrap/app.php`:

```
use DigitalDevLx\LogHole\Middlewares\LogHoleMiddleware;

->withMiddleware(function (Middleware $middleware) {
    $middleware->append(LogHoleMiddleware::class);
})
```

#### Laravel 10.x

[](#laravel-10x)

In `app/Http/Kernel.php`:

```
protected $middlewareGroups = [
    'web' => [
        // ... other middleware
        \DigitalDevLx\LogHole\Middlewares\LogHoleMiddleware::class,
    ],
];
```

### Method-level attribute

[](#method-level-attribute)

```
use DigitalDevLx\LogHole\Attributes\Loggable;

class OrderController extends Controller
{
    #[Loggable(message: 'Order was created', level: 'info')]
    public function store(Request $request)
    {
        // ... your logic
    }

    #[Loggable(message: 'Order was deleted', level: 'warning')]
    public function destroy(Order $order)
    {
        // ... your logic
    }
}
```

### Class-level attribute

[](#class-level-attribute)

Apply the attribute to the class to log all controller actions:

```
use DigitalDevLx\LogHole\Attributes\Loggable;

#[Loggable(level: 'info')]
class UserController extends Controller
{
    public function index() { /* logged automatically */ }
    public function show(User $user) { /* logged automatically */ }
}
```

Method-level attributes take precedence over class-level attributes.

### Attribute options

[](#attribute-options)

ParameterTypeDefaultDescription`message``string``''`Custom log message. If empty, uses `"{method} was called"``level``LogLevel|string``LogLevel::Info`Log level (enum or string like `'error'`)`includeRequest``bool``false`Include request method, URL, and IP in context`channel``?string``null`Target a specific log channel (null = default)### Using the LogLevel enum

[](#using-the-loglevel-enum)

```
use DigitalDevLx\LogHole\Attributes\Loggable;
use DigitalDevLx\LogHole\Enums\LogLevel;

#[Loggable(message: 'Critical action', level: LogLevel::Critical, includeRequest: true)]
public function dangerousAction()
{
    // ...
}
```

---

Dashboard
---------

[](#dashboard)

The LogHole dashboard provides a modern web interface for browsing and filtering logs.

**URL:** `/log-hole` (configurable via `dashboard_route` in config)

### Features

[](#features-1)

- **Stats bar** with total count and per-level counters with color-coded badges
- **Server-side filters:** level, search term, date range (from/to)
- **Log table** with level badges, truncated messages with tooltip, expandable JSON context, and relative timestamps
- **Dark/light mode** toggle with localStorage persistence
- **Auto-refresh** toggle (reloads every 5 seconds)
- **Pagination** with Tailwind styling

### Restricting dashboard access

[](#restricting-dashboard-access)

By default, the dashboard is open to everyone. To restrict access, add authorized emails to the config:

```
'authorized_users' => [
    'admin@example.com',
    'developer@example.com',
],
```

When the list is not empty, only authenticated users with matching emails can access the dashboard. Unauthenticated users or users not in the list will receive a 403 error.

### Gate authorization

[](#gate-authorization)

LogHole also registers a `viewLogHole` Gate that you can use in your own authorization logic:

```
if (Gate::allows('viewLogHole')) {
    // user can view logs
}
```

---

Artisan Command
---------------

[](#artisan-command)

The `log-hole:tail` command allows you to query and purge logs directly from the CLI.

```
php artisan log-hole:tail {options}
```

### Options

[](#options)

OptionDescription`--emergency`Filter by EMERGENCY level`--alert`Filter by ALERT level`--critical`Filter by CRITICAL level`--error`Filter by ERROR level`--warning`Filter by WARNING level`--notice`Filter by NOTICE level`--info`Filter by INFO level`--debug`Filter by DEBUG level`--from=`Start date filter (e.g., `2024-10-01`)`--to=`End date filter (e.g., `2024-10-31`)`--take=`Limit the number of entries (default: 10)`--purge`Purge all logs (asks for confirmation)If no level option is specified, all levels are returned.

### Examples

[](#examples)

Fetch the last 10 logs (default):

```
php artisan log-hole:tail
```

Fetch error-level logs from a date range:

```
php artisan log-hole:tail --error --from=2024-10-01 --to=2024-10-31
```

Fetch the last 5 critical logs:

```
php artisan log-hole:tail --critical --take=5
```

Purge all logs (with confirmation prompt):

```
php artisan log-hole:tail --purge
```

### Output

[](#output)

The command displays logs in a table with the following columns:

```
+-----------+----------------------------------+----------------------------+---------------------+
| Level     | Message                          | Context                    | Logged At           |
+-----------+----------------------------------+----------------------------+---------------------+
| ERROR     | Payment failed                   | {                          | 2024-10-15 14:30:00 |
|           |                                  |     "order_id": 42,        |                     |
|           |                                  |     "reason": "timeout"    |                     |
|           |                                  | }                          |                     |
| WARNING   | Disk space running low           |                            | 2024-10-15 14:25:00 |
| INFO      | User logged in                   | {                          | 2024-10-15 14:20:00 |
|           |                                  |     "user_id": 1           |                     |
|           |                                  | }                          |                     |
+-----------+----------------------------------+----------------------------+---------------------+

```

Context is displayed as pretty-printed JSON for readability.

---

Driver Architecture
-------------------

[](#driver-architecture)

LogHole v2 uses the Strategy Pattern for database access. All drivers implement `LogDriverInterface`:

```
use DigitalDevLx\LogHole\Drivers\Contracts\LogDriverInterface;
```

The `DriverFactory` auto-detects your database driver and returns the appropriate implementation:

DatabaseDriver ClassSpecial FeaturesMySQL`MySqlDriver`JSON\_EXTRACT for context searchMariaDB`MariaDbDriver`Auto-detected via PDO version stringPostgreSQL`PostgreSqlDriver`ILIKE for case-insensitive searchSQLite`SqliteDriver`DELETE instead of TRUNCATE for purgeSQL Server`SqlServerDriver`CAST to NVARCHAR for context searchThe driver is registered as a singleton in the service container. You can resolve it directly:

```
use DigitalDevLx\LogHole\Drivers\Contracts\LogDriverInterface;

$driver = app(LogDriverInterface::class);

// Insert a log
$driver->insert(LogLevel::Info, 'Hello', ['key' => 'value'], now());

// Query logs with filters
$logs = $driver->query(level: LogLevel::Error, search: 'payment', limit: 20);

// Get paginated results
$paginated = $driver->paginate(level: LogLevel::Warning, perPage: 25);

// Get stats
$stats = $driver->stats();
echo $stats->total; // total log count
echo $stats->countForLevel(LogLevel::Error); // error count

// Purge logs
$driver->purge(); // purge all
$driver->purge(level: LogLevel::Debug); // purge only debug logs
$driver->purge(before: now()->subMonth()); // purge logs older than 1 month
```

---

Database Table
--------------

[](#database-table)

The migration creates a `logs_hole` table (configurable via `config('log-hole.database.table')`) with the following structure:

ColumnTypeNotes`id`bigintPrimary key, auto-increment`level`stringLog level (e.g., `ERROR`)`message`textLog message`context`jsonNullable, additional context`logged_at`datetimeNullable, when the log was createdIndexes: `level`, `logged_at`, `(level, logged_at)` composite.

---

Upgrading from v1.x to v2.0
---------------------------

[](#upgrading-from-v1x-to-v20)

### Breaking Changes

[](#breaking-changes)

1. **Config file structure changed** - Re-publish the config:

    ```
    php artisan vendor:publish --tag="log-hole-config" --force
    ```
2. **Publish tag renamed** - Changed from `--tag=logs-config` to `--tag=log-hole-config` (Spatie convention)
3. **Loggable attribute** - The `level` property is now a `LogLevel` enum (string values still work for backward compatibility). The `$level` public property was removed in favor of `$logLevel` (readonly `LogLevel` enum).
4. **Views and routes moved** - Views moved from `src/resources/views/` to `resources/views/`. Routes moved from `src/routes/` to `routes/`. If you published views, re-publish them.
5. **Migration indexes** - Re-run migrations to add the new performance indexes:

    ```
    php artisan migrate
    ```

### New Features in v2.0

[](#new-features-in-v20)

- Multi-driver database support (MySQL, MariaDB, PostgreSQL, SQLite, SQL Server)
- LogLevel enum with color-coded badges
- LogEntry and LogStats DTOs
- Redesigned dashboard with Tailwind v3, Alpine.js, dark mode, server-side filters, stats bar
- Class-level `#[Loggable]` attribute support
- `includeRequest` and `channel` options on `#[Loggable]`
- `--alert` flag and confirmation prompt on `--purge` in the Artisan command
- Pretty-printed JSON context in CLI output
- Configurable database connection via `LOG_HOLE_DB_CONNECTION`
- Auto-refresh toggle on dashboard
- 95 tests with PHPStan level 5

---

Testing
-------

[](#testing)

```
composer run test           # Run all tests (Pest)
composer run test-coverage  # Tests with coverage report
composer run analyse        # PHPStan level 5
composer run format         # Laravel Pint (PSR-12)
composer run check          # analyse + format together
```

---

License
-------

[](#license)

digitaldev-lx/log-hole is open-sourced software licensed under the [MIT license](LICENSE.md).

About DigitalDev
----------------

[](#about-digitaldev)

[DigitalDev](https://www.digitaldev.pt) is a web development agency based in Lisbon, Portugal. We specialize in Laravel, Livewire, and Tailwind CSS.

[Codeboys](https://www.codeboys.pt) is our special partner and we work together to deliver the best solutions for our clients.

###  Health Score

45

—

FairBetter than 93% of packages

Maintenance90

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity62

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~87 days

Recently: every ~130 days

Total

7

Last Release

47d ago

Major Versions

v1.3.0 → v2.0.02026-02-27

v2.0.0 → v3.0.02026-04-01

PHP version history (2 changes)v1.0.0PHP ^8.2

v3.0.0PHP ^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/c6498ae164eb066d13ae98668c2c9df065410dcb1da196561ef8f76c93c1a827?d=identicon)[digitaldevlx](/maintainers/digitaldevlx)

---

Top Contributors

[![digitaldev-lx](https://avatars.githubusercontent.com/u/81043832?v=4)](https://github.com/digitaldev-lx "digitaldev-lx (25 commits)")

---

Tags

laravellogsdashboardmulti-driverdatabase logslog-hole

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/digitaldev-lx-log-hole/health.svg)

```
[![Health](https://phpackages.com/badges/digitaldev-lx-log-hole/health.svg)](https://phpackages.com/packages/digitaldev-lx-log-hole)
```

###  Alternatives

[guava/filament-knowledge-base

A filament plugin that adds a knowledge base and help to your filament panel(s).

206120.5k1](/packages/guava-filament-knowledge-base)[ralphjsmit/laravel-filament-seo

A package to combine the power of Laravel SEO and Filament Admin.

15398.7k10](/packages/ralphjsmit-laravel-filament-seo)[vormkracht10/laravel-mails

Laravel Mails can collect everything you might want to track about the mails that has been sent by your Laravel app.

24149.7k](/packages/vormkracht10-laravel-mails)[andreia/filament-ui-switcher

Add a modal with options to switch between different UI layouts and styles (colors, fonts, font sizes).

233.8k](/packages/andreia-filament-ui-switcher)[geo-sot/filament-env-editor

Access .env file though Filament admin panel

2432.3k1](/packages/geo-sot-filament-env-editor)[caresome/filament-neobrutalism-theme

A neobrutalism theme for FilamentPHP admin panels

303.2k](/packages/caresome-filament-neobrutalism-theme)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
