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

Logger Plugin Laravel Package

php-http/logger-plugin

PSR-3 logger plugin for HTTPlug (php-http). Logs HTTP requests/responses made through your HTTPlug client, helping you debug and monitor outgoing traffic. Install via Composer and configure with your preferred PSR-3 logger implementation.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install Dependencies

    composer require php-http/logger-plugin
    

    (Laravel already includes Monolog and Guzzle, so only logger-plugin may be needed.)

  2. Basic Setup in Laravel (Updated for 1.5.0)

    use Http\Client\Common\PluginClient;
    use Http\Client\Plugin\LoggerPlugin;
    use Illuminate\Support\Facades\Log;
    
    // Create a Guzzle client (Laravel's Http::client() uses Guzzle under the hood)
    $guzzleClient = new \GuzzleHttp\Client();
    
    // Wrap with HTTPlug adapter and logger plugin (1.5.0 now includes URI in log context by default)
    $adapter = new \Http\Adapter\Guzzle6Adapter($guzzleClient);
    $loggerPlugin = new LoggerPlugin(Log::channel('single'), LoggerPlugin::FORMAT_DEBUG);
    $client = new PluginClient($adapter, [$loggerPlugin]);
    
  3. First Use Case: Log an API Call (Now Includes URI)

    $request = new \GuzzleHttp\Psr7\Request('GET', 'https://api.example.com/data');
    $response = $client->sendRequest($request);
    

    Output: Logs will now automatically include the request URI in the log context:

    [2023-10-01 12:00:00] local.DEBUG: Request URI: https://api.example.com/data | Method: GET | Status: 200
    

Implementation Patterns

1. Laravel-Specific Integration (Updated for 1.5.0)

Wrap Laravel’s HTTP Client

Leverage Laravel’s Http::client() with HTTPlug (URI is now logged by default):

use Http\Client\Common\PluginClient;
use Http\Adapter\Guzzle6Adapter;

$guzzleClient = new \GuzzleHttp\Client();
$adapter = new Guzzle6Adapter($guzzleClient);
$loggerPlugin = new LoggerPlugin(Log::channel('stack'), LoggerPlugin::FORMAT_TIDY);

// Bind to Laravel container (optional)
app()->bind('httplug.logger.client', function () use ($adapter, $loggerPlugin) {
    return new PluginClient($adapter, [$loggerPlugin]);
});

Use in Services (URI now auto-included)

public function fetchData()
{
    $client = app('httplug.logger.client');
    $response = $client->sendRequest(new \GuzzleHttp\Psr7\Request('GET', 'https://api.example.com'));
    return json_decode($response->getBody(), true);
}

Log Output:

[2023-10-01 12:00:00] local.DEBUG: Request URI: https://api.example.com | Method: GET | Status: 200

2. Conditional Logging (URI now part of context)

Log Only Errors (URI included in filtered logs)

$loggerPlugin = new LoggerPlugin(Log::channel('single'), LoggerPlugin::FORMAT_DEBUG);
$client = new PluginClient($adapter, [$loggerPlugin]);

// Override handleRequest to filter logs (URI is now part of $context)
$filteredClient = new class($client) implements \Http\Client\Plugin {
    public function __construct(private $client) {}
    public function handleRequest($request, $next, \Http\Promise\PromiseInterface $promise) {
        return $next($request)->then(
            function ($response) {
                if ($response->getStatusCode() >= 400) {
                    $this->client->getPlugin(LoggerPlugin::class)
                        ->logRequest($request, $response);
                    // URI is now automatically logged via LoggerPlugin
                }
                return $response;
            }
        );
    }
};

Log by Route (URI now auto-captured)

$loggerPlugin = new LoggerPlugin(Log::channel('single'), LoggerPlugin::FORMAT_TIDY);
$client = new PluginClient($adapter, [$loggerPlugin]);

// Middleware to log specific routes (URI is now part of $request)
$client->addPlugin(new class implements \Http\Client\Plugin {
    public function handleRequest($request, $next, \Http\Promise\PromiseInterface $promise) {
        if (str_contains($request->getUri(), 'critical-api')) {
            return $next($request)->then(
                function ($response) use ($request) {
                    Log::debug('Critical API call', [
                        'uri' => $request->getUri(), // URI now auto-included
                        'status' => $response->getStatusCode(),
                    ]);
                    return $response;
                }
            );
        }
        return $next($request);
    }
});

