Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Spy Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require farayaz/laravel-spy
    

    The package auto-discovers and requires no manual bootstrapping.

  2. Publish Configuration (optional, uses defaults otherwise):

    php artisan vendor:publish --provider="Farayaz\LaravelSpy\LaravelSpyServiceProvider"
    
  3. Run Migrations:

    php artisan migrate
    

    Creates the http_logs table for storing request/response data.

  4. Enable Logging (via .env):

    SPY_ENABLED=true
    
  5. First Use Case: Any HTTP request via Laravel’s Http facade or Guzzle will now auto-log. Example:

    // In a controller or job
    $response = Http::get('https://api.example.com/data');
    

    The request details (URL, method, headers, body, response, duration) are stored in http_logs.


Implementation Patterns

Core Workflows

1. Auto-Mode (Default)

  • When to Use: For all new Laravel HTTP client usage (Http:: facade or container-bound Guzzle clients).
  • How It Works: The package automatically intercepts requests via Guzzle middleware.
  • Example:
    // Auto-logged (no extra code needed)
    Http::post('https://stripe.com/charges', ['amount' => 1000]);
    

2. Manual Mode (Legacy Code)

  • When to Use: For standalone Guzzle clients (e.g., new \GuzzleHttp\Client()) or non-Laravel HTTP clients.
  • How It Works: Attach the SpyMiddleware manually.
  • Example:
    use Farayaz\LaravelSpy\Middleware\SpyMiddleware;
    
    $client = new \GuzzleHttp\Client([
        'middleware' => [
            new SpyMiddleware(),
        ],
    ]);
    

3. Conditional Logging

  • When to Use: To exclude specific endpoints (e.g., internal APIs, health checks).
  • How It Works: Use SPY_EXCLUDE_URLS in .env:
    SPY_EXCLUDE_URLS=*.internal-api.com,/health
    
  • Dynamic Exclusion: Override via config:
    'excluded_urls' => [
        '*.analytics.example.com',
        fn(string $url) => str_contains($url, 'webhook'),
    ],
    

4. Obfuscation Rules

  • When to Use: To mask sensitive data (tokens, passwords, PII) in logs.
  • How It Works: Configure in config/spy.php:
    'obfuscate' => [
        'headers' => ['authorization', 'x-api-key'],
        'body' => ['password', 'secret', 'token'],
        'response' => ['card_*', 'ssn'],
    ],
    
  • Regex Support: Use regex patterns (e.g., credit_card_.*).

5. Dashboard Integration

  • When to Use: For a UI to inspect logs without querying the database.
  • How It Works: Enable in .env:
    SPY_DASHBOARD_ENABLED=true
    SPY_DASHBOARD_MIDDLEWARE=auth
    
  • Access: Visit /spy (protected by the middleware specified).

6. Log Cleanup

  • When to Use: To manage database bloat from retained logs.
  • How It Works: Run manually or schedule via Laravel:
    php artisan spy:clean
    
  • Automate: Add to app/Console/Kernel.php:
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('spy:clean')->daily();
    }
    

Integration Tips

With Laravel Jobs/Queues

  • Logs are stored synchronously. For high-volume jobs, consider:
    // Dispatch a job to log asynchronously
    Spy::log($request, $response); // Custom event or queue
    
  • Or use the spy:log queue job (if extended).

With Testing

  • Mocking Logs: Use Laravel’s database testing helpers:
    $this->assertDatabaseHas('http_logs', [
        'url' => 'https://api.example.com/data',
    ]);
    
  • Pest Example:
    use Farayaz\LaravelSpy\Facades\Spy;
    
    Spy::shouldReceive('log')->once();
    Http::fake();
    Http::get('https://example.com');
    

With Third-Party APIs

  • Rate Limiting: Use SPY_FIELD_MAX_LENGTH to truncate large responses:
    SPY_FIELD_MAX_LENGTH=5000
    
  • Webhooks: Exclude webhook URLs to reduce noise:
    SPY_EXCLUDE_URLS=*.webhook.example.com
    

With Monolog

  • Custom Logging: Extend the package to log to Monolog:
    // In a service provider
    Spy::extend(function ($app) {
        return new class {
            public function log($request, $response) {
                Log::channel('spy')->info('HTTP Spy', [
                    'request' => $request->toArray(),
                    'response' => $response->toArray(),
                ]);
            }
        };
    });
    

Gotchas and Tips

Pitfalls

1. Guzzle Client Scope

  • Issue: Auto-mode only works for Guzzle clients resolved via Laravel’s service container. Standalone clients (e.g., new \GuzzleHttp\Client()) require manual middleware attachment.
  • Fix: Use manual mode or ensure all clients are container-bound:
    $client = app(\GuzzleHttp\Client::class);
    

2. Large Payloads

  • Issue: Logging large request/response bodies (e.g., file uploads, binary data) can bloat the database or cause timeouts.
  • Fix:
    • Set SPY_FIELD_MAX_LENGTH to truncate fields:
      SPY_FIELD_MAX_LENGTH=2048
      
    • Exclude binary endpoints:
      SPY_EXCLUDE_URLS=*.example.com/upload
      

3. Middleware Order

  • Issue: If other Guzzle middleware (e.g., retry, auth) runs after SpyMiddleware, logs may show incorrect headers/body.
  • Fix: Ensure SpyMiddleware runs first:
    $client->getConfig('middleware')->unshift(
        new SpyMiddleware()
    );
    

4. Database Locks

  • Issue: High-frequency logging (e.g., >1000 RPS) may cause database contention.
  • Fix:
    • Batch inserts or use a queue:
      Spy::queueLog($request, $response); // Hypothetical queue method
      
    • Partition the http_logs table by date.

5. Obfuscation Overhead

  • Issue: Complex obfuscation rules (e.g., regex) may slow down logging.
  • Fix: Test performance with your rule set and simplify if needed.

6. Dashboard Permissions

  • Issue: The dashboard may expose sensitive data if not properly secured.
  • Fix: Restrict access via middleware:
    SPY_DASHBOARD_MIDDLEWARE=auth:admin
    

Debugging Tips

Verify Logging

  • Check if logs are being written:
    php artisan tinker
    >>> \Farayaz\LaravelSpy\Facades\Spy::logs()->count();
    
  • Inspect raw logs:
    php artisan tinker
    >>> \Farayaz\LaravelSpy\Models\HttpLog::latest()->first()->toArray();
    

Enable Debug Mode

  • Add to .env for verbose output:
    SPY_DEBUG=true
    
  • Check Laravel logs for spy-related errors:
    tail -f storage/logs/laravel.log | grep spy
    

Common Errors

  • Class not found: Ensure the package is auto-discovered or manually register the service provider.
  • Migration fails: Run composer dump-autoload if the http_logs table isn’t created.
  • Guzzle not intercepted: Confirm the client is container-bound or manually attach middleware.

Extension Points

Custom Logging

  • Extend the HttpLog model to add custom fields:
    // app/Models/HttpLog.php
    protected $casts = [
        'custom_field' => 'json',
    ];
    
  • Add a custom column to the migration:
    Schema::table('http_logs', function (
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope