日志


简介

为了帮助你了解更多关于应用中所发生的事情,Laravel 提供了强大的日志服务来记录日志信息到文件、系统错误日志、甚至是 Slack 以便通知整个团队。

在日志引擎之下,Laravel 集成了 Monolog 日志库以便提供各种功能强大的日志处理器,从而允许你通过它们来定制自己应用的日志处理。

配置

应用日志系统的所有配置都存放在配置文件 config/logging.php 中,该文件允许你配置应用的日志通道,因此请务必查看每个可用通道及其配置项。下面我们就来看看其中某些配置项。

默认情况下,Laravel 使用 stack 通道来记录日志信息,stack 通道被用于聚合多个日志通道到单个通道,更多关于构建 stack 的信息,请查看下面的文档

配置通道名称

默认情况下,Monolog 通过与当前环境匹配的「通道名称」实例化,例如 productionlocal,要改变这个值,添加 name 项到通道配置:

'stack' => [
    'driver' => 'stack',
    'name' => 'channel-name',
    'channels' => ['single', 'slack'],
],

有效通道驱动列表

名称 描述
stack 用于创建「多通道」通道的聚合器
single 基于单文件/路径的日志通道(StreamHandler
daily 基于 RotatingFileHandler 的 Monolog 驱动,以天为维度对日志进行分隔
slack 基于 SlackWebhookHandler 的 Monolog 驱动
papertrail 基于 SyslogUdpHandler 的 Monolog 驱动
syslog 基于 SyslogHandler 的 Monolog 驱动
errorlog 基于 ErrorLogHandler 的 Monolog 驱动
monolog Monolog 改成驱动,可以使用所有支持的 Monolog 处理器
custom 调用指定改成创建通道的驱动

注:查看高级通道自定义文档学习 monologcustom 驱动。

配置 Single 和 Daily 通道

singledaily 通道有三个可选配置项:bubblepermissionlocking

名称 描述 默认值
bubble 表示消息在被处理后是否冒泡到其它通道 true
permission 日志文件权限 0644
locking 在日志文件写入前尝试锁定它 false

配置 Papertrail 通道

papertrail 通道要求 urlport 配置选项,你可以从 Papertrail 中获取这些值。

配置 Slack 通道

slack 通道需要一个 url 配置项,这个 URL 需要和你配置的 Slack 团队请求 URL 相匹配。默认情况下,Slack 只会接收 critical 级别(及以上)的日志,不过,你可以在配置文件的 logging 选项中进行调整。

构建日志堆栈

如上所述,stack 驱动允许你将多个通道合并到单个日志通道,为了说明如何实现,让我们看一个你可能在生产环境中看到的示例配置:

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

我们来剖析这个配置。首先,注意 stack 通道通过 channels 项将聚合了其他两个通道:syslogslack。因此,记录日志信息时,这两个通道都有机会记录信息。

日志级别

注意上述示例中 syslogslack 通道配置中出现的 level 配置项,这个配置项决定了日志信息被通道记录所必须达到的最低「级别」。为 Laravel 提供日志服务的 Monolog,支持定义在 RFC 5424 规范中的所有日志级别:emergencyalertcriticalerrorwarningnoticeinfodebug

因此,假设我们使用 debug 方法来记录日志信息:

Log::debug('An informational message.');

鉴于我们的配置,syslog 通道将会将信息记录到系统日志;不过,由于错误消息不是 critical 或更高级别,将不会发送到 Slack。但是,如果我们记录的是 emergency 级别的信息,就会被发送到系统日志和 Slack,因为 emergency 级别高于两个通道的最低级别门槛:

Log::emergency('The system is down!');

写入日志信息

你可以使用 Log 门面记录日志信息,如上所述,日志系统提供了定义在 RFC 5424 规范中的八种日志级别:emergencyalertcriticalerrorwarningnoticeinfodebug

Log::emergency($error);
Log::alert($error);
Log::critical($error);
Log::error($error);
Log::warning($error);
Log::notice($error);
Log::info($error);
Log::debug($error);

因此,你可以调用其中的任意一个方法来记录相应级别的日志信息,默认情况下,信息会被写入到通过配置文件 config/logging.php 所配置的默认通道:

<?php
    
namespace App\Http\Controllers;
    
use App\User;
use Illuminate\Support\Facades\Log;
use App\Http\Controllers\Controller;
    
class UserController extends Controller
{
    /**
     * 显示指定用户的属性
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        Log::info('Showing user profile for user: '.$id);
        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}

上下文信息

上下文数据也会以数组形式传递给日志方法,然后和日志信息一起被格式化和显示:

Log::info('User failed to login.', ['id' => $user->id]);

写入指定通道

有时候你可能希望将日志信息记录到某个通道而不是应用的默认通道。要实现这个目的,你可以使用 Log 门面上的 channel 方法来获取配置文件定义的通道并将日志写入进去:

Log::channel('slack')->info('Something happened!');

如果你想要创建一个由多个通道组成的按需日志堆栈,可以使用 stack 方法:

Log::stack(['single', 'slack'])->info('Something happened!');

高级 Monolog 通道自定义

为通道自定义 Monolog

有时候你可能需要在某个通道中完全控制 Monolog 的配置,例如,你可能想要为给定通道的处理器配置一个自定义的 Monolog FormatterInterface 实现。

作为开始,我们在通道的配置上定义一个 tap 数组,这个 tap 数组需要包含可以自定义创建后的 Monolog 实例的类列表:

'single' => [
    'driver' => 'single',
    'tap' => [App\Logging\CustomizeFormatter::class],
    'path' => storage_path('logs/laravel.log'),
    'level' => 'debug',
],

在通道上配置好 tap 项后,就可以定义自定义 Monolog 实例的类了。这个类只需要一个获取 Illuminate\Log\Logger 实例的方法:__invokeIlluminate\Log\Logger 实例会代理所有调用底层 Monolog 实例的方法:

<?php
    
namespace App\Logging;
    
class CustomizeFormatter
{
    /**
     * Customize the given logger instance.
     *
     * @param  \Illuminate\Log\Logger  $logger
     * @return void
     */
    public function __invoke($logger)
    {
        foreach ($logger->getHandlers() as $handler) {
            $handler->setFormatter(new LineFormatter(
                '[%datetime%] %channel%.%level_name%: %message% %context% %extra%'
            ));
        }
    }
}

注:所有「tap」类都通过服务容器解析,所以他们需要的所有构造函数依赖都会被自动注入。

创建 Monolog 处理器通道

Monolog 有多个可用的处理器,在某些情况下,你所想创建的日志记录器类型只不过是带有指定处理器实例的 Monolog 驱动,这些通道可以通过 monolog 驱动创建。

使用 monolog 驱动时,handler 配置项用于指定实例化哪个处理器,作为可选的处理器构造函数参数,可以使用 handler_with 配置项来设置:

'logentries' => [
    'driver'  => 'monolog',
    'handler' => Monolog\Handler\SyslogUdpHandler::class,
    'handler_with' => [
        'host' => 'my.logentries.internal.datahubhost.company.com',
        'port' => '10000',
    ],
],

Monolog 格式化工具

使用 monolog 驱动时,Monolog LineFormatter 会用作默认的格式化工具。不过,你也可以使用 formatterformatter_with 配置项自定义传入处理器的格式化工具的类型:

'browser' => [
    'driver' => 'monolog',
    'handler' => Monolog\Handler\BrowserConsoleHandler::class,
    'formatter' => Monolog\Formatter\HtmlFormatter::class,
    'formatter_with' => [
        'dateFormat' => 'Y-m-d',
    ],
],

如果你使用的是能够自己提供格式化工具的 Monolog 处理器,可以将 formatter 配置项的值设置为 default

'newrelic' => [
    'driver' => 'monolog',
    'handler' => Monolog\Handler\NewRelicHandler::class,
    'formatter' => 'default',
],

通过工厂创建通道

如果你想要定义一个完整的自定义通道从而可以完全控制 Monolog 的实例化和配置,可以在配置文件 config/logging.php 中指定一个 custom 驱动类型。此外,你的配置中还要包含一个 via 项来指定被调用来创建 Monolog 实例的工厂类:

'channels' => [
    'custom' => [
        'driver' => 'custom',
        'via' => App\Logging\CreateCustomLogger::class,
    ],
],

配置好 custom 通道后,就可以定义创建 Monolog 实例的类了,这个类只需要一个返回 Monolog 实例的方法:__invoke

<?php
    
namespace App\Logging;
    
use Monolog\Logger;
    
class CreateCustomLogger
{
    /**
     * Create a custom Monolog instance.
     *
     * @param  array  $config
     * @return \Monolog\Logger
     */
    public function __invoke(array $config)
    {
        return new Logger(...);
    }
}

点赞 取消点赞 收藏 取消收藏

<< 上一篇: 错误处理

>> 下一篇: 用户认证