GithubHelp home page GithubHelp logo

spatie / laravel-http-logger Goto Github PK

View Code? Open in Web Editor NEW
633.0 10.0 58.0 117 KB

Log HTTP requests in Laravel applications

Home Page: https://freek.dev/882-a-laravel-package-to-log-http-requests

License: MIT License

PHP 100.00%
laravel php http logging

laravel-http-logger's Introduction

Log HTTP requests

Latest Version on Packagist run-tests Total Downloads

This package adds a middleware which can log incoming requests to the default log. If anything goes wrong during a user's request, you'll still be able to access the original request data sent by that user.

This log acts as an extra safety net for critical user submissions, such as forms that generate leads.

Support us

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Installation

You can install the package via composer:

composer require spatie/laravel-http-logger

Optionally you can publish the config file with:

php artisan vendor:publish --provider="Spatie\HttpLogger\HttpLoggerServiceProvider" --tag="config" 

This is the contents of the published config file:

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' => [],
];

Usage

This packages provides a middleware which can be added as a global middleware or as a single route.

Laravel >= 11:

->withMiddleware(function (Middleware $middleware) {
    $middleware->append(\Spatie\HttpLogger\Middlewares\HttpLogger::class);
})

Laravel <= 10:

// in `app/Http/Kernel.php`

protected $middleware = [
    // ...
    
    \Spatie\HttpLogger\Middlewares\HttpLogger::class
];
// in a routes file

Route::post('/submit-form', function () {
    //
})->middleware(\Spatie\HttpLogger\Middlewares\HttpLogger::class);

Logging

Two classes are used to handle the logging of incoming requests: a LogProfile class will determine whether the request should be logged, and LogWriter class will write the request to a log.

A default log implementation is added within this package. It will only log POST, PUT, PATCH, and DELETE requests and it will write to the default Laravel logger. Logging is enabled by default but can be toggled on or off via the HTTP_LOGGER_ENABLED variable in the .env file.

You're free to implement your own log profile and/or log writer classes, and configure it in config/http-logger.php.

A custom log profile must implement \Spatie\HttpLogger\LogProfile. This interface requires you to implement shouldLogRequest.

// Example implementation from `\Spatie\HttpLogger\LogNonGetRequests`

public function shouldLogRequest(Request $request): bool
{
   return in_array(strtolower($request->method()), ['post', 'put', 'patch', 'delete']);
}

A custom log writer must implement \Spatie\HttpLogger\LogWriter. This interface requires you to implement logRequest.

// Example implementation from `\Spatie\HttpLogger\DefaultLogWriter`

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);
}

Hide sensitive headers

You can define headers that you want to sanitize before sending them to the log. The most common example would be Authorization header. If you don't want to log jwt token, you can add that header to http-logger.php config file:

// in config/http-logger.php

return [
    // ...
    
    'sanitize_headers' => [
        'Authorization'
    ],
];

Output would be Authorization: "****" instead of Authorization: "Bearer {token}"

Testing

composer test

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you've found a bug regarding security please mail [email protected] instead of using the issue tracker.

Credits

License

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

laravel-http-logger's People

Contributors

adrianmrn avatar angeljqv avatar ayoobmh avatar brendt avatar dongido001 avatar freekmurze avatar kudashevs avatar laravel-shift avatar lsmith77 avatar marcell-ferenc avatar nielsvanpach avatar okipa avatar patinthehat avatar pdewit avatar rogervila avatar rubenvanassche avatar sebastiandedeyne avatar sebastianschoeps avatar serderovsh avatar stfndamjanovic avatar timvandijck avatar tvbeek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-http-logger's Issues

Error when using file input array Laravel 5.5

File Input

{
    "message": "Type error: Argument 1 passed to Spatie\\HttpLogger\\DefaultLogWriter::Spatie\\HttpLogger\\{closure}() must be an instance of Symfony\\Component\\HttpFoundation\\File\\UploadedFile, array given",
    "status_code": 500
}

Any idea how to fix this?

Thanks

File support

Currently, only the request method, path and body are written to the log. Files should probably also be mentioned.

issue during install package

when I used composer require to install package .. it returns

Could not find package spatie/laravel-http-logger at any version matching your PHP version 5.6.25.0

Add blank line before end of array in config file

Given that the array in the config file begins with a blank line, I wonder if it's reasonable for the array to end with a blank line as well. I navigated through another projects from Spatie and they have a blank line before the closing brackets.

Initial implementation

We want a middleware that dumps request payloads to the default log. If there's a bug on a site, we at least will always have the users' submissions. This is critical for websites that have a contact form meant to generate leads.

The package will provide a middleware which users can register in a middleware stack or as route middleware.

