Gau*_*shi 32 php logging laravel laravel-5 laravel-5.2
我们是否可以在laravel 5.2中为不同目的创建自定义日志文件,例如订单相关的日志条目应该在order.log中,对于与付款相关的内容,条目应该记录在payments.log中
我想找到最好的Laravel方式.
目前我们只能更改日志文件的频率(如每日,单一)或者我们可以更改默认日志文件的名称,即laravel.log
小智 42
有一个简单的方法:
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);
Run Code Online (Sandbox Code Playgroud)
在logs/order.log中输出:
[2017-04-30 00:00:00] order.INFO: OrderLog {"orderId":10, "description":"Some description"} []
Run Code Online (Sandbox Code Playgroud)
小智 35
在这里你去...我花了很多时间为Monolog添加自定义功能,能够以适当的方式做到这一点.我尝试了许多不同的方式,但都有点hacky.最后,我找到了一种让这项功能正常工作的好方法....
由于应用程序很大,我需要单独的日志文件,并尽可能地维护现有的Laravel的Log界面.我需要这样的东西:
Log::write('audit', 'User logged in to the app.');
Log::info('event', 'User sent out 2 emails.');
解决方案:
App\Providers\AppServiceProvider.php(添加到注册函数)
//Facade to Object binding
$this->app->bind('chanellog', 'App\Helpers\ChannelWriter');
Run Code Online (Sandbox Code Playgroud)
config\app.php(添加到别名)
//Custom Alias Class
'ChannelLog' => App\Contracts\Facades\ChannelLog::class,
Run Code Online (Sandbox Code Playgroud)
应用程序\合同\外立面\ ChannelLog.php
<?php
namespace 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';
}
}
Run Code Online (Sandbox Code Playgroud)
应用程序\助手\ ChannelWriter.php
<?php
namespace 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]);
}
}
}
Run Code Online (Sandbox Code Playgroud)
应用程序\助手\ ChannelStreamHandler.php
<?php
namespace 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
);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在此之后,您可以在任何文件中执行:
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])
}
Run Code Online (Sandbox Code Playgroud)
Nir*_*hah 11
您可以尝试重新利用日志功能,将不同类型的日志写入不同的文件.这可以通过编辑bootstrap/app.php文件来完成:
$app->configureMonologUsing(function($monolog) {
$bubble = false;
$infoStreamHandler = new Monolog\Handler\StreamHandler( storage_path("/logs/orders.log"), Monolog\Logger::INFO, $bubble);
$monolog->pushHandler($infoStreamHandler);
$warningStreamHandler = new Monolog\Handler\StreamHandler( storage_path("/logs/logins.log"), Monolog\Logger::WARNING, $bubble);
$monolog->pushHandler($warningStreamHandler);
});
Run Code Online (Sandbox Code Playgroud)
然后在您的代码中,您可以:
Log::info('Order was created', ['ORDER-123']);
Log::warning('User login', ['USER-1']);
Run Code Online (Sandbox Code Playgroud)
您可以使用此方法编辑所有可用的日志功能:
fay*_*ayz 10
现在以更简单的方式支持此功能
建立频道
转到:root/config/logging.php,下channels数组添加您的自定义频道,即
'付款'=> [
'驱动程序'=>'单个',
'路径'=> storage_path('logs / payments.log'),
'level'=>'info',
],在您的路线或控制器中写入此日志
Log::channel('payments')->info('A transaction has been made!');
Run Code Online (Sandbox Code Playgroud)可以在以下位置找到付款日志 /storage/logs/payments.log
注意:可扩展以进一步满足您的要求
Laravel 5.6版文档
扩展ShQ的答案:
我注意到的一个问题是日志将被附加[] [],这是空的数组值$context和$extra内部LineFormatter.format();
即 vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php
有两种方法可以解决这个问题,或者提供一种不包含构造函数的额外或上下文的格式LineFormatter,或者提供第四个参数$ignoreEmptyContextAndExtra= true.
ShQ答案中的所有文件保持不变,但ChannelStreamHandler必须更改.
ChannelStreamHandler:
<?php
namespace App\Helpers;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
/**
* Use channels to log into separate files
*
*/
class ChannelStreamHandler extends StreamHandler
{
/**
* Channel name
*
* @var String
*/
protected $channel;
/**
* @param String $channel Channel name to write
* @param bool|int $stream
* @param bool|int $level
* @param bool $bubble
* @param null $filePermission
* @param bool $useLocking
* @see parent __construct for params
*/
public function __construct(
$channel,
$stream,
$level = Logger::DEBUG,
$bubble = true,
$filePermission = null,
$useLocking = false
) {
$this->channel = $channel;
$formatter = new LineFormatter(null, null, false, true);
$this->setFormatter($formatter);
parent::__construct($stream, $level, $bubble);
}
/**
* When to handle the log record.
*
* @param array $record
* @return bool
*/
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
重要的变化是提供第4个真实的参数,即$ignoreEmptyContextAndExtra.这个参数告诉LineFormatter忽略任何context一个extra数组,如果为空:
$formatter = new LineFormatter(null, null, false, true);
$this->setFormatter($formatter);
Run Code Online (Sandbox Code Playgroud)
您必须确保运行monolog 1.22,因为它包含有关的错误修复ignoreEmptyContextAndExtra.
我还为ChannelWritter该类添加了info()的覆盖:
public function info($channel, $message, array $context = [])
{
$level = array_flip($this->levels)[$this->channels[$channel]['level']];
$this->writeLog($channel, $level, $message, $context);
}
Run Code Online (Sandbox Code Playgroud)
此外,我对ShQ解决方案中的"延迟加载记录器"不满意,因此修改为使用服务提供商/ IoC
替换ChannelWriter.writeLog():
public function writeLog(string $channel, string $level, string $message, array $context = [])
{
if (!in_array($channel, array_keys($this->channels))) {
throw new InvalidArgumentException('Invalid channel used.');
}
$logger = \App::make("{$channel}log");
$channelHandler = new ChannelStreamHandler(
$channel,
storage_path() . '/' . $this->channels[$channel]['path'],
$this->channels[$channel]['level']
);
$logger->pushHandler($channelHandler);
$logger->{$level}($message);
}
Run Code Online (Sandbox Code Playgroud)
在你的AppServiceProvider:
$this->app->bind('eventlog', function () {
return new Logger('event');
});
$this->app->bind('auditlog', function () {
return new Logger('audit');
});
Run Code Online (Sandbox Code Playgroud)
我会尝试将它们捆绑在一起.