laravel 5.2 custom log file for different tasks laravel 5.2 custom log file for different tasks laravel laravel

laravel 5.2 custom log file for different tasks


There is a simple way:

use Monolog\Logger;use Monolog\Handler\StreamHandler;$log = ['orderId' => 10,        'description' => 'Some description'];//first parameter passed to Monolog\Logger sets the logging channel name$orderLog = new Logger('order');$orderLog->pushHandler(new StreamHandler(storage_path('logs/order.log')), Logger::INFO);$orderLog->info('OrderLog', $log);

Output in logs/order.log:

[2017-04-30 00:00:00] order.INFO: OrderLog {"orderId":10, "description":"Some description"} []


Here you go... I've spent so much time to add custom functionality to Monolog which able to do THAT in a proper way. I tried sooooo many different ways, but all was a bit hacky. Finally I found a good way to get this functionality working....

As the application is big, I needed separate log files, and maintain the existing Laravel's Log interface as much as possible. I needed something like:

Log::write('audit', 'User logged in to the app.');
Log::info('event', 'User sent out 2 emails.');

The Solution:

App\Providers\AppServiceProvider.php (add to register function)

//Facade to Object binding$this->app->bind('chanellog', 'App\Helpers\ChannelWriter');

config\app.php (add to aliases)

//Custom Alias Class'ChannelLog' => App\Contracts\Facades\ChannelLog::class,

App\Contracts\Facades\ChannelLog.php

<?phpnamespace App\Contracts\Facades;use Illuminate\Support\Facades\Facade;/** * @see \Illuminate\Log\Writer */class ChannelLog extends Facade{    /**     * Get the registered name of the component.     *     * @return string     */    protected static function getFacadeAccessor()    {        return 'chanellog';    }}

App\Helpers\ChannelWriter.php

<?phpnamespace App\Helpers;use Monolog\Logger;use App\Helpers\ChannelStreamHandler;class ChannelWriter{    /**     * The Log channels.     *     * @var array     */    protected $channels = [        'event' => [             'path' => 'logs/audit.log',             'level' => Logger::INFO         ],        'audit' => [             'path' => 'logs/audit.log',             'level' => Logger::INFO         ]    ];    /**     * The Log levels.     *     * @var array     */    protected $levels = [        'debug'     => Logger::DEBUG,        'info'      => Logger::INFO,        'notice'    => Logger::NOTICE,        'warning'   => Logger::WARNING,        'error'     => Logger::ERROR,        'critical'  => Logger::CRITICAL,        'alert'     => Logger::ALERT,        'emergency' => Logger::EMERGENCY,    ];    public function __construct() {}    /**     * Write to log based on the given channel and log level set     *      * @param type $channel     * @param type $message     * @param array $context     * @throws InvalidArgumentException     */    public function writeLog($channel, $level, $message, array $context = [])    {        //check channel exist        if( !in_array($channel, array_keys($this->channels)) ){            throw new InvalidArgumentException('Invalid channel used.');        }        //lazy load logger        if( !isset($this->channels[$channel]['_instance']) ){            //create instance            $this->channels[$channel]['_instance'] = new Logger($channel);            //add custom handler            $this->channels[$channel]['_instance']->pushHandler(                 new ChannelStreamHandler(                     $channel,                     storage_path() .'/'. $this->channels[$channel]['path'],                     $this->channels[$channel]['level']                )            );        }        //write out record        $this->channels[$channel]['_instance']->{$level}($message, $context);    }    public function write($channel, $message, array $context = []){        //get method name for the associated level        $level = array_flip( $this->levels )[$this->channels[$channel]['level']];        //write to log        $this->writeLog($channel, $level, $message, $context);    }    //alert('event','Message');    function __call($func, $params){        if(in_array($func, array_keys($this->levels))){            return $this->writeLog($params[0], $func, $params[1]);        }    }}

App\Helpers\ChannelStreamHandler.php

<?phpnamespace App\Helpers;use Monolog\Handler\StreamHandler;/** * Use channels to log into separate files * * @author Peter Feher */class ChannelStreamHandler extends StreamHandler{    /**     * Channel name     *      * @var String      */    protected $channel;    /**     * @param String $channel Channel name to write     * @see parent __construct for params     */    public function __construct($channel, $stream, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)    {        $this->channel = $channel;        parent::__construct($stream, $level, $bubble);    }    /**     * When to handle the log record.      *      * @param array $record     * @return type     */    public function isHandling(array $record)    {        //Handle if Level high enough to be handled (default mechanism)         //AND CHANNELS MATCHING!        if( isset($record['channel']) ){            return (                 $record['level'] >= $this->level &&                 $record['channel'] == $this->channel             );        } else {            return (                 $record['level'] >= $this->level            );        }    }}

After this, you can do in any file:

use ChannelLog as Log;...function myFunction(){    //Recommended (writes INFO to logs/event.log)    Log::write('event', 'User sent out 3 voucher.')    //Possible to use (writes ALERT to logs/audit.log)    Log::alert('audit', 'User modified xyz entry.')    //Or even:     Log::write('audit', 'User modified xyz entry.', ['user'=>1])}


This is supported in a much easier way now

  1. Create a channel

    goto: root/config/logging.php, under channels array add your custom channel i.e

      'payments' => [          'driver' => 'single',          'path' => storage_path('logs/payments.log'),          'level' => 'info',    ],
  1. In your route or controller write to this log
    Log::channel('payments')->info('A transaction has been made!');
  1. The payment logs can be found at /storage/logs/payments.log

NOTE: extendible to enhance furthur your requirements

Laravel version 5.6 Docs