larave 日志自定义配置格式记录调用文件路径与行号

larave Monolog日志自定义配置

1、原有的日志记录文件只记录了时间和日志内容没有记录是在哪个文件记录的,给新来的人员查看日志增加了额外的负担。类似下面这样

[2018-04-11 10:25:29] local.INFO: 我是来测试日志的 {"content":1111} 
[2018-04-11 10:25:29] local.DEBUG: 我是来测试日志的  
[2018-04-11 10:25:29] local.ERROR: 我是来测试日志的  
[2018-04-11 10:25:29] local.WARNING: 我是来测试日志的  

2、基于公司需求对MonoLog模块的源码进行了分析,发布Laravel是对MonoLog之上做了一层封装,达到了如下效果

[2018-04-11 10:25:29.313456] local.INFO: 我是来测试日志的 {"content":1111} {"pid":1340,"file":"App\\Http\\Controllers\\TestController->log:20","line":20,"ip":"127.0.0.1"}
[2018-04-11 10:25:29.317710] local.DEBUG: 我是来测试日志的  {"pid":1340,"file":"App\\Http\\Controllers\\TestController->log:21","line":21,"ip":"127.0.0.1"}
[2018-04-11 10:25:29.320648] local.ERROR: 我是来测试日志的  {"pid":1340,"file":"App\\Http\\Controllers\\TestController->log:22","line":22,"ip":"127.0.0.1"}
[2018-04-11 10:25:29.324702] local.WARNING: 我是来测试日志的  {"pid":1340,"file":"App\\Http\\Controllers\\TestController->log:23","line":23,"ip":"127.0.0.1"}

接下来告诉大家怎么来实现它

1、重新建立一个Writer.php 类 暂定目录存 app\Utils\Monolog

<?php

namespace App\Utils\Monolog;

use Illuminate\Log\Writer as BaseWriter;
use Monolog\Formatter\LineFormatter;

/**
 * 时间精确到微秒
 *
 * @package app.Utils.Monolog
 */
class Writer extends BaseWriter
{

    /**
     * Get a default Monolog formatter instance.
     *
     * @return \Monolog\Formatter\LineFormatter
     */
    protected function getDefaultFormatter()
    {
        return new LineFormatter(null, 'Y-m-d H:i:s.u', true, true);
    }

2、建立处理程序IntrospectionProcessor.php 目录app\Utils\Monolog\Processor

<?php

namespace App\Utils\Monolog\Processor;

use Monolog\Logger;

/**
 * Monolog用处理模块
 * 标准IntrospectionProcessor的简化版
 *
 * @package app.Utils.Monolog.Processor
 */
class IntrospectionProcessor
{
    private $level;

    private $skipClassesPartials;

    public function __construct($level = Logger::DEBUG, array $skipClassesPartials = ['Monolog\\', 'Illuminate\\'])
    {
        $this->level = Logger::toMonologLevel($level);
        $this->skipClassesPartials = $skipClassesPartials;
    }

