laravel 写日志 并自动 推送到elasticsearch

 参考文献

调试代码

laravel文档

laravel-elastic-scout [数据库与elasticsearch映射]

scout --> elastic

monolog的概念、用法

我写的扩展包

原理流程


1. 客户端调用 Log::info('你好啊');

2. config('logging.default') = stack 

3. config('logging.channels.stack.channels')  由于这个值是个数组,设置了 daily 跟 custom

4. 以custom为例, config('logging.channels.custom.via') = \App\Log\Handler\CreateEsLogger::class
5. \App\Log\Handler\CreateEsLogger.__invoke($config)
6. PushEsHandler->handler($recored);  $record包含Log::info()的传递的相关数据 

7.LogEsclient->write()

8. LogModel->save()

9. 把save的数据同步道 elasticsearch

app/logging.php

<?php

use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;

return [

    /*
    |--------------------------------------------------------------------------
    | Default Log Channel
    |--------------------------------------------------------------------------
    |
    | This option defines the default log channel that gets used when writing
    | messages to the logs. The name specified in this option should match
    | one of the channels defined in the "channels" configuration array.
    |
    */

    'default' => env('LOG_CHANNEL', 'stack'),

    /*
    |--------------------------------------------------------------------------
    | Log Channels
    |--------------------------------------------------------------------------
    |
    | Here you may configure the log channels for your application. Out of
    | the box, Laravel uses the Monolog PHP logging library. This gives
    | you a variety of powerful log handlers / formatters to utilize.
    |
    | Available Drivers: "single", "daily", "slack", "syslog",
    |                    "errorlog", "monolog",
    |                    "custom", "stack"
    |
    */

    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['daily', 'custom'], //注意,这里加上custom,而custom对应着elasticsearch的handler
            'ignore_exceptions' => false,
        ],

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

        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'days' => 14,
        ],

        'slack' => [
            'driver' => 'slack',
            'url' => env('LOG_SLACK_WEBHOOK_URL'),
            'username' => 'Laravel Log',
            'emoji' => ':boom:',
            'level' => 'critical',
        ],

        'papertrail' => [
            'driver' => 'monolog',
            'level' => 'debug',
            'handler' => SyslogUdpHandler::class,
            'handler_with' => [
                'host' => env('PAPERTRAIL_URL'),
                'port' => env('PAPERTRAIL_PORT'),
            ],
        ],

        'stderr' => [
            'driver' => 'monolog',
            'handler' => StreamHandler::class,
            'formatter' => env('LOG_STDERR_FORMATTER'),
            'with' => [
                'stream' => 'php://stderr',
            ],
        ],

        'syslog' => [
            'driver' => 'syslog',
            'level' => 'debug',
        ],

        'errorlog' => [
            'driver' => 'errorlog',
            'level' => 'debug',
        ],
        //elasticsearch
        'custom'  => [
            'driver' => 'custom',
            'via' => \App\Log\Handler\CreateEsLogger::class,  //用来生成elastic的日志工厂
            'url' =>  'http://es.wlcat.com', //es的超链接
            'port'=> '9200', //es的端口
            'index'=> 'laralog', //es的索引名
            'toDB' => false, //是否写入数据库
        ]
    ],

];

 

 

/*
文件: app/Log/Handler/CreateEsLogger.php
这个文件,用来当客户端调用Log::info() Log::debug() 等等不同级别的写入日志方法时候
自动调用这个类的__invoke方法,并把在logging.php配置的custom配置数组传递该函数中
这个文件做了monolog对象,该对象传递一个 推送到es的handler<PushEsHandler>

*/
<?php
namespace App\Log\Handler;

use Illuminate\Log\ParsesLogConfiguration;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\FormattableHandlerInterface;
use Monolog\Handler\HandlerInterface;
use Monolog\Logger as Monolog;

class CreateEsLogger {
    use ParsesLogConfiguration;
    /**
     * The standard date format to use when writing logs.
     *
     * @var string
     */
    protected $dateFormat = 'Y-m-d H:i:s';

    /**
     * 创建一个 Monolog 实例.
     *
     * @param  array  $config
     * @return \Monolog\Logger
     */
    public function __invoke(array $config)
    {

        return (new Monolog($config['driver'], [
            $this->prepareHandler((new PushEsHandler(
                $config['url'], $config['port'], $config['index'], $config['toDB'] ?? false, $this->level($config),
                $config['bubble'] ?? true
            )), $config),
        ]));
    }

    /**
     * Prepare the handler for usage by Monolog.
     *
     * @param  \Monolog\Handler\HandlerInterface  $handler
     * @param  array  $config
     * @return \Monolog\Handler\HandlerInterface
     */
    protected function prepareHandler(HandlerInterface $handler, array $config = [])
    {
        $isHandlerFormattable = false;

        if (Monolog::API === 1) {
            $isHandlerFormattable = true;
        } elseif (Monolog::API === 2 && $handler instanceof FormattableHandlerInterface) {
            $isHandlerFormattable = true;
        }

        if ($isHandlerFormattable && ! isset($config['formatter'])) {
            $handler->setFormatter($this->formatter());
        } elseif ($isHandlerFormattable && $config['formatter'] !== 'default') {
            $handler->setFormatter($this->app->make($config['formatter'], $config['formatter_with'] ?? []));
        }

        return $handler;
    }

    /**
     * Get a Monolog formatter instance.
     *
     * @return \Monolog\Formatter\FormatterInterface
     */
    protected function formatter()
    {
        return tap(new LineFormatter(null, $this->dateFormat, true, true), function ($formatter) {
            $formatter->includeStacktraces();
        });
    }

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章