freightseeker/http-logger

Configurable outbound HTTP request logger for Laravel and Guzzle.

Maintainers

Package info

github.com/freightseeker/http-logger

pkg:composer/freightseeker/http-logger

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.2.2 2026-04-18 14:37 UTC

This package is auto-updated.

Last update: 2026-04-18 14:38:50 UTC


README

A robust, highly configurable outbound HTTP request logger designed specifically for Laravel applications and Guzzle HTTP clients.

This package allows you to automatically monitor and store outbound API requests made by your application, providing full visibility into third-party integrations, webhook deliveries, and external service calls.

Key Features

  • Store Options: Output logs securely to your SQL database (default) or redirect them to a structured Laravel log file based on configuration.
  • Automatic Laravel Integration: Seamlessly attaches to Laravel's HTTP Client (Illuminate\Support\Facades\Http).
  • Native Guzzle Support: Includes middleware for easily logging raw Guzzle requests.
  • Advanced Redaction & Security: Automatically redacts sensitive headers (e.g., API keys, Authorization tokens) and recursively scrubs sensitive JSON payload keys before persisting to the database.
  • Filtering & Truncation: Configure maximum payload sizes to preserve database space, and strictly control which requests should be logged.
  • Eloquent Polymorphism: Tie HTTP requests directly to Eloquent models using the withLoggable() macro and HasHttpLogs trait.
  • Manual Logging Support: Use the HttpLogger facade to record logs from custom auto-generated SDKs or vanilla cURL scripts.

Requirements

  • PHP 8.3+
  • Laravel 11.0 / 12.0 / 13.0

Installation

You can install the package via composer:

composer require freightseeker/http-logger

Laravel Projects

You can publish and run the migrations with:

php artisan vendor:publish --tag="http-logger-migrations"
php artisan migrate

You can publish the config file with:

php artisan vendor:publish --tag="http-logger-config"

Non-Laravel Projects

If you are using this package in a standalone PHP application (without the Laravel framework), you will need to manually handle the database schema or inject a custom HttpLogWriter into the HttpLogger.

If you choose to use the built-in database writer (which depends on illuminate/database), you must manually run this equivalent raw SQL to create the http_logs table:

CREATE TABLE `http_logs` (
  `id` CHAR(26) NOT NULL,
  `direction` VARCHAR(10) NOT NULL,
  `driver` VARCHAR(20) NOT NULL,
  `url` TEXT NOT NULL,
  `method` VARCHAR(10) NOT NULL,
  `request_headers` JSON NULL,
  `request_body` LONGTEXT NULL,
  `response_status` INT NULL,
  `response_headers` JSON NULL,
  `response_body` LONGTEXT NULL,
  `duration_ms` INT UNSIGNED NOT NULL,
  `error_message` TEXT NULL,
  `loggable_type` VARCHAR(255) NULL,
  `loggable_id` CHAR(26) NULL,
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  INDEX `http_logs_loggable_type_loggable_id_created_at_index` (`loggable_type`, `loggable_id`, `created_at`)
);

To entirely bypass illuminate/database, you can implement the HttpLogWriter interface and store your logs using raw PDO, Monolog, or any other solution:

use HttpLogger\Contracts\HttpLogWriter;
use HttpLogger\HttpLogEntry;

class MyPdoWriter implements HttpLogWriter
{
    public function write(HttpLogEntry $entry): void
    {
        // Insert $entry data using raw PDO...
    }
}

Usage

Laravel Integration

Laravel HTTP Client

The package automatically integrates with the Laravel HTTP Client. You don't need any additional setup.

use Illuminate\Support\Facades\Http;

$response = Http::withHeaders(['X-First' => 'foo'])
    ->get('https://api.github.com/users/octocat');

// The request and response are now automatically stored in the database.

Polymorphic Relations

You can associate HTTP request logs with your Eloquent models using polymorphic relations. This is useful for tracking which requests belong to a specific record, such as a user, order, or shipment.

When using the Laravel HTTP Client, you can use the built-in macro to attach a model to the request:

