quetzal-studio/request-logger

Request logger for laravel

Maintainers

Package info

github.com/kangata/request-logger

pkg:composer/quetzal-studio/request-logger

Transparency log

Statistics

Installs: 298

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.0.14 2026-07-31 11:46 UTC

This package is auto-updated.

Last update: 2026-07-31 11:48:30 UTC


README

Request logger for Laravel. Logs incoming requests (and outgoing Guzzle/HTTP client requests) with their responses to a dedicated log channel, with configurable masking for sensitive fields.

Requirements

Version
PHP 7.4 – 8.5
Laravel 6.x – 13.x

Install package

composer require quetzal-studio/request-logger

Publish config file

php artisan vendor:publish --tag=request-logger-config

Using middleware

Laravel 6 – 9

// app/Http/Kernel.php
protected $routeMiddleware = [
    // ...
    'request.logger' => \QuetzalStudio\RequestLogger\Http\Middleware\RequestLogger::class,
];

Laravel 10

// app/Http/Kernel.php
protected $middlewareAliases = [
    // ...
    'request.logger' => \QuetzalStudio\RequestLogger\Http\Middleware\RequestLogger::class,
];

Laravel 11 – 13

// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'request.logger' => \QuetzalStudio\RequestLogger\Http\Middleware\RequestLogger::class,
    ]);
})

Then attach it to routes:

Route::post('/payment', PaymentController::class)->middleware('request.logger');

// Or with a custom log channel
Route::post('/payment', PaymentController::class)->middleware('request.logger:payment');

Logging runs in the middleware's terminate() method, after the response has been sent to the client, so it does not add to response time.

Log channel

By default logs are written to the request channel. If that channel is not defined in config/logging.php, a daily driver writing to storage/logs/request/request.log (14 days retention) is created automatically. Change the default channel via request_logger.log.channel or per route with the middleware parameter.

Message-only logging

By default every entry includes the full request/response context. To log only the message line ({http_method} {url} {http_status}) without the request and response payloads, set the config globally:

'log' => [
    'channel' => 'request',
    'context' => false,
],

Or per call with withoutContext():

(new RequestLogger)
    ->request($request)
    ->response($response)
    ->withoutContext()
    ->create(); // logs "POST https://example.com/api/payment 200" with no context

Masking

Keys listed in the masking config are replaced before logging. A plain key is fully masked with ********:

'masking' => [
    'request' => [
        'body' => [
            'password',
            'password_confirmation',
            'client_secret',
        ],
        'headers' => [
            'authorization',
        ],
    ],
    'response' => [
        'body' => [
            'access_token',
            'refresh_token',
        ],
    ],
],

Keys support dot notation for nested values (e.g. user.password).

Partial masking

For PII fields you need to trace in the logs (which email/phone/account a request was about), use the mask option to keep part of the value visible:

'body' => [
    'password',                                          // ********
    'email' => ['mask' => 'email'],                      // jo****@example.com
    'phone' => ['mask' => ['show_last' => 4]],           // ********7890
    'account_number' => ['mask' => ['show_last' => 4]],  // ******3456
    'name' => ['mask' => ['show_first' => 2]],           // Jo******
],
  • show_last / show_first are capped at 4 characters, even if you configure more.
  • Values too short to mask meaningfully (fewer than 4 hidden characters left) fall back to the full ******** mask.
  • Keep secrets (password, client_secret, authorization, tokens) fully masked — partial masking is meant for identifiers, not credentials.

Mask only on specific URLs

'body' => [
    'client_secret' => ['only' => ['oauth/token']],
    'phone' => ['only' => ['api/v1/users'], 'mask' => ['show_last' => 4]],
],

The key is masked only when the request URL matches one of the patterns.

Log a custom message

The logger can also be used directly, without request/response context:

use QuetzalStudio\RequestLogger\RequestLogger;

(new RequestLogger)->create('Payment callback received');

(new RequestLogger)->channel('audit')->create('Manual sync triggered');

You can attach only a request, only a response, or both — whatever is set is included in the log context (with masking applied):

(new RequestLogger)
    ->request($request)   // Illuminate\Http\Request or GuzzleHttp\Psr7\Request
    ->response($response) // Illuminate\Http\Client\Response or Symfony Response
    ->create();           // message defaults to "METHOD url STATUS"