spatie/laravel-http-logger

repository·main·Indexed 20 days ago

https://github.com/spatie/laravel-http-logger

A Laravel package providing middleware to log incoming HTTP requests. It includes features for sanitizing sensitive headers and body fields, and utilizes LogProfile and LogWriter abstractions to determine which requests to log and how to write them. By default, it uses LogNonGetRequests to log only POST, PUT, PATCH, DELETE, and QUERY requests.

Tokens
2.7K
Snippets
9
Records
10
Agent score
70%

What's inside spatie/laravel-http-logger

  1. How LogProfile and LogWriter work together

    main

    The package uses two main abstractions to handle logging:

    1. LogProfile: Determines if a request should be logged. You must implement the shouldLogRequest(Request $request): bool method. The default implementation (LogNonGetRequests) only logs POST, PUT, PATCH, DELETE, and QUERY requests.

    2. LogWriter: Determines how the request is written. You must implement the logRequest(Request $request): void method. The default implementation (DefaultLogWriter) writes the method, URI, and body (excluding fields in the except config) to the configured Laravel log channel.

    You can swap these out in config/http-logger.php to implement custom logic.

    // Example LogProfile implementation
    public function shouldLogRequest(Request $request): bool
    {
       return in_array(strtolower($request->method()), ['post', 'put', 'patch', 'delete', 'query']);
    }
    
    // Example LogWriter implementation
    public function logRequest(Request $request): void
    {
        $method = strtoupper($request->getMethod());
        $uri = $request->getPathInfo();
        $bodyAsJson = json_encode($request->except(config('http-logger.except')));
        $message = "{$method} {$uri} - {$bodyAsJson}";
    
        Log::channel(config('http-logger.log_channel'))->info($message);
    }
  2. Sanitize sensitive headers in logs

    main

    To prevent sensitive information like JWT tokens or cookies from being written to your logs, add the header names to the sanitize_headers array in config/http-logger.php. When a header is sanitized, its value will be replaced with "****" in the log output.

    // in config/http-logger.php
    
    return [
        // ...
        
        'sanitize_headers' => [
            'Authorization'
        ],
    ];
  3. Register the HttpLogger middleware

    main

    You can apply the \Spatie\HttpLogger\Middlewares\HttpLogger::class middleware globally, or to specific routes.

    For Laravel 11+ (Global): Add it to your bootstrap/app.php file.

    For Laravel <= 10 (Global): Add it to the $middleware array in app/Http/Kernel.php.

    For a single route: Apply it directly to the route definition.

    // Laravel >= 11 Global Middleware
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->append(\Spatie\HttpLogger\Middlewares\HttpLogger::class);
    })
    
    // Laravel <= 10 Global Middleware (app/Http/Kernel.php)
    protected $middleware = [
        // ...
        \Spatie\HttpLogger\Middlewares\HttpLogger::class
    ];
    
    // Single Route Usage
    Route::post('/submit-form', function () {
        //
    })->middleware(\Spatie\HttpLogger\Middlewares\HttpLogger::class);
  4. Configure the http-logger settings

    main

    The configuration file config/http-logger.php allows you to control how requests are logged. Key options include:

    • enabled: Boolean to toggle the middleware (controlled via HTTP_LOGGER_ENABLED env var).
    • log_profile: A class implementing LogProfile that decides if a request should be logged.
    • log_writer: A class implementing LogWriter that handles the actual writing of the log.
    • log_channel: The Laravel log channel to use (e.g., stack).
    • log_level: The log level (e.g., info).
    • except: An array of body fields to exclude from logs (e.g., password).
    • sanitize_headers: An array of header names to be masked in the logs.
    return [
    
        /*
         * Determine if the http-logger middleware should be enabled.
         */
        'enabled' => env('HTTP_LOGGER_ENABLED', true),
    
        /*
         * The log profile which determines whether a request should be logged.
         * It should implement `LogProfile`.
         */
        'log_profile' => \Spatie\HttpLogger\LogNonGetRequests::class,
    
        /*
         * The log writer used to write the request to a log.
         * It should implement `LogWriter`.
         */
        'log_writer' => \Spatie\HttpLogger\DefaultLogWriter::class,
        
        /*
         * The log channel used to write the request.
         */
        'log_channel' => env('LOG_CHANNEL', 'stack'),
        
        /*
         * The log level used to log the request.
         */
        'log_level' => 'info',
        
        /*
         * Filter out body fields which will never be logged.
         */
        'except' => [
            'password',
            'password_confirmation',
        ],
        
        /*
         * List of headers that will be sanitized. For example Authorization, Cookie, Set-Cookie...
         */
        'sanitize_headers' => [],
    ];
  5. Configure LogProfile and LogWriter via config

    main

    The package uses Laravel's service container to bind LogProfile and LogWriter as singletons based on your configuration. You can swap the implementations by updating the following keys in config/http-logger.php:

    • log_profile: The class name for the LogProfile implementation.
    • log_writer: The class name for the LogWriter implementation.
  6. Sanitize sensitive data with the Sanitizer class

    main

    The Sanitizer class is used to mask sensitive information within request data (like passwords or API keys) before it is logged. It works by recursively traversing an array and replacing values associated with specified keys with a mask string.

    Key Methods:

    • clean(array $input, $keys): Recursively scans the $input array. If a key matches any of the provided $keys (case-insensitive), its value is replaced by the mask. If the value is an array, it is replaced by an array containing the mask.
    • setMask(string $mask): Updates the string used to replace sensitive values.
    • normalize(string $string): A helper method used to normalize keys (defaults to strtolower). You can override this to change how keys are matched.
    use Spatie\HttpLogger\Sanitizer;
    
    $sanitizer = new Sanitizer('REDACTED');
    
    $data = [
        'user' => [
            'name' => 'John Doe',
            'password' => 'secret123',
        ],
        'api_key' => 'abc-123',
    ];
    
    $cleanData = $sanitizer->clean($data, ['password', 'api_key']);
    
    // Result:
    // [
    //     'user' => [
    //         'name' => 'John Doe',
    //         'password' => 'REDACTED',
    //     ],
    //     'api_key' => 'REDACTED',
    // ]
  7. Use the LogNonGetRequests profile to filter requests

    main

    The LogNonGetRequests class is a predefined LogProfile implementation. When used as a logging profile, it ensures that only non-GET requests are logged.

    It follows these rules:

    1. It checks if the package is enabled via the http-logger.enabled configuration key.
    2. It only returns true for requests using the following HTTP methods: POST, PUT, PATCH, DELETE, or QUERY (case-insensitive).

    This is useful for reducing log noise by ignoring standard GET requests and focusing on state-changing operations.

    use Spatie\HttpLogger\LogNonGetRequests;
    
    // This profile can be used when configuring your HTTP logger
    // to only capture mutating requests.
  8. Use the HttpLogger middleware to intercept requests

    main

    The Spatie\HttpLogger\Middlewares\HttpLogger class is a Laravel middleware designed to intercept incoming HTTP requests and log them. It relies on two injected dependencies:

    1. LogProfile: Determines whether a specific request meets the criteria to be logged via the shouldLogRequest method.
    2. LogWriter: Handles the actual writing of the request data via the logRequest method.

    To use this, you must register it in your application's middleware stack (e.g., in app/Http/Kernel.php or via your application's routing configuration) so that it can intercept the Illuminate\Http\Request objects.

    namespace Spatie\HttpLogger\Middlewares;
    
    use Closure;
    use Illuminate\Http\Request;
    
    class HttpLogger
    {
        public function handle(Request $request, Closure $next)
        {
            // ... logic to check LogProfile and call LogWriter
            return $next($request);
        }
    }