Two important configurable features:

  • We need a way to determine which requests we want to log. Our spatie/laravel-responsecache package does this elegantly by passing a class to in the configuration that determines wether a request should be cached. It might also be nice to define a method that pulls out the attributes that should be logged, so users have full control there too
  • The config file should also have a blacklist array for attributes we never want to log. By default: ['password', 'password_confirmation'], like Laravel's TrimStrings middleware

The config file could look like this:

return [
    'log_profile' => Spatie\HttpLogger\DefaultLogger::class,
    
    'except' => [
        'password',
        'password_confirmation',
    ],
];

Update to Laravel 11

The documentation is not updated to Laravel 11, middleware configuration.
and I dont seem to get it to work,
Added the middleware to the bootstrap app.php like this
`
->withMiddleware(function (Middleware $middleware) {

    $middleware->append(\Spatie\HttpLogger\Middlewares\HttpLogger::class);
})

`
but no log generated in the expected storage/logs directory
thnx

why no get request?

public function shouldLogRequest(Request $request): bool { return in_array(strtolower($request->method()), ['post', 'put', 'patch', 'delete']); }

Hook into kernel terminate

Hi there!

Did you ever consider adjusting the middleware to hook into kernel terminate?
That way, the logging won't affect the performance of the request (and the response is available to log).

After type middleware

Could the after type middleware be added in package, that logs responses which has status code other than 200?

Response logger

Hi,

Thanks for the great package!

I have a requirement to log the response as well and I am happy to submit a PR, but, would like some feedback from the community:

  1. Should I modify the existing middleware to also log the response (perhaps controlled via a flag)?
  2. Should I be reusing some of the configs such as 'except' or new ones will make sense?

Response code whitelist/blacklist

It would be great if there was a configurable feature where only requests with certain response codes could be excluded or excluded. This would greatly reduce the amount of noise in the logs for people who don't have a special searchable log system setup.

For example, being able to exclude 200 responses. Or include only 400 or 500 errors.

I could probably submit a PR if there was any interest.

split up DefaultLogWriter::logRequest()

Would you be open a to a PR to split this method by extracting a protected method “getMessage()” that basically does everything except for the call to Log::info()? This would make it feasible to extend the class in case one wants to store the data else where, f.e. in a DB. Potentially there should even be another “formatMessage()” method and “getMessage()” just provides an array of data. what do you think?

https://github.com/spatie/laravel-http-logger/blob/master/src/DefaultLogWriter.php#L12

can't log api route

hi, using this with laravel spark, but it seem like no way to log the api route ?

Better log output

Currently, the log output is just a single line. There might be a better format.

Opinions are welcome.

Target [Spatie\HttpLogger\LogProfile] is not instantiable ..

I am only getting this error on prod, not local:

