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

 

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