use Illuminate\Support\Facades\Http;

$order = Order::find(1);

Http::withLoggable($order)
    ->post('https://api.example.com/orders/sync', $order->toArray());

Note: withLoggable() stores the model in a per-process singleton and is designed for sequential requests. When using Http::pool() with multiple concurrent requests, only the most recently set loggable will be attached. For concurrent use-cases, construct an HttpLogEntry directly with the desired loggable and call HttpLogger::record() manually.

To easily retrieve the associated logs, add the provided trait (or manually define the morphMany relationship) on your Eloquent model:

use Illuminate\Database\Eloquent\Model;
use HttpLogger\Laravel\Concerns\HasHttpLogs;

class Order extends Model
{
    use HasHttpLogs;
}

Now you can access the previous HTTP request logs directly from your model instance:

$logs = $order->httpLogs;

Guzzle HTTP Client

Automatic Logging (Recommended)

The package provides a LoggingGuzzleClient wrapper that handles all logging automatically. It is registered as a singleton in the Laravel service container and can be injected directly via the constructor:

use HttpLogger\Guzzle\LoggingGuzzleClient;

class GitHubService
{
    public function __construct(private readonly LoggingGuzzleClient $http) {}

    public function getUser(string $username): array
    {
        $response = $this->http->get("https://api.github.com/users/{$username}");

        // The request and response are automatically logged.
        return json_decode((string) $response->getBody(), true);
    }
}

You can associate requests with an Eloquent model using withLoggable(), mirroring the Laravel HTTP Client behavior:

$response = $this->http
    ->withLoggable($order)
    ->post('https://api.example.com/orders/sync', ['json' => $order->toArray()]);

Note: withLoggable() is designed for sequential requests. The loggable is consumed (reset to null) after the next request is dispatched.

To pass custom Guzzle config options (e.g. base_uri, timeout), resolve the client manually with LoggingGuzzleClient::make():

use HttpLogger\Guzzle\LoggingGuzzleClient;
use HttpLogger\HttpLogger;

$client = LoggingGuzzleClient::make(app(HttpLogger::class), [
    'base_uri' => 'https://api.example.com',
    'timeout'  => 10,
]);

Manual Middleware

If you need to attach logging to an existing Guzzle HandlerStack (e.g. wrapping a third-party SDK), push the middleware directly:

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use HttpLogger\Guzzle\HttpLoggerMiddleware;
use HttpLogger\HttpLogger;

$stack = HandlerStack::create();
$stack->push(HttpLoggerMiddleware::make(app(HttpLogger::class)));

$client = new Client(['handler' => $stack]);

$client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');

Manual Logging

If you need to log requests made outside of Laravel's HTTP Client or Guzzle (for example, raw cURL requests or third-party SDKs), you can easily record entries using the built-in timer and the HttpLogger::log() helper method.

The log() method safely swallows all exceptions, guaranteeing that logging will never halt your application execution.

use HttpLogger\HttpDirection;
use HttpLogger\Laravel\Facades\HttpLogger;

// 1. Start the internal logger timer — returns a Closure that yields elapsed ms when called
$timer = HttpLogger::startTimer();

// 2. Perform your manual request/interaction...
$response = $customSdk->syncData(['foo' => 'bar']);

// 3. Log the execution using the timer Closure
HttpLogger::log(
    direction: HttpDirection::Outbound,
    driver: 'custom-sdk',
    url: 'https://api.example.com/sync',
    method: 'POST',
    requestHeaders: ['Content-Type' => 'application/json'],
    requestBody: json_encode(['data' => 'sync-me']),
    responseStatus: 200,
    responseHeaders: ['Content-Type' => 'application/json'],
    responseBody: json_encode(['status' => 'success']),
    timer: $timer, // Automagically resolves the request duration
    errorMessage: null, // Populate if your manual implementation encountered an error
);

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Releasing

Please see RELEASING for instructions on how to cut a new release.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

License

The MIT License (MIT). Please see License File for more information.