Turkish documentation: README.tr.md
A professional Laravel package that automatically captures, deduplicates, and stores all unhandled exceptions to the database — giving you a persistent, queryable history of every error your application encounters.
- Zero-configuration capture — automatically intercepts all unhandled exceptions via Laravel's
reportable()hook. No changes toHandler.phporbootstrap/app.phprequired. - Smart deduplication — identical errors (same class + message + file + line) are grouped into a single record. Only the occurrence count and last-seen timestamp update on repeat occurrences.
- Manual capture — catch blocks can report exceptions with one line using the
ErrorTracker::capture()facade or Laravel's built-inreport()helper. - Per-call severity override — override the severity level for a specific capture call:
ErrorTracker::capture($e, ['severity' => 'critical']). - Full HTTP context — stores the URL, HTTP method, client IP, user agent, authenticated user ID, sanitized request input, and selected headers alongside each error.
- CLI & queue support — exceptions from Artisan commands and queued jobs are captured with null HTTP fields.
- PSR-3 severity levels — configurable severity mapping by exception class (debug → emergency).
- Status lifecycle — triage errors as
open,resolved, orignoreddirectly on the model. - Rich statistics — 10+ static methods on the
ErrorLogmodel for building dashboards and reports. - Artisan commands —
error-tracker:statsanderror-tracker:clearfor CLI management. - Async queue support — writes can be dispatched asynchronously to keep response times fast.
- Rate limiting — prevents the same error from flooding the queue during bursts. Each unique fingerprint is throttled to a configurable number of dispatches per time window using the Laravel cache.
- Privacy first — configurable field exclusion (passwords, tokens, payment data) and a header whitelist.
- Laravel 9 / 10 / 11 / 12 compatible.
| Dependency | Version |
|---|---|
| PHP | >= 8.0 |
| Laravel | 9, 10, 11, or 12 |
composer require ibrahim-kaya/error-trackerphp artisan migratephp artisan vendor:publish --tag=error-tracker-configThis copies the config file to config/error-tracker.php where you can customize it.
The package works out of the box without publishing the config — sensible defaults are applied automatically.
After publishing the config, open config/error-tracker.php:
return [
// Toggle error tracking on/off without uninstalling the package.
// Env key: ERROR_TRACKER_ENABLED
'enabled' => env('ERROR_TRACKER_ENABLED', true),
// Exception classes (and their subclasses) that should NOT be tracked.
'excluded_exceptions' => [
\Illuminate\Validation\ValidationException::class,
\Illuminate\Auth\AuthenticationException::class,
\Illuminate\Session\TokenMismatchException::class,
\Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class,
\Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException::class,
],
// Dispatch the DB write via a queue worker (true) or synchronously (false).
// Env key: ERROR_TRACKER_QUEUE
'use_queue' => env('ERROR_TRACKER_QUEUE', true),
// Queue name to dispatch jobs onto.
// Env key: ERROR_TRACKER_QUEUE_NAME
'queue' => env('ERROR_TRACKER_QUEUE_NAME', 'default'),
// Store sanitized request input alongside each error.
'log_request_input' => true,
// These request fields are always stripped before storage.
'excluded_input_fields' => [
'password', 'password_confirmation', 'token', '_token',
'credit_card', 'cvv', 'card_number', 'ssn',
],
// Store selected request headers (disabled by default for security).
'log_request_headers' => false,
// Only these headers are ever stored when log_request_headers is true.
'logged_headers' => ['accept', 'accept-language', 'content-type', 'referer', 'origin'],
// Map exception classes to PSR-3 severity levels.
// Uses instanceof — parent classes cover all subclasses.
'severity_map' => [
\Illuminate\Database\QueryException::class => 'critical',
\Illuminate\Database\Eloquent\ModelNotFoundException::class => 'warning',
\Symfony\Component\HttpKernel\Exception\HttpException::class => 'warning',
],
];| Key | Default | Description |
|---|---|---|
ERROR_TRACKER_ENABLED |
true |
Enable or disable tracking |
ERROR_TRACKER_QUEUE |
true |
Use queue for async writes |
ERROR_TRACKER_QUEUE_NAME |
default |
Queue name for jobs |
Once installed, nothing extra is needed. All unhandled exceptions are automatically intercepted and stored. The package registers a reportable() callback through the ServiceProvider — your existing Handler.php or bootstrap/app.php is never modified.
use IbrahimKaya\ErrorTracker\Facades\ErrorTracker;
try {
$this->processPayment($order);
} catch (\Exception $e) {
// Capture and continue — will not re-throw
ErrorTracker::capture($e);
return response()->json(['error' => 'Payment failed, please retry.'], 500);
}use IbrahimKaya\ErrorTracker\Facades\ErrorTracker;
try {
$this->syncInventory();
} catch (\Exception $e) {
// Override the severity level for this specific capture
ErrorTracker::capture($e, ['severity' => 'critical']);
}Laravel's report() helper also triggers the package's reportable() callback:
try {
$this->sendWelcomeEmail($user);
} catch (\Exception $e) {
report($e); // Works with ErrorTracker automatically
// continue with the request...
}Use the ErrorLog Eloquent model directly:
use IbrahimKaya\ErrorTracker\Models\ErrorLog;
// Get all open errors, most recent first
$errors = ErrorLog::open()->orderByDesc('last_seen_at')->get();
// Get only critical errors
$critical = ErrorLog::withSeverity('critical')->get();
// Get errors for a specific exception class
$queryErrors = ErrorLog::forExceptionClass(\Illuminate\Database\QueryException::class)->get();
// Get errors within a date range
$rangeErrors = ErrorLog::dateRange('2024-01-01', '2024-03-31')->get();
// Find a specific error by fingerprint
$error = ErrorLog::where('fingerprint', $hash)->first();$error = ErrorLog::find(1);
// Mark as resolved — resolves and records resolved_at
$error->markResolved();
// Mark as ignored — records ignored_at
$error->markIgnored();
// Reopen a resolved or ignored error
$error->reopen();All statistics are available as static methods on the ErrorLog model:
use IbrahimKaya\ErrorTracker\Models\ErrorLog;
// Counts
ErrorLog::totalErrors(); // Total unique error groups
ErrorLog::totalErrors('open'); // Only open errors
ErrorLog::totalOccurrences(); // Sum of all occurrence counts
ErrorLog::openErrorCount();
ErrorLog::resolvedErrorCount();
ErrorLog::ignoredErrorCount();
// Rankings
ErrorLog::mostFrequent(10); // Top 10 most-occurring errors
ErrorLog::mostRecent(10); // Top 10 most recently seen
// Grouped aggregations
ErrorLog::statisticsByExceptionClass(5); // Top 5 exception classes
ErrorLog::statisticsBySeverity(); // Counts grouped by severity
ErrorLog::statisticsByStatus(); // Counts grouped by status
ErrorLog::statisticsByFile(10); // Top 10 most error-prone files
// Trends
ErrorLog::dailyStatistics(30); // Daily counts for last 30 days
ErrorLog::errorsByDateRange('2024-01-01', '2024-12-31', 'open');
// Dashboard — single call that returns all of the above
$summary = ErrorLog::summaryStatistics(30);
// Returns: total_errors, total_occurrences, open_errors, resolved_errors,
// ignored_errors, by_severity, by_exception_class, most_frequent,
// most_recent, daily_trendphp artisan error-tracker:stats
php artisan error-tracker:stats --days=7Example output:
Error Tracker Statistics (last 30 days)
──────────────────────────────────────────────────────
Overview
Total unique errors: 42
Total occurrences: 317
Open: 28
Resolved: 10
Ignored: 4
By Severity
+----------+--------------+--------------------+
| Severity | Error Groups | Total Occurrences |
+----------+--------------+--------------------+
| critical | 5 | 134 |
| error | 30 | 162 |
| warning | 7 | 21 |
+----------+--------------+--------------------+
Top 5 Exception Classes
+--------------------------------------------+--------+-------------+
| Exception Class | Groups | Occurrences |
+--------------------------------------------+--------+-------------+
| Illuminate\Database\QueryException | 5 | 134 |
| ErrorException | 12 | 89 |
+--------------------------------------------+--------+-------------+
# Delete all error logs (with confirmation prompt)
php artisan error-tracker:clear
# Delete only resolved errors
php artisan error-tracker:clear --status=resolved
# Delete resolved errors older than 30 days
php artisan error-tracker:clear --status=resolved --older-than=30
# Skip the confirmation prompt (for scheduled tasks)
php artisan error-tracker:clear --status=resolved --older-than=90 --forceOptions:
| Option | Default | Description |
|---|---|---|
--status |
(all) | Filter by status: open, resolved, or ignored |
--older-than |
0 |
Only delete records last seen more than N days ago |
--force |
false |
Skip the confirmation prompt |
| Laravel | PHP | Supported |
|---|---|---|
| 9.x | 8.0, 8.1 | ✅ |
| 10.x | 8.1, 8.2 | ✅ |
| 11.x | 8.2, 8.3 | ✅ |
| 12.x | 8.2, 8.3, 8.4 | ✅ |
The package uses ExceptionHandler::reportable(), which has been available since Laravel 8 and works identically across all supported versions — including Laravel 11+'s new bootstrap/app.php skeleton.
| Field | Description |
|---|---|
| Exception class | The PHP class name of the exception |
| Message | The exception message text |
| File & line | Where in the codebase the exception occurred |
| Stack trace | Function call chain (arguments excluded) |
| URL, method | The request URL and HTTP verb |
| IP address | Client IP, supports IPv6 |
| User agent | Browser string |
| User ID | Authenticated user's ID (cast to string) |
| Request input | Sanitized — sensitive fields stripped |
| Headers | Only whitelisted headers when enabled |
- Raw passwords or any field listed in
excluded_input_fields Authorizationheaders, cookies, or session data- Stack frame arguments (can contain models, closures, or large objects)
- File upload objects
Rate limiting prevents the same error from flooding the queue and database when it fires thousands of times per second (e.g. an exception inside a loop).
How it works:
Each unique fingerprint is tracked in the Laravel cache. Once it is captured more than max_attempts times within decay_seconds, further dispatches are silently dropped until the window resets. The error group is still correctly recorded — only excess job dispatches are suppressed.
// config/error-tracker.php
'rate_limiting' => [
'enabled' => env('ERROR_TRACKER_RATE_LIMITING', true),
'max_attempts' => 5, // allow up to 5 dispatches per window
'decay_seconds' => 60, // window resets after 60 seconds
],# Disable rate limiting entirely
ERROR_TRACKER_RATE_LIMITING=falseNote: Rate limiting requires a cache driver that supports atomic increments (Redis, Memcached, or the database driver). If the cache driver is unavailable, the check fails open — captures are never dropped due to a cache failure.
Add exception classes to the excluded_exceptions config key to prevent them from being tracked:
'excluded_exceptions' => [
\App\Exceptions\ExpectedBusinessException::class,
\Illuminate\Validation\ValidationException::class,
// ...
],# .env.local
ERROR_TRACKER_ENABLED=falseContributions, issues, and feature requests are welcome. Please open an issue first to discuss what you would like to change.
This package is open-sourced software licensed under the MIT license.
Author: İbrahim Kaya