日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

【Laravel系列7.1】日志

 硬核項(xiàng)目經(jīng)理 2022-05-26 發(fā)布于湖南

日志

對(duì)于一個(gè)框架系統(tǒng)來說,日志和異常處理可以說是非常重要的一個(gè)功能組件。我們的項(xiàng)目不管大還是小,對(duì)于錯(cuò)誤異常都應(yīng)該是零容忍的狀態(tài)。異常處理機(jī)制可以幫助我們及時(shí)發(fā)現(xiàn)問題,并且將問題記錄到日志中。而日志可以幫助我們掌握系統(tǒng)的運(yùn)行情況,查找問題原因??傊?,日志和異常處理是在系統(tǒng)的運(yùn)維狀態(tài)中非常重要的兩個(gè)功能。

日志記錄

Laravel 中的日志功能的使用非常簡(jiǎn)單,我們前面講過的門面就可以直接使用。它是基于 Monolog 來實(shí)現(xiàn)的,底層就是一套 Monolog ,如果有使用過這個(gè)日志框架的同學(xué)學(xué)起來會(huì)非常輕松。

\Illuminate\Support\Facades\Log::info("記錄一條日志");

一條簡(jiǎn)單地日志就這樣記錄下來了,如果沒有進(jìn)行別的配置,那么這條日志將記錄在 storage/logs/laravel.log 里面,輸出的是這樣子的:

[2021-09-14 00:52:47] local.INFO: 記錄一條日志  

它還有第二個(gè)參數(shù),可以記錄一些上下文信息,我們也可以直接理解為記錄一些參數(shù)。

\Illuminate\Support\Facades\Log::info("記錄一條日志,加點(diǎn)參數(shù)", ['name'=>'ZyBlog']);
// [2021-09-14 00:52:47] local.INFO: 記錄一條日志,加點(diǎn)參數(shù) {"name":"ZyBlog"} 

除了 info 之外,我們還可以定義 emergency、alert、critical、error、warning、notice、info 和 debug 等類型,這也是遵循 RFC 5424 specificationhttps://datatracker./doc/html/rfc5424 的日志標(biāo)準(zhǔn)格式。至于它們的使用的話,其實(shí)和 info() 方法都是一樣的,只是在日志中最后記錄的 local.INFO 這里的名稱不同。

$message = '記錄一條日志';
\Illuminate\Support\Facades\Log::emergency($message);
\Illuminate\Support\Facades\Log::alert($message);
\Illuminate\Support\Facades\Log::critical($message);
\Illuminate\Support\Facades\Log::error($message);
\Illuminate\Support\Facades\Log::warning($message);
\Illuminate\Support\Facades\Log::notice($message);
\Illuminate\Support\Facades\Log::debug($message);
// [2021-09-14 01:09:31] local.EMERGENCY: 記錄一條日志  
// [2021-09-14 01:09:31] local.ALERT: 記錄一條日志  
// [2021-09-14 01:09:31] local.CRITICAL: 記錄一條日志  
// [2021-09-14 01:09:31] local.ERROR: 記錄一條日志  
// [2021-09-14 01:09:31] local.WARNING: 記錄一條日志  
// [2021-09-14 01:09:31] local.NOTICE: 記錄一條日志  
// [2021-09-14 01:09:31] local.DEBUG: 記錄一條日志  

日志通道

日志通道可以看成是日志的類型分類,比如說我們最常用的就是要將日志按天記錄,那么我們直接配置一個(gè) daily 就可以了,這樣所記錄的日志就不會(huì)全部記錄在一個(gè) laravel.log 文件中。首先,我們來看一下默認(rèn)情況下 Laravel 的日志配置有哪些。

return [
    'default' => env('LOG_CHANNEL''stack'),
    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['single'],
            'ignore_exceptions' => false,
        ],

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

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

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

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

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

        'syslog' => [
            'driver' => 'syslog',
            'level' => env('LOG_LEVEL''debug'),
        ],

        'errorlog' => [
            'driver' => 'errorlog',
            'level' => env('LOG_LEVEL''debug'),
        ],

        'null' => [
            'driver' => 'monolog',
            'handler' => NullHandler::class,
        ],

        'emergency' => [
            'path' => storage_path('logs/laravel.log'),
        ],
    ],

];

從配置文件中,我們可以看出,默認(rèn)的日志通道是在 .env 文件中 LOG_CHANNEL 配置屬性定義的,下面提供了一些已經(jīng)配置好的默認(rèn)日志通道。默認(rèn)情況下,我們使用的是 stack 這個(gè)通道,其實(shí)它是一個(gè)堆棧的聚合通道,在它的配置里面還有一個(gè) channels 屬性,這個(gè)里面可以配置其它通道。這樣的話,我們就可以在這一個(gè)通道中讓它配置在 channels 中的所能通道都有機(jī)會(huì)處理日志信息。比如說我們這樣配置一下。

'stack' => [
    'driver' => 'stack',
    'channels' => ['single''daily''errorlog'],
    'ignore_exceptions' => false,
],

