Download the PHP package ahmedmerza/logscope without Composer
On this page you can find all versions of the php package ahmedmerza/logscope. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download ahmedmerza/logscope
More information about ahmedmerza/logscope
Files in ahmedmerza/logscope
Package logscope
Short Description A fast, database-backed log viewer for Laravel applications
License MIT
Informations about the package logscope
LogScope
A beautiful, database-backed log viewer for Laravel applications. Production-ready.
Quick Start
Visit /logscope in your browser. That's it!
What's New
Latest: 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 for full release history and behavior-change notes.
Table of Contents
- Features
- Requirements
- When to Use LogScope
- Installation
- Configuration
- Usage
- Production Deployment
- Customization
- Contributing
- License
β¨ Features
| Feature | Description |
|---|---|
| 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
- PHP 8.2+
- Laravel 10+
- SQLite, MySQL, or PostgreSQL
π€ 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:
| Concern | Solution |
|---|---|
| Database bloat | Retention policies with scheduled pruning (default: 30 days) |
| Performance | Batch mode writes logs after response is sent |
| Query speed | Proper indexes on common filter combinations |
β οΈ 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
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 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
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 viarunningUnitTests()-style guards in some versions)- Custom
set_error_handlercalls in user code that don't chain to the previous handler error_reportingbeing lowered to excludeE_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
If a dependency (or your own code) does:
β¦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:
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
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
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
Run the install command:
Access the dashboard at /logscope.
βοΈ Configuration
After installation, configure LogScope in config/logscope.php or via environment variables.
Capture Mode
Write Mode (Performance)
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():
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
Note: Retention requires either flipping
LOGSCOPE_RETENTION_AUTO_SCHEDULE=trueor schedulinglogscope:pruneyourself - see Schedule Pruning.
Features
Noise Reduction
Note:
null_channeldefaults tofalsebecauseLog::build()(dynamic loggers) produce logs without a channel. Setting this totruewould filter out those logs.
Cache TTL
JSON Viewer
Configure collapsible JSON behavior in config/logscope.php:
Routes
Add middleware and configure error redirects:
Error Handling
LogScope handles errors gracefully with toast notifications:
| Error | Behavior |
|---|---|
| 401/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 error | Toast only (check connection) |
Note: Redirect URLs can be relative paths (
/login) or absolute URLs (https://auth.example.com/login).
π Usage
Automatic Capture
All logs are captured automatically - no code changes needed:
Keyboard Shortcuts
| Key | Action |
|---|---|
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, Rto 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.
Search Syntax
Type directly in the search box using field:value syntax:
| Syntax | Example | Description |
|---|---|---|
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
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.
| Input | Treated as | Matches |
|---|---|---|
payment failed: timeout |
Single substring | Logs 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 alone |
Structured | Logs 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
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.168to find all IPs starting with that prefix, or42to 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:
Regex mode: Click the .* button to enable regex patterns:
Both search syntax and regex can be disabled in config if not needed.
Status Workflow
Logs have a status workflow: Open β Investigating β Resolved or Ignored.
Customize who changed the status:
Customize Statuses
Override built-in statuses or add new ones in config/logscope.php:
Available colors: gray, yellow, green, slate, blue, red, orange, purple
Quick Filters
Configure one-click filters in config/logscope.php:
Available options: label, icon (calendar/clock/alert/filter), levels, statuses, from, to
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:
Keyboard Shortcuts
Action shortcuts (refresh, pagination) are configurable or can be disabled:
Set any shortcut to null to disable it:
Authorization
LogScope uses a flexible auth system (checked in order):
1. Custom Callback:
2. Gate:
3. Default: Only accessible in local environment.
Custom Context
Add custom data to every log entry (e.g., API token ID, 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
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
Recommended Settings
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:
Don't enable both β auto-schedule plus a manual entry will run prune twice per night.
High-Traffic Apps
For thousands of requests/day:
-
Use queue mode with a dedicated queue:
-
Run a separate queue worker:
- Consider shorter retention (7 days).
π¨ Customization
Theme
Customize the appearance in config/logscope.php:
Disable external fonts (use system fonts instead):
Context Sanitization
LogScope automatically expands objects in your log context for better debugging:
Sensitive data is automatically redacted (password, token, api_key, credit_card, etc.):
Configure in config/logscope.php:
Publishing Assets
All Environment Variables
π‘οΈ Extensions
Watchtower
Block malicious IPs directly from the LogScope UI and sync the blacklist across all your environments automatically. (Previously named ahmedmerza/logscope-guard.)
π€ Contributing
Contributions are welcome! Please open an issue or submit a pull request.
π License
MIT License. See LICENSE for details.
All versions of logscope with dependencies
illuminate/contracts Version >=10.0
illuminate/database Version >=10.0
illuminate/support Version >=10.0