facade/flare-client-php
PHP client for Flare error reporting and monitoring. Captures exceptions in Laravel/PHP apps, enriches with context, and sends them to Flare for grouping, analysis, and alerts. Configurable transport, stack traces, and metadata support.
## Getting Started
### Minimal Setup
1. **Install the package** via Composer:
```bash
composer require facade/flare-client-php
php artisan vendor:publish --provider="Facade\FlareClient\FlareServiceProvider" --tag="config"
.env with your Flare API key:
FLARE_API_KEY=your_api_key_here
use Facade\FlareClient\Flare;
try {
// Risky operation
} catch (\Exception $e) {
Flare::report($e)
->filter(function (\Exception $e) {
return $e instanceof \RuntimeException; // Custom filter logic
});
throw $e;
}
FlareServiceProvider (handles auto-registration in Laravel).Flare (primary entry point for reporting, now with programmatic filtering).config/flare.php (API key, endpoint, new: comprehensive filtering rules).Flare::report(new \Exception("Oops!")); // Respects config/flare.php filter rules
Flare::report($e)
->filter(function (\Exception $e) {
return strpos($e->getMessage(), 'critical') !== false;
});
'filter' => [
'types' => [\RuntimeException::class, \InvalidArgumentException::class],
],
'filter' => [
'messages' => ['*Timeout*', '*Connection*'],
],
'filter' => [
'callback' => function (\Exception $e) {
return app()->environment('production');
},
];
Flare::report($e)->filter(function (\Exception $e) {
return $e->getCode() === 500; // Override config
});
Add context while respecting filtering:
Flare::breadcrumb('User action', ['step' => 'checkout'])
->filter(function ($breadcrumb) {
return !app()->environment('local'); // Skip in local
});
Automatically report and filter exceptions:
class ReportFilteredExceptions
{
public function handle($request, Closure $next)
{
try {
return $next($request);
} catch (\Exception $e) {
Flare::report($e)
->filter(function (\Exception $e) use ($request) {
return $request->ip() !== '127.0.0.1'; // Skip local IPs
});
throw $e;
}
}
}
Leverage Laravel environments in filters:
Flare::report($e)->filter(function (\Exception $e) {
return app()->environment(['staging', 'production']);
});
Modify payloads before filtering occurs:
Flare::extend(function ($payload) {
$payload['is_critical'] = strpos($payload['exception']['message'], 'critical') !== false;
return $payload;
});
Filter Precedence Confusion:
->filter() call in code takes priority over config/flare.php rules.Overly Aggressive Filtering:
catch-all callbacks that return false).APP_DEBUG=true and log skipped reports:
Flare::report($e)->filter(function (\Exception $e) {
if (app()->environment('local')) {
Log::debug("Skipping local report: " . $e->getMessage());
return false;
}
return true;
});
Performance in Filter Callbacks:
// Bad: DB query in filter
->filter(function (\Exception $e) {
return DB::table('errors')->where('id', $e->getCode())->exists();
});
// Good: Pre-compute or use simple logic
->filter(function (\Exception $e) {
return $e->getCode() >= 500;
});
Wildcard Filtering Quirks:
messages wildcards (*) are case-sensitive and match substrings.'*Timeout*' matches "Request Timeout" but not "timeout error".Filtering and ->later():
Type Hierarchy in Filtering:
\RuntimeException, subclasses (e.g., \InvalidArgumentException) are not automatically excluded unless specified.'filter' => [
'types' => [\RuntimeException::class, \InvalidArgumentException::class],
],
Verify Filter Rules:
'filter' => false, // Disable in config
Flare::report($e)->filter(function (\Exception $e) {
$shouldReport = strpos($e->getMessage(), 'error') !== false;
Log::debug("Filter result for {$e::class}: " . ($shouldReport ? 'PASS' : 'BLOCK'));
return $shouldReport;
});
Check Filter Order:
->then() to chain filters and debug precedence:
Flare::report($e)
->filter(function (\Exception $e) { /* First filter */ })
->then(function ($payload) { /* Inspect payload */ })
->filter(function (\Exception $e) { /* Second filter */ });
Test with Edge Cases:
$e->getPrevious()).null or objects).Custom Filter Logic:
class ProductionOnlyFilter
{
public function __invoke(\Exception $e)
{
return app()->environment('production');
}
}
Flare::report($e)->filter(new ProductionOnlyFilter());
Filter Validation:
Flare::extend(function ($payload) {
if (empty($payload['exception']['class'])) {
throw new \InvalidArgumentException("Invalid exception payload");
}
return $payload;
});
Filter Presets:
'filters' => [
'production' => [
'types' => [\RuntimeException::class],
'messages' => ['*critical*'],
],
'staging' => [
'callback' => function (\Exception $e) {
return true; // Report everything
},
],
];
Filter Events:
event(new FlareFiltering($e, $shouldReport));
Dynamic Filter Loading:
$filterRules = Cache::get('flare_filters');
Flare::report($e)->filter(function (\Exception $e) use ($filterRules) {
return $filterRules['callback']($e);
});
callback) will throw:
How can I help you explore Laravel packages today?