也就是給 channels 增加了一個(gè) daily 配置。然后運(yùn)行上面的日志路由,你會(huì)發(fā)現(xiàn) storage/logs/ 目錄下多了一個(gè) laravel-2021-09-17.log 文件,這個(gè)就是按天記錄的日志文件。然后在 laravel.log 和 laravel-2021-09-17.log 中都會(huì)記錄我們的日志信息。另外還有一個(gè) errorlog ,這個(gè)通道走的是 MonoLog 的 ErrorLogHandler ,也就是會(huì)把我們的錯(cuò)誤信息寫入到 PHP 的錯(cuò)誤日志文件中,它就是你在 php.ini 中配置的那個(gè)錯(cuò)誤日志路徑。大家可以自己嘗試一下,具體的 MonoLog 相關(guān)的知識(shí)不是我們今天學(xué)習(xí)的重點(diǎn),所以就需要大家自己去查閱相關(guān)的資料咯。

名稱描述
stack一個(gè)便于創(chuàng)建『多通道』通道的包裝器
single單個(gè)文件或者基于日志通道的路徑 (StreamHandler)
daily一個(gè)每天輪換的基于 Monolog 驅(qū)動(dòng)的 RotatingFileHandler
slack一個(gè)基于 Monolog 驅(qū)動(dòng)的 SlackWebhookHandler
papertrail一個(gè)基于 Monolog 驅(qū)動(dòng)的 SyslogUdpHandler
syslog一個(gè)基于 Monolog 驅(qū)動(dòng)的 SyslogHandler
errorlog一個(gè)基于 Monolog 驅(qū)動(dòng)的 ErrorLogHandler
monolog一個(gè)可以使用任何支持 Monolog 處理程序的 Monolog 工廠驅(qū)動(dòng)程序
custom一個(gè)調(diào)用指定工廠創(chuàng)建通道的驅(qū)動(dòng)程序

這個(gè)表格的內(nèi)容還是需要大家記住的。同時(shí),我們也可以直接修改 .env 中的 LOG_CHANNEL 來單獨(dú)指定某個(gè)日志通道,比如我們?cè)诰€上經(jīng)常就只會(huì)使用一個(gè) daily 來進(jìn)行日志記錄。同時(shí),我們也可以在記錄日志時(shí)直接指定使用哪個(gè)日志通道。

\Illuminate\Support\Facades\Log::channel('errorlog')->info($message);

另外你也可以手動(dòng)創(chuàng)建一個(gè)日志棧 stack 來進(jìn)行日志處理。

\Illuminate\Support\Facades\Log::stack(['daily''errorlog'])->info($message);

自定義日志處理

我們可以直接使用上面介紹的那些日志處理通道進(jìn)行組合搭配來實(shí)現(xiàn)自己的日志操作功能,同時(shí)也可以自己來定義一個(gè)自己的日志通道。

'custom'=>[
    'driver'=>'custom',
    'via'=>App\Logging\CreateCustomLogger::class,
    'tap' => [App\Logging\CustomizeFormatter::class],
    'path' => storage_path('logs/zyblog.log'),
]

指定 driver 類型為 custom ,就可以實(shí)現(xiàn)一個(gè)你自己完全控制和配置的 Monolog 日志操作通道,在這個(gè)配置中,必須要有的是一個(gè) via 屬性,它指向?qū)⒈徽{(diào)用以創(chuàng)建 Monolog 實(shí)例的工廠類。

namespace App\Logging;

use Monolog\Handler\StreamHandler;
use Monolog\Logger;

class CreateCustomLogger
{
    public function __invoke(array $config)
    
{
        return new Logger('ZyBlog', [new StreamHandler($config['path'])]);
    }
}

在這個(gè) CreateCustomLogger 類中,我們只需要實(shí)現(xiàn) __invoke() 這個(gè)魔術(shù)方法,讓它返回一個(gè) Monolog 實(shí)例對(duì)象,就可以實(shí)現(xiàn)通道的指定類處理。在配置文件中的參數(shù)會(huì)通過 $config 變量注入進(jìn)來。比如在這段代碼中,我們就是簡(jiǎn)單地定義了一個(gè) Logger 對(duì)象,使用的處理器是 StreamHandler ,并且讓它的路徑指定為我們?cè)谂渲梦募信渲煤玫穆窂健?/p>

另外一個(gè) tap 屬性是干什么的呢?它是在通道創(chuàng)建完成之后,對(duì) Logger 對(duì)象進(jìn)行自定義處理的。因此,它的 __invoke() 方法注入進(jìn)來的就是一個(gè) Logger 對(duì)象。

namespace App\Logging;


use Monolog\Formatter\LineFormatter;

class CustomizeFormatter
{
    public function __invoke($logger)
    
{
        foreach ($logger->getHandlers() as $handler) {
            $handler->setFormatter(new LineFormatter(
                'ZYBLOG [%datetime%] %channel%.%level_name%: %message% %context% %extra%'
            ));
        }

    }
}

我們可以為這個(gè) Logger 對(duì)象進(jìn)行其它的屬性設(shè)置。在這里本身我們就是使用的自定義的通道,所以效果可能不明顯,這個(gè) tap 屬性是可以放在其它系統(tǒng)默認(rèn)提供的通道中的,比如說 single 或者 daily 中的。在這里我們只是修改了記錄的格式,使用的依然還是 LineFormatter ,但格式中有一些簡(jiǎn)單的變化。

