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
Create a channel
goto:
root/config/logging.php
, underchannels
array add your custom channel i.e
'payments' => [ 'driver' => 'single', 'path' => storage_path('logs/payments.log'), 'level' => 'info', ],
- In your route or controller write to this log
Log::channel('payments')->info('A transaction has been made!');
- The payment logs can be found at
/storage/logs/payments.log
NOTE: extendible to enhance furthur your requirements
Laravel version 5.6 Docs