    /**
     * @param  array $record
     * @return array
     */
    public function __invoke(array $record)
    {
        // return if the level is not high enough
        if ($record['level'] < $this->level) {
            return $record;
        }

        $trace = debug_backtrace();

        // skip first since it's always the current method
        array_shift($trace);
        // the call_user_func call is also skipped
        array_shift($trace);

        $i = 0;

        while (isset($trace[$i]['class'])) {
            foreach ($this->skipClassesPartials as $part) {
                if (strpos($trace[$i]['class'], $part) !== false) {
                    $i++;
                    continue 2;
                }
            }
            break;
        }

        $line = null;
        if (isset($trace[$i]['class'])) {
            $line = $trace[$i]['class'];
            if (isset($trace[$i]['class'])) {
                $line = $line . '->' . $trace[$i]['function'];
            }
        } else if (isset($trace[$i - 1]['file'])) {
            $line = $trace[$i - 1]['file'];
        }
        if (null !== $line && isset($trace[$i - 1]['line'])) {
            $line = $line . ':' . $trace[$i - 1]['line'];
        }

        $record['extra']['file'] = $line;
        $record['extra']['line'] = $trace[$i - 1]['line'];
        $record['extra']['ip'] = $_SERVER["REMOTE_ADDR"];
        return $record;
    }
}

3、建立 处理模块 ProcessIdProcessor.php 目录 app\Utils\Monolog\Processor

<?php

namespace App\Utils\Monolog\Processor;

/**
 * Monolog用处理模块
 * 标准IntrospectionProcessor的简化版, 原输出键值文字长度过长
 *
 * @package app.Utils.Monolog.Processor
 */
class ProcessIdProcessor
{
    /**
     * @param  array $record
     * @return array
     */
    public function __invoke(array $record)
    {
        $record['extra']['pid'] = getmypid();

        return $record;
    }
}

4、建立 ServiceProvider 文件 LogServiceProvider.php 目录 app\Providers

<?php
namespace App\Providers;

use Monolog\Logger as Monolog;
use Illuminate\Support\ServiceProvider;
use App\Utils\Monolog\Writer;

class LogServiceProvider extends ServiceProvider
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('log', function () {
            return $this->createLogger();
        });
    }

    /**
     * Create the logger.
     *
     * @return \Illuminate\Log\Writer
     */
    public function createLogger()
    {
        $processors = [
            new \App\Utils\Monolog\Processor\ProcessIdProcessor(),
            new \App\Utils\Monolog\Processor\IntrospectionProcessor()
        ];

        $log = new \App\Utils\Monolog\Writer(
            new Monolog($this->channel(), [], $processors), $this->app['events']
        );

        if ($this->app->hasMonologConfigurator()) {
            call_user_func($this->app->getMonologConfigurator(), $log->getMonolog());
        } else {
            $this->configureHandler($log);
        }
        return $log;
    }

    /**
     * Get the name of the log "channel".
     *
     * @return string
     */
    protected function channel()
    {
        return $this->app->bound('env') ? $this->app->environment() : 'production';
    }

    /**
     * Configure the Monolog handlers for the application.
     *
     * @param  \Illuminate\Log\Writer  $log
     * @return void
     */
    protected function configureHandler(Writer $log)
    {
        $this->{'configure'.ucfirst($this->handler()).'Handler'}($log);
    }

    /**
     * Configure the Monolog handlers for the application.
     *
     * @param  \Illuminate\Log\Writer  $log
     * @return void
     */
    protected function configureSingleHandler(Writer $log)
    {
        $log->useFiles(
            $this->app->storagePath().'/logs/laravel.log',
            $this->logLevel()
        );
    }

    /**
     * Configure the Monolog handlers for the application.
     *
     * @param  \Illuminate\Log\Writer  $log
     * @return void
     */
    protected function configureDailyHandler(Writer $log)
    {
        $log->useDailyFiles(
            $this->app->storagePath().'/logs/laravel.log', $this->maxFiles(),
            $this->logLevel()
        );
    }

    /**
     * Configure the Monolog handlers for the application.
     *
     * @param  \Illuminate\Log\Writer  $log
     * @return void
     */
    protected function configureSyslogHandler(Writer $log)
    {
        $log->useSyslog('laravel', $this->logLevel());
    }

    /**
     * Configure the Monolog handlers for the application.
     *
     * @param  \Illuminate\Log\Writer  $log
     * @return void
     */
    protected function configureErrorlogHandler(Writer $log)
    {
        $log->useErrorLog($this->logLevel());
    }

    /**
     * Get the default log handler.
     *
     * @return string
     */
    protected function handler()
    {
        if ($this->app->bound('config')) {
            return $this->app->make('config')->get('app.log', 'single');
        }

        return 'single';
    }

    /**
     * Get the log level for the application.
     *
     * @return string
     */
    protected function logLevel()
    {
        if ($this->app->bound('config')) {
            return $this->app->make('config')->get('app.log_level', 'debug');
        }

        return 'debug';
    }

    /**
     * Get the maximum number of log files for the application.
     *
     * @return int
     */
    protected function maxFiles()
    {
        if ($this->app->bound('config')) {
            return $this->app->make('config')->get('app.log_max_files', 5);
        }

        return 0;
    }
}

5、最后注册新建的LogServiceProvider.php 服务到容器里面覆盖掉底层的LogServiceProvider

#打开 config/app.php在 providers数组里面添加上
App\Providers\LogServiceProvider::class,

到此大功完成,可以新建一个控制器来看看实现的效果

<?php
namespace App\Http\Controllers;
/**
 * 数据
 */
class TestController extends Controller{
    public function log()
    {
        echo "我是来测试的";
        \Log::info('我是来测试日志的', ['content' => 1111]);
        \Log::debug('我是来测试日志的');
        \Log::error('我是来测试日志的');
        \Log::warning('我是来测试日志的');
    }
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
994914376
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 1

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!