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
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 1

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!