最后,我們看一下生成的日志,它被記錄在了 storage/logs/zyblog.log 文件中。

ZYBLOG [2021-09-23T00:58:17.965496+00:00] ZyBlog.INFO: 記錄一條日志custom [] []

日志記錄分析

日志功能其實(shí)也是走的門面模式,這個(gè)已經(jīng)不用多說了,大家可以一路找到門面最后實(shí)現(xiàn)的對(duì)象,也就是 vendor/laravel/framework/src/Illuminate/Log/LogManager.php 。我們以 daily 為例,看一下這個(gè)按天分割的日志處理器是怎么定義的。

在 LogManager 中,直接找到 info() 方法,也就是我們記錄的普通日志的方法,其它方法也是類似的,所以我們就從這個(gè)方法入手。

public function info($message, array $context = [])
{
    $this->driver()->info($message, $context);
}

可以看到它調(diào)用了當(dāng)前類中的 driver() 方法的 info() 方法。

public function driver($driver = null)
{
    return $this->get($driver ?? $this->getDefaultDriver());
}

driver() 從名字就能看出是驅(qū)動(dòng)的意思,接下來,它又調(diào)用了 get() 方法。

protected function get($name)
{
    try {
        return $this->channels[$name] ?? with($this->resolve($name), function ($logger) use ($name) {
            return $this->channels[$name] = $this->tap($name, new Logger($logger, $this->app['events']));
        });
    } catch (Throwable $e) {
        return tap($this->createEmergencyLogger(), function ($logger) use ($e) {
            $logger->emergency('Unable to create configured logger. Using emergency logger.', [
                'exception' => $e,
            ]);
        });
    }
}

看著很復(fù)雜呀,其實(shí)主要就是 try 里面的內(nèi)容,如果當(dāng)前類中的 channels 變量中已經(jīng)保存了當(dāng)前指定的通道的話,那么就使用這個(gè)通道,否則的話使用 resolve() 方法去創(chuàng)建通道,接下來我們就進(jìn)入到 resolve() 方法中。

protected function resolve($name)
{
    $config = $this->configurationFor($name);

    if (is_null($config)) {
        throw new InvalidArgumentException("Log [{$name}] is not defined.");
    }

    if (isset($this->customCreators[$config['driver']])) {
        return $this->callCustomCreator($config);
    }

    $driverMethod = 'create'.ucfirst($config['driver']).'Driver';

    if (method_exists($this, $driverMethod)) {
        return $this->{$driverMethod}($config);
    }

    throw new InvalidArgumentException("Driver [{$config['driver']}] is not supported.");
}

protected function configurationFor($name)
{
    return $this->app['config']["logging.channels.{$name}"];
}

configurationFor() 方法用于從配置文件中獲取指定的通道配置信息。接下來判斷是否是自定義的通道,如果不是的話,調(diào)用一個(gè)組合起來的方法名,也就是 createXXXDriver 這樣的方法。我們要看的是 daily 這個(gè)通道,所以組合起來的應(yīng)該是 createDailyDriver 這個(gè)方法,繼續(xù)在文件中查找,果然,這個(gè)方法是存在的。

protected function createDailyDriver(array $config)
{
    return new Monolog($this->parseChannel($config), [
        $this->prepareHandler(new RotatingFileHandler(
            $config['path'], $config['days'] ?? 7$this->level($config),
            $config['bubble'] ?? true, $config['permission'] ?? null, $config['locking'] ?? false
        ), $config),
    ]);
}

重點(diǎn)需要關(guān)心的是通道的創(chuàng)建,在這里它使用的是 RotatingFileHandler() 這個(gè)通道,剩下的相信不用多說了吧,這是 Monolog 自帶的一個(gè)通道,每天創(chuàng)建一個(gè)文件,自動(dòng)刪除超時(shí)的文件。整體看下來,是不是和我們自定義日志通道配置的處理流程是一樣一樣的。

總結(jié)

通過今天的學(xué)習(xí),我們了解到了 Laravel 中日志相關(guān)處理的流程以及使用方式。這個(gè)東西吧,大家只要做了 Laravel 項(xiàng)目多少都會(huì)接觸到,只是平??赡芫褪呛?jiǎn)單地配置一下 .env 文件就完事了,并沒有深入的了解。Monolog 很強(qiáng)大,而且也很實(shí)用,但如果你想用別的日志工具,其實(shí)也可以通過之前的文章去配置 服務(wù)提供者 和 門面 來進(jìn)行方便地使用。

關(guān)于 Monolog 的內(nèi)容,將來我們?cè)賳为?dú)開小系列的文章進(jìn)行學(xué)習(xí),今天日志相關(guān)的內(nèi)容就簡(jiǎn)單地介紹到這里,下節(jié)課我們?cè)倭私庖幌?Laravel 的異常和錯(cuò)誤處理機(jī)制。

參考文檔:

https:///docs/laravel/8.x/logging/9376

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多