3. Structured Logging with Monolog (URI now part of default context)

Add Context to Logs (URI now auto-included)

Log::channel('single')->pushProcessor(function ($record) {
    $record['extra']['user_id'] = auth()->id();
    $record['extra']['request_id'] = request()->header('X-Request-ID');
    $record['extra']['request_uri'] = $record['context']['request']['uri'] ?? null; // URI now auto-captured
    return $record;
});

Custom Log Format (URI now part of default output)

$loggerPlugin = new LoggerPlugin(Log::channel('single'), function ($message, array $context) {
    return sprintf(
        "[HTTP] %s | URI: %s | Method: %s | Status: %s",
        $context['timestamp'] ?? now()->toIso8601String(),
        $context['request']['uri'] ?? 'UNKNOWN', // URI now auto-included
        $context['request']['method'] ?? 'UNKNOWN',
        $context['response']['status'] ?? 'UNKNOWN'
    );
});

4. Masking Sensitive Data (URI unaffected)

Filter Request/Response Bodies (URI remains visible)

$loggerPlugin = new LoggerPlugin(Log::channel('single'), LoggerPlugin::FORMAT_DEBUG);
$loggerPlugin->setMasking(function ($body) {
    return preg_replace('/"password":"[^"]+"/', '"password":"[FILTERED]"', $body);
});

Note: The URI is not masked and remains visible in logs.


Gotchas and Tips

Pitfalls

  1. Double Logging (URI now part of context)

    • Issue: If Laravel’s default logging and LoggerPlugin both log HTTP calls, logs may duplicate including URIs.
    • Fix: Disable Laravel’s default logging for HTTP clients or use a single logger channel.
      // Disable Laravel's default HTTP logging middleware if present
      
  2. Performance Bottlenecks (URI now auto-logged)

    • Issue: Logging large request/response bodies (e.g., file uploads) can slow down requests, even with URIs included.
    • Fix: Disable body logging or limit log size.
      $loggerPlugin = new LoggerPlugin(Log::channel('single'), false); // Disable body logging (URI still logged)
      
  3. Circular Dependencies (URI now part of request context)

    • Issue: Logging a request that triggers another HTTP call (e.g., retries) may cause infinite loops, now including URI in logs.
    • Fix: Use a request ID to deduplicate logs.
      $loggerPlugin->setRequestIdGenerator(function () {
          return uniqid('http_', true);
      });
      
  4. Logger Plugin Not Triggering (URI now auto-included)

    • Issue: Logs aren’t appearing despite correct setup.
    • Debug Steps:
      1. Verify the logger channel is configured (e.g., Log::channel('single') exists).
      2. Check Monolog handlers are active (e.g., storage/logs/laravel.log permissions).
      3. Ensure the plugin is the first in the chain (plugins execute in order).
      4. Test with LoggerPlugin::FORMAT_DEBUG for verbose output (URI now auto-included).

Debugging Tips (URI now part of logs)

  1. Log Plugin Execution (URI now visible) Add debug logs to the plugin itself:

    $loggerPlugin = new LoggerPlugin(Log::channel('single'), LoggerPlugin::FORMAT_DEBUG);
    $loggerPlugin->setLogger(new class(Log::channel('single')) implements \Psr\Log\LoggerInterface {
        public function debug($message, array $context = []) {
            Log::debug("[LoggerPlugin] $message | URI: " . ($context['request']['uri'] ?? 'N/A'), $context);
            $this->logger->debug($message, $context);
        }
        // Implement other PSR-3 methods...
    });
    
  2. Inspect HTTPlug Client (URI now part of context) Dump the client’s plugins to verify the logger is attached:

    dd($client->getPlugins()); // Should include LoggerPlugin (URI now auto-logged)
    
  3. Check Guzzle Middleware (URI now auto-captured)

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.
anousss007/vigilance
supportpal/eloquent-model
ardenexal/fhir-models
laravel-at/laravel-image-sanitize
romalytar/yammi-audit-log-laravel
ardenexal/fhir-validation
arshaviras/weather-widget
laravel-chronicle/core
sunchayn/nimbus
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope
nawasara/auth-primitives
adhocrat-io/arkhe-main
make-dev/orca-harpoon