farayaz/laravel-spy
Zero-config Laravel package to spy on outgoing HTTP calls. Automatically logs Laravel Http facade and Guzzle requests with URL, method, headers, payload, response/status, and duration. Includes configurable logging and obfuscation for sensitive data.
Installation:
composer require farayaz/laravel-spy
The package auto-discovers and requires no manual bootstrapping.
Publish Configuration and Migrations:
php artisan vendor:publish --provider="Farayaz\LaravelSpy\LaravelSpyServiceProvider"
php artisan migrate
This sets up the http_logs table and default config.
Enable Logging:
Set SPY_ENABLED=true in your .env to start tracking requests immediately.
Debugging a Failing API Call:
// In your controller or job:
$response = Http::post('https://api.example.com/webhooks', [
'user_id' => 123,
'event' => 'payment.succeeded'
]);
// Check the logs table for the request/response details:
$log = \Farayaz\LaravelSpy\Models\HttpLog::latest()->first();
dd($log->response_body); // Inspect the raw response
php artisan tinker and query:
\Farayaz\LaravelSpy\Models\HttpLog::latest()->take(5)->get();
config/laravel-spy.php for obfuscation rules and exclusions.SPY_DASHBOARD_ENABLED=true), access /spy for a UI overview.Http:: facade calls and Guzzle clients bound to Laravel’s container are auto-logged.// Auto-logged via middleware
Http::get('https://api.github.com/users/octocat');
spy helper or service container to log requests manually:
use Farayaz\LaravelSpy\Facades\Spy;
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://api.example.com');
Spy::log($response, [
'url' => 'https://api.example.com',
'method' => 'GET',
'headers' => [],
'body' => null,
]);
.env:
SPY_EXCLUDE_URLS=*.staging.example.com,api.internal.*
if (!app('spy')->shouldLog('https://api.example.com')) {
// Skip logging
}
config/laravel-spy.php:
'obfuscate' => [
'headers' => ['authorization', 'x-api-key'],
'body' => ['password', 'credit_card'],
],
'obfuscate' => [
'body' => ['/token=[^&]+/', '/secret_[a-z]+/'],
],
HttpLog model or bind a custom logger via the spy.logged event:
// In EventServiceProvider
public function boot()
{
\Farayaz\LaravelSpy\Events\HttpLogged::listen(function ($log) {
// Send to external service (e.g., Datadog, Sentry)
\Log::channel('external')->info($log->toArray());
});
}
spy:clean scheduled daily.$this->post('/webhook', ['event' => 'test'])
->assertOk();
$log = \Farayaz\LaravelSpy\Models\HttpLog::latest()->first();
$this->assertEquals('POST', $log->method);
$this->assertStringContainsString('event=test', $log->body);
spy:clean command to purge old logs and integrate with Telescope’s storage:
// In app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->command('spy:clean')->daily();
}
spy middleware:
$client = new \GuzzleHttp\Client([
'middleware' => [
new \Farayaz\LaravelSpy\Middleware\SpyMiddleware(),
],
]);
'field_max_length' => 1024, // Truncate bodies >1KB
SPY_EXCLUDE_URLS=*.example.com/files/*
http_logs table.php artisan schedule:run
(Add to app/Console/Kernel.php as shown above.)SPY_CLEAN_DAYS=7
SpyMiddleware as shown in the integration section.token=[a-z0-9]{32} instead of token=.*).LaravelSpyServiceProvider loads after your middleware in app/Providers/AppServiceProvider.php:
public function register()
{
$this->app->register(\Farayaz\LaravelSpy\LaravelSpyServiceProvider::class);
}
php artisan tinker
>>> app('spy')->isEnabled()
// Should return `true`
php artisan tinker
>>> app('spy')->shouldLog('https://excluded.example.com')
// Should return `false` if excluded
php artisan spy:list
// Lists recent logs with IDs for debugging
SPY_ENABLED=false php artisan your:command
Add metadata to logs via the spy.logged event:
\Farayaz\LaravelSpy\Events\HttpLogged::listen(function ($log) {
$log->metadata = json_encode(['user_id' => auth()->id()]);
$log->save();
});
Extend the default dashboard (if enabled) by publishing views:
php artisan vendor:publish --tag=spy-views
Then override resources/views/vendor/laravel-spy/dashboard.blade.php.
Subscribe to the spy.logged event to forward logs to tools like Datadog or Sentry:
\Farayaz\LaravelSpy\Events\HttpLogged::listen(function ($log) {
\Sentry\captureMessage("HTTP Request: {$log->method} {$log->url}", [
'level' => 'info',
'extra' => $log->toArray(),
]);
});
Create a custom command to export logs to CSV/JSON:
// app/Console/Commands/ExportSpyLogs.php
public function handle()
{
$logs = \Farayaz\LaravelSpy\Models\HttpLog::all();
$this->info(json_encode($logs->toArray()));
}
How can I help you explore Laravel packages today?