php laravel 5.2 不同任务的自定义日志文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37809989/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 01:23:49  来源:igfitidea点击:

laravel 5.2 custom log file for different tasks

phplaravellaravel-5logginglaravel-5.2

提问by Gaurav Bakshi

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

回答by massreuy

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:

日志/order.log 中的输出:

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

回答by ShQ

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', 'User logged in to the app.');
Log::info('event', 'User sent out 2 emails.');

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

App\Contracts\Facades\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

App\Helpers\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

App\Helpers\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])
}

回答by f_i

This is supported in a much easier way now

现在以更简单的方式支持这一点

  1. Create a channel

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

  1. 创建频道

    转到:root/config/logging.php,在channels数组下添加您的自定义频道,即

      'payments' => [
          'driver' => 'single',
          'path' => storage_path('logs/payments.log'),
          'level' => 'info',
    ],
  1. In your route or controller write to this log
  1. 在您的路由或控制器中写入此日志
    Log::channel('payments')->info('A transaction has been made!');
  1. The payment logs can be found at /storage/logs/payments.log
  1. 可以在以下位置找到付款日志 /storage/logs/payments.log

NOTE:extendible to enhance furthur your requirements

注意:可扩展以进一步增强您的要求

Laravel version 5.6 Docs

Laravel 5.6 版文档

回答by Niraj Shah

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.phpfile:

您可以尝试重新利用日志功能将不同类型的日志写入不同的文件。这可以通过编辑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
  • INFO
  • NOTICE
  • WARNING
  • ERROR
  • CRITICAL
  • ALERT
  • EMERGENCY
  • 调试
  • 信息
  • 注意
  • 警告
  • 错误
  • 危急
  • 警报
  • 紧急情况

回答by wired00

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 $contextand $extrawithin LineFormatter.format();

一个问题,我注意到的是,日志将被附加[] [],这是空数组值$context$extraLineFormatter.format();

ie, vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php

IE, 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 ChannelStreamHandlermust change.

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);
        }
    }

}

The important change is to provide 4th param of true, which is $ignoreEmptyContextAndExtra. This param, tells LineFormatterto ignore either contextof extraarrays if empty:

重要的变化是提供 true 的第四个参数,即$ignoreEmptyContextAndExtra. 这个参数告诉LineFormatter忽略任何context一个extra数组,如果为空:

$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 ChannelWritterclass:

我还在类中添加了 info() 的覆盖ChannelWritter

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.

我会试着把它捆绑成一个包。

回答by Deepak Pandey

Quickest Way to output log to different files

将日志输出到不同文件的最快方法

Log::useFiles('path/to/file.log');
Log::info('Info');

回答by Romain Laneuville

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 <[email protected]>
 */

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.

当您在应用程序的任何位置调用它的名称时,它就可以访问。

回答by tristanbailey

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.

nb 这是我之前从 config 设置日志级别的地方,所以我最终得到了 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);

}

回答by Kundan roy

Solution:

step1: create a channel inside config/logging.php file

example :

'channels' => [
    'single' => [
    'driver' => 'single', 
    'path' => storage_path('logs/laravel.log'),
    'level' => 'debug',
],

'web' => [
      'driver' => 'single',
      'path' => storage_path('logs/web/web.log'),
   ],

]

Step2: Now set dynamic path from the controller  like this

config(['logging.channels.web.path' => storage_path('logs/web/'.time().'.log')]);

Step3 : now generate your log

  Log::channel('web')->info("your message goes here");

Enjoy :)

回答by Manchumahara

I managed my own log function which can be put in helper.php file in app dir.

我管理了我自己的日志函数,它可以放在 app 目录的 helper.php 文件中。

if ( ! function_exists( 'write_log' ) ) {
    /**
     * Write log to log file
     *
     * @param string|array|object $log
     */
    function write_log( $log ) {
        if ( env('APP_LOG_LEVEL', 'debug') == 'debug' ) {
            if ( is_array( $log ) || is_object( $log ) ) {
                file_put_contents(laravelInstallDir().'../debug.log', print_r( $log, true ), FILE_APPEND);
            } else {
                file_put_contents(laravelInstallDir().'../debug.log', $log, FILE_APPEND);
            }
        }
    }
}

Please adjust the path laravelInstallDir().'../debug.log' as need

请根据需要调整路径laravelInstallDir().'../debug.log'