Can we create a custom log file for different purposes in laravel 5.2 like for order related log entries that should be in order.log and for payment related stuff the entry should get logged in payments.log
我们是否可以在laravel 5.2中为不同目的创建自定义日志文件,例如订单相关的日志条目应该在order.log中,对于与付款相关的内容,条目应该记录在payments.log中
I want to find the best possible Laravel way.
我想找到最好的Laravel方式。
Currently we can only change the log file frequency (like daily, single) or we can change the name of the log file other than default i.e laravel.log
目前我们只能更改日志文件频率(如每日,单一)或者我们可以更改默认日志文件的名称,即laravel.log
7 个解决方案
#1
30
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....
在这里你去...我花了很多时间为Monolog添加自定义功能,能够以适当的方式做到这一点。我尝试了许多不同的方法,但都有点hacky。最后,我找到了一种让这项功能正常工作的好方法....
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:
由于应用程序很大,我需要单独的日志文件,并尽可能地维护现有的Laravel的Log界面。我需要这样的东西:
Log::write('audit', 'User logged in to the app.');
Log::info('event', 'User sent out 2 emails.');
Log :: write('audit','用户登录到应用程序。'); Log :: info('event','User发出2封电子邮件。');
The Solution:
解决方案:
App\Providers\AppServiceProvider.php (add to register function)
App \ Providers \ AppServiceProvider.php(添加到注册函数)
//Facade to Object binding
$this->app->bind('chanellog', 'App\Helpers\ChannelWriter');
config\app.php (add to aliases)
config \ app.php(添加到别名)
//Custom Alias Class
'ChannelLog' => App\Contracts\Facades\ChannelLog::class,
App\Contracts\Facades\ChannelLog.php
应用程序\合同\外立面\ 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';
}
}
App\Helpers\ChannelWriter.php
应用程序\助手\ 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]);
}
}
}
App\Helpers\ChannelStreamHandler.php
应用程序\助手\ 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
);
}
}
}
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])
}
#2
26
There is a simple way:
有一个简单的方法:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$log = ['orderId' => 10,
'description' => 'Some description'];
$orderLog = new Logger(order);
$orderLog->pushHandler(new StreamHandler(storage_path('logs/order.log')), Logger::INFO);
$orderLog->info('OrderLog', $log);
Output in logs/order.log:
在logs / order.log中输出:
[2017-04-30 00:00:00] order.INFO: OrderLog {"orderId":10, "description":"Some description"} []
#3
9
You can try repurposing the log functions to write different types of logs to different files. This can be done by editing the bootstrap/app.php
file:
您可以尝试重新调整日志功能,以将不同类型的日志写入不同的文件。这可以通过编辑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);
});
Then in your code, you can do:
然后在您的代码中,您可以:
Log::info('Order was created', ['ORDER-123']);
Log::warning('User login', ['USER-1']);
You can use this method to edit all the available log functions:
您可以使用此方法编辑所有可用的日志功能:
- DEBUG
- DEBUG
- INFO
- 信息
- NOTICE
- 注意
- WARNING
- 警告
- ERROR
- 错误
- CRITICAL
- 危急
- ALERT
- 警报
- EMERGENCY
- 紧急
#4
4
To expand on ShQ's answer:
扩展ShQ的答案:
One issue I noticed is that the log will be appended with [] []
, which are the empty array values for $context
and $extra
within LineFormatter.format();
我注意到的一个问题是日志将附加[] [],这是$ context的空数组值和LineFormatter.format()中的$ extra;
ie, vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php
即,vendor / monolog / monolog / src / Monolog / Formatter / LineFormatter.php
There are two ways around this, either provide a format which does not include extra or context to the constructor of LineFormatter
, or provide the 4th argument $ignoreEmptyContextAndExtra
= true
.
有两种方法可以解决这个问题,或者为LineFormatter的构造函数提供一个不包含额外或上下文的格式,或者提供第四个参数$ ignoreEmptyContextAndExtra = true。
All files within ShQ's answer remain the same but ChannelStreamHandler
must change.
ShQ的答案中的所有文件保持不变,但ChannelStreamHandler必须更改。
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);
}
}
}
The important change is to provide 4th param of true, which is $ignoreEmptyContextAndExtra
. This param, tells LineFormatter
to ignore either context
of extra
arrays if empty:
重要的变化是提供第4个真实的参数,即$ ignoreEmptyContextAndExtra。这个参数告诉LineFormatter如果为空则忽略额外数组的上下文:
$formatter = new LineFormatter(null, null, false, true);
$this->setFormatter($formatter);
You must be sure to also ensure your running monolog 1.22 because it includes a bug fix regarding ignoreEmptyContextAndExtra
.
您必须确保运行monolog 1.22,因为它包含有关ignoreEmptyContextAndExtra的错误修复。
I also added an override for info() to the ChannelWritter
class:
我还为ChannelWritter类添加了info()的覆盖:
public function info($channel, $message, array $context = [])
{
$level = array_flip($this->levels)[$this->channels[$channel]['level']];
$this->writeLog($channel, $level, $message, $context);
}
Additionally, I wasn't happy with the "lazy load logger" in ShQ's solution so modified to use the service provider/IoC
此外,我对ShQ解决方案中的“延迟加载记录器”不满意,因此修改为使用服务提供商/ IoC
Replace ChannelWriter.writeLog()
:
替换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);
}
and in your AppServiceProvider
:
并在您的AppServiceProvider中:
$this->app->bind('eventlog', function () {
return new Logger('event');
});
$this->app->bind('auditlog', function () {
return new Logger('audit');
});
I'll try bundle this together into a package.
我会尝试将它们捆绑在一起。
#5
0
For me in Laravel 5.3, I am not sure if it was my install previously but I found the bootstrap/app.php did not work for me.
对于我来说,在Laravel 5.3中,我不确定它是否是我之前的安装,但我发现bootstrap / app.php对我不起作用。
I needed to put this in app/Providers/AppServiceProvider.php.
我需要把它放在app / Providers / AppServiceProvider.php中。
n.b. This is where I had the setting of the log level from config before, so I end up with 3 log handlers.
注:这是我之前从配置设置日志级别的地方,所以我最终得到了3个日志处理程序。
public function register()
{
$monolog = Log::getMonolog();
foreach ($monolog->getHandlers() as $handler) {
$handler->setLevel(Config::get('app.log_level'));
}
$bubble = false;
$infoStreamHandler = new \Monolog\Handler\StreamHandler( storage_path("logs/info.log"), \Monolog\Logger::INFO, $bubble);
$monolog->pushHandler($infoStreamHandler);
$warningStreamHandler = new \Monolog\Handler\StreamHandler( storage_path("logs/warning.log"), \Monolog\Logger::WARNING, $bubble);
$monolog->pushHandler($warningStreamHandler);
}
#6
0
Based on the ShQ answer, a shorter and simpler logger helper that allows you to log to a custom file on the fly. You can also add your custom handler and set the file path.
基于ShQ答案,更简单,更简单的记录器助手,允许您即时登录自定义文件。您还可以添加自定义处理程序并设置文件路径。
App\Helper
应用程序\助手
<?php
/**
* Logger helper to log into different files
*
* @package App\Helpers
* @author Romain Laneuville <romain.laneuville@hotmail.fr>
*/
namespace App\Helpers;
use Monolog\Logger;
use Monolog\Handler\HandlerInterface;
use Monolog\Handler\StreamHandler;
/**
* Class LogToChannels
*
* @package App\Helpers
*/
class LogToChannels
{
/**
* The LogToChannels channels.
*
* @var Logger[]
*/
protected $channels = [];
/**
* LogToChannels constructor.
*/
public function __construct()
{
}
/**
* @param string $channel The channel to log the record in
* @param int $level The error level
* @param string $message The error message
* @param array $context Optional context arguments
*
* @return bool Whether the record has been processed
*/
public function log(string $channel, int $level, string $message, array $context = []): bool
{
// Add the logger if it doesn't exist
if (!isset($this->channels[$channel])) {
$handler = new StreamHandler(
storage_path() . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . $channel . '.log'
);
$this->addChannel($channel, $handler);
}
// LogToChannels the record
return $this->channels[$channel]->{Logger::getLevelName($level)}($message, $context);
}
/**
* Add a channel to log in
*
* @param string $channelName The channel name
* @param HandlerInterface $handler The channel handler
* @param string|null $path The path of the channel file, DEFAULT storage_path()/logs
*
* @throws \Exception When the channel already exists
*/
public function addChannel(string $channelName, HandlerInterface $handler, string $path = null)
{
if (isset($this->channels[$channelName])) {
throw new \Exception('This channel already exists');
}
$this->channels[$channelName] = new Logger($channelName);
$this->channels[$channelName]->pushHandler(
new $handler(
$path === null ?
storage_path() . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . $channelName . '.log' :
$path . DIRECTORY_SEPARATOR . $channelName . '.log'
)
);
}
/**
* Adds a log record at the DEBUG level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function debug(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::DEBUG, $message, $context);
}
/**
* Adds a log record at the INFO level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function info(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::INFO, $message, $context);
}
/**
* Adds a log record at the NOTICE level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function notice(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::NOTICE, $message, $context);
}
/**
* Adds a log record at the WARNING level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function warn(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::WARNING, $message, $context);
}
/**
* Adds a log record at the WARNING level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function warning(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::WARNING, $message, $context);
}
/**
* Adds a log record at the ERROR level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function err(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::ERROR, $message, $context);
}
/**
* Adds a log record at the ERROR level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function error(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::ERROR, $message, $context);
}
/**
* Adds a log record at the CRITICAL level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function crit(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::CRITICAL, $message, $context);
}
/**
* Adds a log record at the CRITICAL level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return Boolean Whether the record has been processed
*/
public function critical(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::CRITICAL, $message, $context);
}
/**
* Adds a log record at the ALERT level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function alert(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::ALERT, $message, $context);
}
/**
* Adds a log record at the EMERGENCY level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function emerg(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::EMERGENCY, $message, $context);
}
/**
* Adds a log record at the EMERGENCY level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function emergency(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::EMERGENCY, $message, $context);
}
}
App\Providers\AppServiceProvider.php (add to register function)
App \ Providers \ AppServiceProvider.php(添加到注册函数)
//Facade to Object binding
$this->app->bind('LogToChannels', 'App\Helpers\LogToChannels');
config\app.php (add to aliases)
config \ app.php(添加到别名)
// Custom Alias Class
'Log' => App\Contracts\Facades\LogToChannels::class
Then anywhere in your app you can call
然后,您可以在应用中的任何地方拨打
Log::info('logger_name', 'Log message');
Log::error('other_logger_name', 'Log message', $someContext);
You can even customize your logger output by calling
您甚至可以通过调用自定义记录器输出
Log::addChannel('channel_name', $customHandler);
And it will be accessible when you will call its name anywhere in your app.
当您在应用中的任何位置调用其名称时,它将可访问。
#7
0
Quickest Way to output log to different files
最快的方式将日志输出到不同的文件
Log::useFiles('path/to/file.log');
Log::info('Info');
#1
30
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....
在这里你去...我花了很多时间为Monolog添加自定义功能,能够以适当的方式做到这一点。我尝试了许多不同的方法,但都有点hacky。最后,我找到了一种让这项功能正常工作的好方法....
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:
由于应用程序很大,我需要单独的日志文件,并尽可能地维护现有的Laravel的Log界面。我需要这样的东西:
Log::write('audit', 'User logged in to the app.');
Log::info('event', 'User sent out 2 emails.');
Log :: write('audit','用户登录到应用程序。'); Log :: info('event','User发出2封电子邮件。');
The Solution:
解决方案:
App\Providers\AppServiceProvider.php (add to register function)
App \ Providers \ AppServiceProvider.php(添加到注册函数)
//Facade to Object binding
$this->app->bind('chanellog', 'App\Helpers\ChannelWriter');
config\app.php (add to aliases)
config \ app.php(添加到别名)
//Custom Alias Class
'ChannelLog' => App\Contracts\Facades\ChannelLog::class,
App\Contracts\Facades\ChannelLog.php
应用程序\合同\外立面\ 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';
}
}
App\Helpers\ChannelWriter.php
应用程序\助手\ 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]);
}
}
}
App\Helpers\ChannelStreamHandler.php
应用程序\助手\ 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
);
}
}
}
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])
}
#2
26
There is a simple way:
有一个简单的方法:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$log = ['orderId' => 10,
'description' => 'Some description'];
$orderLog = new Logger(order);
$orderLog->pushHandler(new StreamHandler(storage_path('logs/order.log')), Logger::INFO);
$orderLog->info('OrderLog', $log);
Output in logs/order.log:
在logs / order.log中输出:
[2017-04-30 00:00:00] order.INFO: OrderLog {"orderId":10, "description":"Some description"} []
#3
9
You can try repurposing the log functions to write different types of logs to different files. This can be done by editing the bootstrap/app.php
file:
您可以尝试重新调整日志功能,以将不同类型的日志写入不同的文件。这可以通过编辑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);
});
Then in your code, you can do:
然后在您的代码中,您可以:
Log::info('Order was created', ['ORDER-123']);
Log::warning('User login', ['USER-1']);
You can use this method to edit all the available log functions:
您可以使用此方法编辑所有可用的日志功能:
- DEBUG
- DEBUG
- INFO
- 信息
- NOTICE
- 注意
- WARNING
- 警告
- ERROR
- 错误
- CRITICAL
- 危急
- ALERT
- 警报
- EMERGENCY
- 紧急
#4
4
To expand on ShQ's answer:
扩展ShQ的答案:
One issue I noticed is that the log will be appended with [] []
, which are the empty array values for $context
and $extra
within LineFormatter.format();
我注意到的一个问题是日志将附加[] [],这是$ context的空数组值和LineFormatter.format()中的$ extra;
ie, vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php
即,vendor / monolog / monolog / src / Monolog / Formatter / LineFormatter.php
There are two ways around this, either provide a format which does not include extra or context to the constructor of LineFormatter
, or provide the 4th argument $ignoreEmptyContextAndExtra
= true
.
有两种方法可以解决这个问题,或者为LineFormatter的构造函数提供一个不包含额外或上下文的格式,或者提供第四个参数$ ignoreEmptyContextAndExtra = true。
All files within ShQ's answer remain the same but ChannelStreamHandler
must change.
ShQ的答案中的所有文件保持不变,但ChannelStreamHandler必须更改。
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);
}
}
}
The important change is to provide 4th param of true, which is $ignoreEmptyContextAndExtra
. This param, tells LineFormatter
to ignore either context
of extra
arrays if empty:
重要的变化是提供第4个真实的参数,即$ ignoreEmptyContextAndExtra。这个参数告诉LineFormatter如果为空则忽略额外数组的上下文:
$formatter = new LineFormatter(null, null, false, true);
$this->setFormatter($formatter);
You must be sure to also ensure your running monolog 1.22 because it includes a bug fix regarding ignoreEmptyContextAndExtra
.
您必须确保运行monolog 1.22,因为它包含有关ignoreEmptyContextAndExtra的错误修复。
I also added an override for info() to the ChannelWritter
class:
我还为ChannelWritter类添加了info()的覆盖:
public function info($channel, $message, array $context = [])
{
$level = array_flip($this->levels)[$this->channels[$channel]['level']];
$this->writeLog($channel, $level, $message, $context);
}
Additionally, I wasn't happy with the "lazy load logger" in ShQ's solution so modified to use the service provider/IoC
此外,我对ShQ解决方案中的“延迟加载记录器”不满意,因此修改为使用服务提供商/ IoC
Replace ChannelWriter.writeLog()
:
替换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);
}
and in your AppServiceProvider
:
并在您的AppServiceProvider中:
$this->app->bind('eventlog', function () {
return new Logger('event');
});
$this->app->bind('auditlog', function () {
return new Logger('audit');
});
I'll try bundle this together into a package.
我会尝试将它们捆绑在一起。
#5
0
For me in Laravel 5.3, I am not sure if it was my install previously but I found the bootstrap/app.php did not work for me.
对于我来说,在Laravel 5.3中,我不确定它是否是我之前的安装,但我发现bootstrap / app.php对我不起作用。
I needed to put this in app/Providers/AppServiceProvider.php.
我需要把它放在app / Providers / AppServiceProvider.php中。
n.b. This is where I had the setting of the log level from config before, so I end up with 3 log handlers.
注:这是我之前从配置设置日志级别的地方,所以我最终得到了3个日志处理程序。
public function register()
{
$monolog = Log::getMonolog();
foreach ($monolog->getHandlers() as $handler) {
$handler->setLevel(Config::get('app.log_level'));
}
$bubble = false;
$infoStreamHandler = new \Monolog\Handler\StreamHandler( storage_path("logs/info.log"), \Monolog\Logger::INFO, $bubble);
$monolog->pushHandler($infoStreamHandler);
$warningStreamHandler = new \Monolog\Handler\StreamHandler( storage_path("logs/warning.log"), \Monolog\Logger::WARNING, $bubble);
$monolog->pushHandler($warningStreamHandler);
}
#6
0
Based on the ShQ answer, a shorter and simpler logger helper that allows you to log to a custom file on the fly. You can also add your custom handler and set the file path.
基于ShQ答案,更简单,更简单的记录器助手,允许您即时登录自定义文件。您还可以添加自定义处理程序并设置文件路径。
App\Helper
应用程序\助手
<?php
/**
* Logger helper to log into different files
*
* @package App\Helpers
* @author Romain Laneuville <romain.laneuville@hotmail.fr>
*/
namespace App\Helpers;
use Monolog\Logger;
use Monolog\Handler\HandlerInterface;
use Monolog\Handler\StreamHandler;
/**
* Class LogToChannels
*
* @package App\Helpers
*/
class LogToChannels
{
/**
* The LogToChannels channels.
*
* @var Logger[]
*/
protected $channels = [];
/**
* LogToChannels constructor.
*/
public function __construct()
{
}
/**
* @param string $channel The channel to log the record in
* @param int $level The error level
* @param string $message The error message
* @param array $context Optional context arguments
*
* @return bool Whether the record has been processed
*/
public function log(string $channel, int $level, string $message, array $context = []): bool
{
// Add the logger if it doesn't exist
if (!isset($this->channels[$channel])) {
$handler = new StreamHandler(
storage_path() . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . $channel . '.log'
);
$this->addChannel($channel, $handler);
}
// LogToChannels the record
return $this->channels[$channel]->{Logger::getLevelName($level)}($message, $context);
}
/**
* Add a channel to log in
*
* @param string $channelName The channel name
* @param HandlerInterface $handler The channel handler
* @param string|null $path The path of the channel file, DEFAULT storage_path()/logs
*
* @throws \Exception When the channel already exists
*/
public function addChannel(string $channelName, HandlerInterface $handler, string $path = null)
{
if (isset($this->channels[$channelName])) {
throw new \Exception('This channel already exists');
}
$this->channels[$channelName] = new Logger($channelName);
$this->channels[$channelName]->pushHandler(
new $handler(
$path === null ?
storage_path() . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . $channelName . '.log' :
$path . DIRECTORY_SEPARATOR . $channelName . '.log'
)
);
}
/**
* Adds a log record at the DEBUG level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function debug(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::DEBUG, $message, $context);
}
/**
* Adds a log record at the INFO level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function info(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::INFO, $message, $context);
}
/**
* Adds a log record at the NOTICE level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function notice(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::NOTICE, $message, $context);
}
/**
* Adds a log record at the WARNING level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function warn(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::WARNING, $message, $context);
}
/**
* Adds a log record at the WARNING level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function warning(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::WARNING, $message, $context);
}
/**
* Adds a log record at the ERROR level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function err(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::ERROR, $message, $context);
}
/**
* Adds a log record at the ERROR level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function error(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::ERROR, $message, $context);
}
/**
* Adds a log record at the CRITICAL level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function crit(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::CRITICAL, $message, $context);
}
/**
* Adds a log record at the CRITICAL level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return Boolean Whether the record has been processed
*/
public function critical(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::CRITICAL, $message, $context);
}
/**
* Adds a log record at the ALERT level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function alert(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::ALERT, $message, $context);
}
/**
* Adds a log record at the EMERGENCY level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function emerg(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::EMERGENCY, $message, $context);
}
/**
* Adds a log record at the EMERGENCY level.
*
* @param string $channel The channel name
* @param string $message The log message
* @param array $context The log context
*
* @return bool Whether the record has been processed
*/
public function emergency(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::EMERGENCY, $message, $context);
}
}
App\Providers\AppServiceProvider.php (add to register function)
App \ Providers \ AppServiceProvider.php(添加到注册函数)
//Facade to Object binding
$this->app->bind('LogToChannels', 'App\Helpers\LogToChannels');
config\app.php (add to aliases)
config \ app.php(添加到别名)
// Custom Alias Class
'Log' => App\Contracts\Facades\LogToChannels::class
Then anywhere in your app you can call
然后,您可以在应用中的任何地方拨打
Log::info('logger_name', 'Log message');
Log::error('other_logger_name', 'Log message', $someContext);
You can even customize your logger output by calling
您甚至可以通过调用自定义记录器输出
Log::addChannel('channel_name', $customHandler);
And it will be accessible when you will call its name anywhere in your app.
当您在应用中的任何位置调用其名称时,它将可访问。
#7
0
Quickest Way to output log to different files
最快的方式将日志输出到不同的文件
Log::useFiles('path/to/file.log');
Log::info('Info');