Search code examples
phplaravelmonolog

Passing optional custom parameter with Laravel (Monolog) logging


I have a Laravel project. I would like to pass an optional custom parameter (domain ID) when creating log entries. I am logging to a MySQL database via a custom Monolog event handler, based on this tutorial:.

I have searched but cannot find any solutions for what appears to be a relatively simple problem, there's a number of posts discussing things like adding user ID but none consider a simple optional parameter. Any help would be much appreciated!

Laravel: 8.27 PHP: 8.0.2

As per the tutorial, I have configured a custom handler and I can see how to use session variables or similar for customer

As per the tutorial, I have this custom handler:

namespace App\Logging;
use DB;
use Illuminate\Support\Facades\Auth;
use Monolog\Logger;
use Monolog\Handler\AbstractProcessingHandler;
class MySQLLoggingHandler extends AbstractProcessingHandler{

    public function __construct($level = Logger::DEBUG, $bubble = true) {
        parent::__construct($level, $bubble);
    }
    protected function write(array $record):void
    {
        $remote_addr = '127.0.0.1';
        if (isset( $_SERVER['REMOTE_ADDR'])) {$remote_addr = $_SERVER['REMOTE_ADDR'];}
        $user_agent = 'Unknown';
        if (isset( $_SERVER['HTTP_USER_AGENT'])) {$user_agent = $_SERVER['HTTP_USER_AGENT'];}
        $data = array(
            'message'       => $record['message'],
            'context'       => json_encode($record['context']),
            'level'         => $record['level'],
            'level_name'    => $record['level_name'],
            'channel'       => $record['channel'],
            'record_datetime' => $record['datetime']->format('Y-m-d H:i:s'),
            'extra'         => json_encode($record['extra']),
            'formatted'     => $record['formatted'],
            'remote_addr'   => $remote_addr,
            'user_agent'    => $user_agent,
            'created_at'    => date("Y-m-d H:i:s"),
        );
        DB::connection()->table('log_entries')->insert($data);
    }
}

And the custom logger class that uses it:

namespace App\Logging;
use Monolog\Logger;
class MySQLCustomLogger{
    /**
     * Custom Monolog instance.
     */
    public function __invoke(array $config){
        $logger = new Logger("MySQLLoggingHandler");
        return $logger->pushHandler(new MySQLLoggingHandler());
    }
}

The above works great for pushing logs to the database like this:

Log::info("New record created for domain id".$domain_id);

Unfortunately this makes searching the database painful when looking for enties for a specific ID, I was hoping to be able to add an option parameter like this:

Log::info("New record created for domain", $domain_id);


Solution

  • If you log the following way

    Log::info('New record created for domain id', ['domain_id' => $domain_id]);
    

    This should be accessible on the extra parameter on the array.

    protected function write(array $record):void
    {
        ...
    
        $data = [
            ...
            'domain_id' => $record['context']['domain_id'],
        ];
    

    For a better understanding, the $record is actually a type of Log Record, which will help understanding what capabilities the $record property has.