[2021-01-02 20:13:03] production.ERROR: Target [Spatie\HttpLogger\LogProfile] is not instantiable while building [Spatie\HttpLogger\Middlewares\HttpLogger]. {"userId":2,"exception":"[object] (Illuminate\\Contracts\\Container\\BindingResolutionException(code: 0): Target [Spatie\\HttpLogger\\LogProfile] is not instantiable while building [Spatie\\HttpLogger\\Middlewares\\HttpLogger]. at /app/vendor/laravel/framework/src/Illuminate/Container/Container.php:1017)

I wonder if this is som cache issue but php artisan cache:clear did not fix the issue.

Here is my config

<?php

return [

    /*
     * The log profile which determines whether a request should be logged.
     * It should implement `LogProfile`.
     */
    'log_profile' => \App\LogApiRequests::class,

    /*
     * The log writer used to write the request to a log.
     * It should implement `LogWriter`.
     */
    'log_writer' => \App\DbLogWriter::class,

    /*
     * Filter out body fields which will never be logged.
     */
    'except' => [
        'password',
        'password_confirmation',
        'api_token',
    ],

];

This is the implementation of LogApiRequests

<?php

namespace App;

use Illuminate\Http\Request;
use Spatie\HttpLogger\LogProfile;

class LogApiRequests implements LogProfile
{
    public function shouldLogRequest(Request $request): bool
    {
        return strpos($request->path(), 'api') === 0;
    }
}

Any idea?

Error installing under laravel 5.7

$ composer require spatie/laravel-http-logger

Using version ^1.2 for spatie/laravel-http-logger
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for spatie/laravel-http-logger ^1.2 -> satisfiable by spatie/laravel-http-logger[1.2.0].
    - Conclusion: remove laravel/framework v5.7.15
    - Conclusion: don't install laravel/framework v5.7.15
    - spatie/laravel-http-logger 1.2.0 requires illuminate/support ~5.8.0 -> satisfiable by laravel/framework[5.8.x-dev], illuminate/support[5.8.x-dev, v5.8.0, v5.8.2, v5.8.3, v5.8.4, v5.8.8, v5.8.9].
    - Can only install one of: laravel/framework[5.8.x-dev, v5.7.15].
    - don't install illuminate/support 5.8.x-dev|don't install laravel/framework v5.7.15
    - don't install illuminate/support v5.8.0|don't install laravel/framework v5.7.15
    - don't install illuminate/support v5.8.2|don't install laravel/framework v5.7.15
    - don't install illuminate/support v5.8.3|don't install laravel/framework v5.7.15
    - don't install illuminate/support v5.8.4|don't install laravel/framework v5.7.15
    - don't install illuminate/support v5.8.8|don't install laravel/framework v5.7.15
    - don't install illuminate/support v5.8.9|don't install laravel/framework v5.7.15
    - Installation request for laravel/framework (locked at v5.7.15, required as 5.7.*) -> satisfiable by laravel/framework[v5.7.15].


Installation failed, reverting ./composer.json to its original content.

Any lead?

Improve tests

The current tests only test for the bare minimum of scenarios.

For starters, the DefaultLogProfileTest only tests for POST and GET requests. Different scenarios should be added for PUT, PATCH and DELETE.

Second, the IntegrationTest can use some more scenarios to test real-world examples.

working with php 5.6 version

i currently working on laravel 5.4 and php 5.6, but this package required php 7.0. So can you team make it work with lower php version like 5.6 as minimal version. Thank you!

English is not my native language. Sorry for any spelling mistakes.

SUGGESTION: Add possibility to log both request and response

I would like to post a PR that adds support for logging both request and response, but before doing so I would like to check if this is something you would be willing to merge?

Motivation

Sometimes it might be interesting to log both request and response, a use case I will use myself i to log slow responses or to only log responses with a given HTTP status code.

Middleware request and response generally

In src/Middlewares/HttpLogger.php we can do this in a number of ways:

public function handle(Request $request, Closure $next)
{
    $timer = microtime();

    // Before passing the request downstream - Here we can log the request if we would like

    // Passing the request down the middleware line and getting the response back
    $response = $next($request);

    // Before passing the response upstream
    // Here we can log using both the request and response - but notice that we might
    // never get to this point in case of early access from another middleware down the line

    // Returning the request
    return $next($request);
}

Possible implementations

In both cases the user can decide to log the request before passing it downstream or log before passing the response upstream.

Note that both implementations are breaking changes since we are making modifications to the LogProfile and LogWriter interfaces.

Single action

An easy way of implementing this could be to add an optional second parameter to the LogProfile and LogWriter like so:

// src/LogProfile.php
public function shouldLogRequest(Request $request, ?Response $response = null, ?float $time = null): bool;

and

// src/LogWriter.php
public function logRequest(Request $request, ?Response $response = null, ?float $time = null);

And then call these twice, first Before passing the request downstream (where $response = null) and secondly Before passing the response upstream (where $response is now the actual response).

public function handle(Request $request, Closure $next)
{
    $startTime = microtime();

    // Before passing the request downstream
    if ($this->logProfile->shouldLogRequest($request)) {
        $this->logWriter->logRequest($request);
    }

    // Passing the request down the middleware line and getting the response back
    $response = $next($request);
    $time = microtime() - $startTime;

    // Before passing the response upstream - Note that this might never be called in case of early middleware return
    if ($this->logProfile->shouldLogRequest($request, $response, $time)) {
        $this->logWriter->logRequest($request, $response, $time);
    }

    return $next($request);
}

Separate actions

This implementation adds dedicated methods for logging before or after passing the response downstream.

// src/LogProfile.php
public function shouldLogRequest(Request $request): bool;

public function shouldLogRequestAndResponse(Request $request, ?Response $response, float $time): bool;

and

// src/LogWriter.php
public function logRequest(Request $request));

public function logRequestAndResponse(Request $request, Response $response, float $time);

And the implementation:

public function handle(Request $request, Closure $next)
{
    $startTime = microtime();

    // Before passing the request downstream
    if ($this->logProfile->shouldLogRequest($request)) {
        $this->logWriter->logRequest($request);
    }

    // Passing the request down the middleware line and getting the response back
    $response = $next($request);
    $time = microtime() - $startTime;

    // Before passing the response upstream - Note that this might never be called in case of early middleware return
    if ($this->logProfile->shouldLogRequestAndResponse($request, $response, $time)) {
        $this->logWriter->logRequestAndResponse($request, $response, $time);
    }

    return $next($request);
}

User logged

is possible to get the user id if there is logged ?

like that $user = Auth::user();
regards!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.