PHPackages                             ahmedmerza/logscope - 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. [Logging &amp; Monitoring](/categories/logging)
4. /
5. ahmedmerza/logscope

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

ahmedmerza/logscope
===================

A fast, database-backed log viewer for Laravel applications

v1.7.1(1mo ago)2183[1 issues](https://github.com/AhmedMerza/laravel-logscope/issues)1MITPHPPHP ^8.2

Since Jan 20Pushed 1mo agoCompare

[ Source](https://github.com/AhmedMerza/laravel-logscope)[ Packagist](https://packagist.org/packages/ahmedmerza/logscope)[ RSS](/packages/ahmedmerza-logscope/feed)WikiDiscussions master Synced today

READMEChangelog (10)Dependencies (21)Versions (41)Used By (1)

LogScope
========

[](#logscope)

[![Latest Version](https://camo.githubusercontent.com/255a916e087a564bfaf7f9a63aafa9e6da9281e8d585d3410af405b8a05b6bdb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f61686d65646d65727a612f6c6f6773636f70652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/ahmedmerza/logscope)[![License](https://camo.githubusercontent.com/a2433598416c95aacb94e1ae36ec397f3336d51ab6d43de19777a075a97d4f21/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f61686d65646d65727a612f6c6f6773636f70652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/ahmedmerza/logscope)[![PHP Version](https://camo.githubusercontent.com/543d4fafc416213a7c4bbd8fd16dcb41fb40cbabfd0f292c66b3e363e1dbbd65/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f61686d65646d65727a612f6c6f6773636f70652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/ahmedmerza/logscope)

A beautiful, database-backed log viewer for Laravel applications. Production-ready.

[![LogScope Screenshot](art/logscope-preview.png)](art/logscope-preview.png)

Quick Start
-----------

[](#quick-start)

```
composer require ahmedmerza/logscope
php artisan logscope:install
php artisan migrate
```

Visit `/logscope` in your browser. That's it!

---

What's New
----------

[](#whats-new)

**Latest: [v1.7.1](https://github.com/AhmedMerza/laravel-logscope/releases/tag/v1.7.1)** — Search NOT toggle is now a true boolean complement (#24): `include + exclude == total` for any input. A stray colon in a phrase no longer fragments your search, and rows with NULL columns no longer disappear from both views.

See [CHANGELOG.md](CHANGELOG.md) for full release history and behavior-change notes.

---

Table of Contents
-----------------

[](#table-of-contents)

- [Features](#-features)
- [Requirements](#-requirements)
- [When to Use LogScope](#-when-to-use-logscope)
- [Installation](#-installation)
- [Configuration](#%EF%B8%8F-configuration)
- [Usage](#-usage)
- [Production Deployment](#-production-deployment)
- [Customization](#-customization)
- [Contributing](#-contributing)
- [License](#-license)

---

✨ Features
----------

[](#-features)

FeatureDescription**Zero-Config Capture**Automatically captures ALL logs from ALL channels**Request Context**Trace ID, user ID, IP, URL, and user agent for every log**Advanced Search**Search syntax (`field:value`), regex support, NOT toggle**Smart Filters**Include/exclude by level, channel, HTTP method, date range**Active Filters Bar**See all active filters at a glance, clear individually**Channel Search**Search and filter channels when you have many**JSON Viewer**Syntax-highlighted, collapsible JSON with copy support**Smart Context**Auto-expand Request/Model objects, redact sensitive data**Status Workflow**Track logs as open, investigating, resolved, or ignored**Log Notes**Add investigation notes to any log entry**Quick Filters**One-click filters for common queries**Keyboard Shortcuts**14 shortcuts for navigation, status changes, and actions**Dark Mode**Full dark mode support with persistence**Shareable URLs**Current filters reflected in URL for sharing**Deep Linking**Link directly to specific log entries**Performance**Keyset pagination, batch writes, query optimization, proper indexing---

📋 Requirements
--------------

[](#-requirements)

- PHP 8.2+
- Laravel 10+
- SQLite, MySQL, or PostgreSQL

---

🤔 When to Use LogScope
----------------------

[](#-when-to-use-logscope)

LogScope stores logs in your database - a deliberate choice that works great for most Laravel apps.

**Great fit if you:**

- Want log visibility without external services
- Have a typical Laravel app (up to ~100K requests/day)
- Need rich search and filtering
- Prefer simplicity over infrastructure complexity

**Consider alternatives if you:**

- Process millions of requests daily
- Need months/years of log retention
- Already use centralized logging (Datadog, CloudWatch, ELK)

**How LogScope handles common concerns:**

ConcernSolutionDatabase bloatRetention policies with scheduled pruning (default: 30 days)PerformanceBatch mode writes logs *after* response is sentQuery speedProper indexes on common filter combinations---

⚠️ Known Limitations
--------------------

[](#️-known-limitations)

LogScope captures everything that flows through Laravel's logger (`Illuminate\Log\Logger`). A few categories of logs structurally bypass that path and **cannot be auto-captured**. These are PHP / framework limitations, not bugs we can fix from a Composer package.

### 1. PHP's native `error_log()` is not interceptable

[](#1-phps-native-error_log-is-not-interceptable)

`error_log("...")` is a built-in PHP function that writes directly to the destination configured in `php.ini`'s `error_log` directive (file, syslog, or stderr). It calls into PHP's C-level logging, never invokes `set_error_handler`, and there's no userland API to redirect it. Workarounds (the [`uopz`](https://www.php.net/manual/en/book.uopz.php) extension, php.ini overrides, stderr capture) all live outside the PHP application — out of scope for a package.

If your app or a dependency calls `error_log()`, those messages land in your php-fpm/server log, **not** in LogScope. Search both places when investigating.

### 2. `trigger_error(E_USER_*)` *should* work, but depends on Laravel's exception handler

[](#2-trigger_errore_user_-should-work-but-depends-on-laravels-exception-handler)

PHP routes `trigger_error()` through the registered `set_error_handler`, and Laravel's `HandleExceptions` bootstrapper installs one that converts these to `ErrorException` and reports them — which then fires `MessageLogged` and reaches LogScope. So in normal HTTP/CLI flow this works.

**It can break in specific contexts** where Laravel's exception handler is bypassed:

- `php artisan tinker` (skips reporting via `runningUnitTests()`-style guards in some versions)
- Custom `set_error_handler` calls in user code that don't chain to the previous handler
- `error_reporting` being lowered to exclude `E_USER_*` levels

If something seems missing here, check `error_reporting()` and that `\Illuminate\Foundation\Bootstrap\HandleExceptions::class` is in your bootstrap chain (it is by default in Laravel 10/11/12).

### 3. Direct Monolog instances bypass capture

[](#3-direct-monolog-instances-bypass-capture)

If a dependency (or your own code) does:

```
$logger = new \Monolog\Logger('foo');
$logger->error('something');
```

…that's a raw Monolog logger, not Laravel's `Illuminate\Log\Logger`. Only Laravel's logger fires `MessageLogged`. The Monolog instance has no way to know LogScope exists.

**Opt-in workaround:** push our handler onto the Monolog instance:

```
use LogScope\Logging\LogScopeHandler;

$logger = new \Monolog\Logger('foo');
$logger->pushHandler(new LogScopeHandler('foo'));  // 'foo' = the channel name to record
$logger->error('captured by LogScope now');
```

Auto-instrumentation isn't possible — we'd have to patch the `Monolog\Logger` class itself.

### 4. SIGKILL / segfault / E\_PARSE in batch write mode loses the buffered batch

[](#4-sigkill--segfault--e_parse-in-batch-write-mode-loses-the-buffered-batch)

Batch mode (`LOGSCOPE_WRITE_MODE=batch`, default) accumulates logs during the request and flushes them on `app->terminating()` or PHP shutdown. Both safety nets require a graceful shutdown:

- `kill -9` (SIGKILL): cannot be caught by PHP — buffer is gone
- OOM kill: same
- `E_PARSE` / `E_COMPILE_ERROR`: PHP can't run user code at shutdown for these

**If low-loss is critical**, set `LOGSCOPE_WRITE_MODE=sync` to write every log immediately. Cost: each `Log::*()` call adds a synchronous DB round-trip.

### 5. `null_channel` filter — read before enabling

[](#5-null_channel-filter--read-before-enabling)

`LOGSCOPE_IGNORE_NULL_CHANNEL=true` drops logs that LogScope can't attribute to a named channel. **This includes Laravel's own framework-level error reporter in some configurations**, which means enabling this flag may silently drop unhandled exceptions. Only enable if you know exactly which no-channel logs flow through your app.

---

📦 Installation
--------------

[](#-installation)

```
composer require ahmedmerza/logscope
```

Run the install command:

```
php artisan logscope:install
php artisan migrate
```

Access the dashboard at `/logscope`.

---

⚙️ Configuration
----------------

[](#️-configuration)

After installation, configure LogScope in `config/logscope.php` or via environment variables.

### Capture Mode

[](#capture-mode)

```
# 'all' (default) - Capture all logs automatically
# 'channel' - Only capture logs sent to the logscope channel
LOGSCOPE_CAPTURE=all
```

### Write Mode (Performance)

[](#write-mode-performance)

```
# 'batch' (default) - Buffer logs, write after response
# 'sync' - Write immediately (simple, but slower)
# 'queue' - Queue each log entry (best for high-traffic)
LOGSCOPE_WRITE_MODE=batch

# Queue settings (when using 'queue' mode)
LOGSCOPE_QUEUE=default
LOGSCOPE_QUEUE_CONNECTION=
```

### Testing

[](#testing)

LogScope forces `write_mode` to `sync` whenever the app is running in the `testing` environment, regardless of what `LOGSCOPE_WRITE_MODE` or `config/logscope.php` says. This mirrors how Laravel ships sensible test defaults for mail (`array`), queue (`sync`), and cache (`array`).

Why: in `batch` mode the buffer is flushed on `Application::terminate()`. Unit tests that never dispatch a request never trigger that callback, so entries accumulate across tests and get discarded at PHP shutdown — producing both noisy stderr warnings and silent loss of the captured logs. `sync` writes land inside the test's transaction and roll back cleanly with `RefreshDatabase` / `DatabaseTransactions`.

If you specifically want to exercise batch behavior in a test, opt back in inside `setUp()`:

```
protected function setUp(): void
{
    parent::setUp();
    config(['logscope.write_mode' => 'batch']);
}
```

Even with that override, the shutdown discard warning is suppressed in the testing env (the loss is expected and uninteresting) — production keeps the loud notify so real data loss stays visible.

### Retention

[](#retention)

```
LOGSCOPE_RETENTION_ENABLED=true
LOGSCOPE_RETENTION_DAYS=30

# Optional: let LogScope register the prune schedule for you (off by default).
# Leave off if you already wire `logscope:prune` in your own console kernel.
LOGSCOPE_RETENTION_AUTO_SCHEDULE=false
LOGSCOPE_RETENTION_SCHEDULE_AT=03:00
```

> **Note:** Retention requires either flipping `LOGSCOPE_RETENTION_AUTO_SCHEDULE=true` or scheduling `logscope:prune` yourself - see [Schedule Pruning](#schedule-pruning).

### Features

[](#features)

```
LOGSCOPE_FEATURE_STATUS=true       # Enable status workflow
LOGSCOPE_FEATURE_NOTES=true        # Add notes to logs
```

### Noise Reduction

[](#noise-reduction)

```
# Filter out noisy logs
LOGSCOPE_IGNORE_DEPRECATIONS=true  # Skip "is deprecated" messages (default: true)
LOGSCOPE_IGNORE_NULL_CHANNEL=false # Skip logs without a channel (default: false)
```

> **Note:** `null_channel` defaults to `false` because `Log::build()` (dynamic loggers) produce logs without a channel. Setting this to `true` would filter out those logs.

### Cache TTL

[](#cache-ttl)

```
# How long (in seconds) to cache stats and filter options (levels, channels, etc.)
# Set to 0 to disable caching
LOGSCOPE_CACHE_TTL=60
```

### JSON Viewer

[](#json-viewer)

Configure collapsible JSON behavior in `config/logscope.php`:

```
'json_viewer' => [
    'collapse_threshold' => 5,  // Auto-collapse arrays/objects larger than this
    'auto_collapse_keys' => ['trace', 'stack_trace', 'stacktrace', 'backtrace'],
],
```

### Routes

[](#routes)

```
LOGSCOPE_ROUTES_ENABLED=true
LOGSCOPE_ROUTE_PREFIX=logscope
LOGSCOPE_DOMAIN=
LOGSCOPE_FORBIDDEN_REDIRECT=/
LOGSCOPE_UNAUTHENTICATED_REDIRECT=/login
```

Add middleware and configure error redirects:

```
'routes' => [
    'middleware' => ['web', 'auth'],
    'forbidden_redirect' => '/',           // Where to redirect on 403 (access denied)
    'unauthenticated_redirect' => '/login', // Where to redirect on 401/419 (session expired)
],
```

### Error Handling

[](#error-handling)

LogScope handles errors gracefully with toast notifications:

ErrorBehavior401/419 (Session expired)Toast + redirect to `unauthenticated_redirect`403 (Access denied)Toast + redirect to `forbidden_redirect`429 (Rate limited)Toast only (retry later)500+ (Server error)Toast only (temporary issue)Network errorToast only (check connection)> **Note:** Redirect URLs can be relative paths (`/login`) or absolute URLs (`https://auth.example.com/login`).

---

🚀 Usage
-------

[](#-usage)

### Automatic Capture

[](#automatic-capture)

All logs are captured automatically - no code changes needed:

```
Log::info('User logged in', ['user_id' => 1]);
Log::channel('slack')->error('Payment failed');
Log::stack(['daily', 'slack'])->warning('Low inventory');
```

### Keyboard Shortcuts

[](#keyboard-shortcuts)

KeyAction`j` / `k`Navigate down / up`h` / `l`Previous / next page`r`Refresh data`Enter`Open detail panel`Esc`Close panel`/`Focus search`y`Copy context (yank)`n`Focus note field`c`Clear all filters`d`Toggle dark mode`?`Show keyboard help**Status shortcuts** *(require Shift, context-aware — **behavior change since v1.5.8**)*:

| `O` | Open | `I` | Investigating | `R` | Resolved | `X` | Ignored |

- **With a log detail panel open** → change that log's status, advance to the next log. Optimistic UI: the row updates (or disappears, if hidden by current filter) immediately, no spinner. Designed for rapid triage — chain `R, R, R, R` to resolve four logs in seconds.
- **With no detail open** → filter the list by that status (the legacy behavior).

Pre-v1.5.9, these shortcuts always filtered the list, regardless of whether a log was open. If you relied on that, the in-detail-panel behavior is what you'll notice as different. The "no detail open" path is unchanged.

If a status update fails (network, server error), the row is restored and an error toast appears.

Action shortcuts (`r`, `h`, `l`) and status shortcuts are configurable — see [Keyboard Shortcuts](#keyboard-shortcuts).

### Search Syntax

[](#search-syntax)

Type directly in the search box using `field:value` syntax:

SyntaxExampleDescription`field:value``message:error`Search in specific field`-field:value``-level:debug`Exclude matches`field:"value"``message:"user login"`Quoted values with spaces`text``error`Search in all fields`-text``-deprecated`Exclude from all fields**Searchable fields:** `message`, `source`, `context`, `level`, `channel`, `user_id`, `ip_address`, `url`, `trace_id`, `http_method`

#### How multi-word and quoted searches behave

[](#how-multi-word-and-quoted-searches-behave)

LogScope only switches into structured-parse mode when the input actually looks structured. Otherwise the whole input is matched as a single substring — so a stray `:` in a log message (e.g. `failed: timeout`) doesn't fragment your query.

InputTreated asMatches`payment failed: timeout`Single substringLogs whose message/context/source contains the contiguous phrase `payment failed: timeout``"payment failed"`Single substring (quotes stripped)Logs containing `payment failed` contiguously`level:error message:timeout`Structured (`field:value` × 2)Logs where `level` matches `error` AND `message` contains `timeout``payment -warning`Structured (per-token `-` exclusion)Logs containing `payment` AND NOT containing `warning``level:error` aloneStructuredLogs where `level` matches `error`**Structured mode triggers when the input contains any of:** a quoted phrase (`"..."`), a per-token exclusion (`-word` or ` -word`), or a `field:value` where `field` is one of the searchable field names listed above.

#### NOT toggle = true boolean complement

[](#not-toggle--true-boolean-complement)

The UI's NOT toggle (or `exclude=1` on a `searches[]` query-string entry) inverts the entire search expression. For any input, `include_count + exclude_count == total_count` — logs are never lost between the two views.

> **Tip:** Request context filters (trace ID, user ID, IP, URL) support partial matching. Type `192.168` to find all IPs starting with that prefix, or `42` to find user IDs containing "42".

> **Tip:** Click on trace ID, user ID, or IP address in the detail panel to pivot your investigation — severity, channel, status, and search filters are cleared so nothing is hidden. Your date range is preserved.

**Examples:**

```
# Find errors in the API channel
channel:api level:error

# Find payment logs excluding debug
channel:payment -level:debug

# Find logs mentioning a specific user ID
user_id:123

# Find logs containing "timeout" anywhere
timeout

# Find logs with "connection failed" in message
message:"connection failed"

# Find context containing a job ID
context:abc123

# Exclude deprecated warnings
-message:deprecated

# Combine multiple conditions
level:error channel:database message:timeout

# Find all POST requests
http_method:POST

# Find logs from specific URL path
url:/api/payments

# Exclude health check endpoints
-url:/health -url:/ping

# Find logs from specific IP range
ip_address:192.168

# Track a specific request by trace ID
trace_id:abc-123-def
```

**Regex mode:** Click the `.*` button to enable regex patterns:

```
# Match error OR warning levels
level:error|warning

# Match any payment-related message
message:payment.*failed

# Match IP addresses starting with 192.168
ip_address:192\.168\.\d+\.\d+
```

Both search syntax and regex can be disabled in config if not needed.

### Status Workflow

[](#status-workflow)

Logs have a status workflow: **Open** → **Investigating** → **Resolved** or **Ignored**.

Customize who changed the status:

```
// In AppServiceProvider::boot()
use LogScope\LogScope;

LogScope::statusChangedBy(function ($request) {
    return $request->user()?->name;
});
```

#### Customize Statuses

[](#customize-statuses)

Override built-in statuses or add new ones in `config/logscope.php`:

```
'statuses' => [
    // Override built-in status
    'investigating' => [
        'label' => 'In Progress',
        'color' => 'blue',
    ],
    // Add custom statuses
    'waiting' => [
        'label' => 'Waiting for Customer',
        'color' => 'orange',
        'closed' => false,  // Shows in "Needs Attention"
    ],
    'duplicate' => [
        'label' => 'Duplicate',
        'color' => 'purple',
        'closed' => true,   // Hidden from "Needs Attention"
    ],
],
```

Available colors: `gray`, `yellow`, `green`, `slate`, `blue`, `red`, `orange`, `purple`

### Quick Filters

[](#quick-filters)

Configure one-click filters in `config/logscope.php`:

```
'quick_filters' => [
    ['label' => 'Today', 'icon' => 'calendar', 'from' => 'today'],
    ['label' => 'Recent Errors', 'icon' => 'alert', 'levels' => ['error', 'critical'], 'from' => '-24 hours'],
    ['label' => 'Needs Attention', 'icon' => 'filter', 'statuses' => ['open', 'investigating']],
    ['label' => 'Resolved Today', 'icon' => 'filter', 'statuses' => ['resolved'], 'from' => 'today'],
],
```

Available options: `label`, `icon` (calendar/clock/alert/filter), `levels`, `statuses`, `from`, `to`

### Status Shortcuts

[](#status-shortcuts)

Each status has a default keyboard shortcut (uppercase, requires Shift). The shortcut is **context-aware**:

- **Detail panel open:** change the open log's status, advance to next (rapid triage)
- **Detail panel closed:** filter the list by that status

Customize in `config/logscope.php`:

```
'statuses' => [
    // Disable a shortcut entirely (no triage AND no filter for this status)
    'ignored' => ['shortcut' => null],

    // Custom status with shortcut — works in both contexts automatically
    'waiting' => ['label' => 'Waiting', 'color' => 'orange', 'shortcut' => 'w'],
],
```

### Keyboard Shortcuts

[](#keyboard-shortcuts-1)

Action shortcuts (refresh, pagination) are configurable or can be disabled:

```
'keyboard_shortcuts' => [
    'refresh'   => 'r',  // Refresh logs and stats
    'prev_page' => 'h',  // Previous page
    'next_page' => 'l',  // Next page
],
```

Set any shortcut to `null` to disable it:

```
'keyboard_shortcuts' => [
    'prev_page' => null,  // Disable previous page shortcut
    'next_page' => null,
],
```

### Authorization

[](#authorization)

LogScope uses a flexible auth system (checked in order):

**1. Custom Callback:**

```
LogScope::auth(fn ($request) => $request->user()?->isAdmin());
```

**2. Gate:**

```
Gate::define('viewLogScope', fn ($user) => $user->hasRole('admin'));
```

**3. Default:** Only accessible in `local` environment.

### Custom Context

[](#custom-context)

Add custom data to every log entry (e.g., API token ID, tenant ID):

```
// In AppServiceProvider::boot()
use LogScope\LogScope;

LogScope::captureContext(function ($request) {
    $token = $request->user()?->currentAccessToken();

    return [
        // Sanctum returns TransientToken (no `id`) for session-authenticated
        // requests and PersonalAccessToken (has `id`) for token-authenticated
        // requests. Type-check before accessing.
        'token_id' => $token instanceof \Laravel\Sanctum\PersonalAccessToken ? $token->id : null,
        'tenant_id' => $request->user()?->tenant_id,
    ];
});
```

This data is merged into the log's `context` field and appears in the JSON viewer.

If your callback throws (a property access on the wrong type, an unbound service, etc.), LogScope catches the exception, drops the custom context for that log entry only, and adds `_logscope_callback_error` to the entry's context with the exception class + message. The original log is still captured. The callback failure is also surfaced via `error_log()` and the in-UI failure banner so you know the callback is broken.

### Artisan Commands

[](#artisan-commands)

```
# Import existing log files (one-time migration)
php artisan logscope:import
php artisan logscope:import storage/logs/laravel.log --days=7

# Prune old logs
php artisan logscope:prune
php artisan logscope:prune --dry-run
php artisan logscope:prune --days=14

# Diagnose configuration & wiring (CI-friendly: non-zero exit on any FAIL)
php artisan logscope:doctor
php artisan logscope:doctor --json

# Smoke-test the capture pipeline end-to-end
php artisan logscope:test
php artisan logscope:test --keep   # leave the test entry in the table
```

> **Note:** The import command is a one-time migration for existing log files. After setup, new logs are captured automatically.

`logscope:doctor` checks the table, capture mode, write mode (including queue connection), middleware wiring, retention + schedule status, authorization resolution path, Octane integration, built assets, and any cached write-failure breadcrumb. Run it after install or whenever something feels off.

`logscope:test` emits a uniquely-tagged log through the configured capture path, forces a sync write for the duration of the test, and verifies the entry lands in `log_entries`. Useful as a one-shot post-install sanity check.

---

🏭 Production Deployment
-----------------------

[](#-production-deployment)

### Recommended Settings

[](#recommended-settings)

```
LOGSCOPE_WRITE_MODE=batch
LOGSCOPE_RETENTION_DAYS=14
LOG_LEVEL=info
```

### Schedule Pruning

[](#schedule-pruning)

You have two options:

**Option 1 — Let LogScope do it (opt-in, off by default).** Set `LOGSCOPE_RETENTION_AUTO_SCHEDULE=true` and LogScope registers `logscope:prune` on Laravel's scheduler at the time configured by `LOGSCOPE_RETENTION_SCHEDULE_AT` (defaults to `03:00`), with `->onOneServer()` for safe multi-server deploys.

**Option 2 — Wire it yourself.** Leave `LOGSCOPE_RETENTION_AUTO_SCHEDULE` off and add the schedule entry where you keep the rest of your scheduled tasks:

```
// Laravel 11+ (routes/console.php)
Schedule::command('logscope:prune')->daily();

// Laravel 10 (app/Console/Kernel.php)
$schedule->command('logscope:prune')->daily();
```

> **Don't enable both** — auto-schedule plus a manual entry will run prune twice per night.

### High-Traffic Apps

[](#high-traffic-apps)

For thousands of requests/day:

1. Use queue mode with a dedicated queue:

    ```
    LOGSCOPE_WRITE_MODE=queue
    LOGSCOPE_QUEUE=logs
    ```
2. Run a separate queue worker:

    ```
    php artisan queue:work --queue=logs
    ```
3. Consider shorter retention (7 days).

---

🎨 Customization
---------------

[](#-customization)

### Theme

[](#theme)

Customize the appearance in `config/logscope.php`:

```
'theme' => [
    // Primary accent color (buttons, links, selections)
    'primary' => '#10b981',

    // Default to dark mode for new users (users can toggle and preference is saved)
    'dark_mode_default' => true,

    // Google Fonts (set to false to use system fonts)
    'fonts' => [
        'sans' => 'Outfit',         // UI text
        'mono' => 'JetBrains Mono', // Code/logs
    ],

    // Log level badge colors
    'levels' => [
        'error' => ['bg' => '#dc2626', 'text' => '#ffffff'],
        'warning' => ['bg' => '#f59e0b', 'text' => '#1f2937'],
        // ... other levels
    ],
],
```

**Disable external fonts** (use system fonts instead):

```
'fonts' => [
    'sans' => false,
    'mono' => false,
],
```

### Context Sanitization

[](#context-sanitization)

LogScope automatically expands objects in your log context for better debugging:

```
// Request objects show useful data
Log::info('API request', ['request' => $request]);
// Context: { "request": { "_type": "request", "method": "POST", "url": "...", "input": {...} } }

// Models and Arrayable objects are converted
Log::info('User action', ['user' => $user]);
// Context: { "user": { "name": "John", "email": "..." } }
```

**Sensitive data is automatically redacted** (password, token, api\_key, credit\_card, etc.):

```
Log::info('Login', ['request' => $request]);
// Input: { "email": "john@example.com", "password": "[REDACTED]" }
```

Configure in `config/logscope.php`:

```
'context' => [
    'expand_objects' => true,      // Set false to show [Object: ClassName]
    'redact_sensitive' => true,    // Set false to disable redaction (not recommended)
    'sensitive_keys' => [],        // Empty = use defaults, or provide your own list
    'sensitive_headers' => [],     // Empty = use defaults, or provide your own list
],
```

### Publishing Assets

[](#publishing-assets)

```
php artisan vendor:publish --tag=logscope-config
php artisan vendor:publish --tag=logscope-migrations
php artisan vendor:publish --tag=logscope-views
```

### All Environment Variables

[](#all-environment-variables)

```
# Capture & Performance
LOGSCOPE_CAPTURE=all
LOGSCOPE_WRITE_MODE=batch
LOGSCOPE_QUEUE=default
LOGSCOPE_QUEUE_CONNECTION=

# Features
LOGSCOPE_FEATURE_STATUS=true
LOGSCOPE_FEATURE_NOTES=true
LOGSCOPE_FEATURE_SEARCH_SYNTAX=true
LOGSCOPE_FEATURE_REGEX=true
LOGSCOPE_IGNORE_DEPRECATIONS=true
LOGSCOPE_IGNORE_NULL_CHANNEL=false

# Database & Retention
LOGSCOPE_TABLE=log_entries
LOGSCOPE_RETENTION_ENABLED=true
LOGSCOPE_RETENTION_DAYS=30
LOGSCOPE_MIGRATIONS_ENABLED=true

# Routes
LOGSCOPE_ROUTES_ENABLED=true
LOGSCOPE_ROUTE_PREFIX=logscope
LOGSCOPE_DOMAIN=
LOGSCOPE_MIDDLEWARE_ENABLED=true
LOGSCOPE_FORBIDDEN_REDIRECT=/
LOGSCOPE_UNAUTHENTICATED_REDIRECT=/login

# Search
LOGSCOPE_SEARCH_DRIVER=database

# Cache
LOGSCOPE_CACHE_TTL=60

# Context Sanitization
LOGSCOPE_EXPAND_OBJECTS=true
LOGSCOPE_REDACT_SENSITIVE=true
```

---

🛡️ Extensions
-------------

[](#️-extensions)

### Watchtower

[](#watchtower)

Block malicious IPs directly from the LogScope UI and sync the blacklist across all your environments automatically. (Previously named `ahmedmerza/logscope-guard`.)

```
composer require ahmedmerza/laravel-watchtower
php artisan watchtower:install
```

[View Watchtower →](https://github.com/AhmedMerza/laravel-watchtower)

---

🤝 Contributing
--------------

[](#-contributing)

Contributions are welcome! Please open an issue or submit a pull request.

---

📄 License
---------

[](#-license)

MIT License. See [LICENSE](LICENSE) for details.

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance81

Actively maintained with recent releases

Popularity17

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 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 ~3 days

Total

38

Last Release

44d ago

Major Versions

v0.6.1 → v1.0.02026-01-26

### Community

Maintainers

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

---

Top Contributors

[![AhmedMerza](https://avatars.githubusercontent.com/u/67040497?v=4)](https://github.com/AhmedMerza "AhmedMerza (19 commits)")

---

Tags

laravelloggingmonitoringdebugginglogslog viewer

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/ahmedmerza-logscope/health.svg)

```
[![Health](https://phpackages.com/badges/ahmedmerza-logscope/health.svg)](https://phpackages.com/packages/ahmedmerza-logscope)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[laravel/ai

The official AI SDK for Laravel.

1.0k3.2M193](/packages/laravel-ai)[spatie/laravel-health

Monitor the health of a Laravel application

87512.0M164](/packages/spatie-laravel-health)[api-platform/laravel

API Platform support for Laravel

58170.8k13](/packages/api-platform-laravel)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45444.2k1](/packages/pressbooks-pressbooks)[kssadi/log-tracker

A powerful, intuitive, and efficient log viewer for Laravel applications.

296.3k](/packages/kssadi-log-tracker)

PHPackages © 2026

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