Laravel 日志
简介
为了帮助我们更多地了解应用程序中发生的事情,Laravel提供了强大的日志记录服务,使我们可以将消息记录到文件,系统错误日志甚至Slack中,从而通知整个团队。
默认情况下,Laravel使用Monolog
,它提供了多种强大的日志处理程序的支持。Laravel可以轻松配置这些处理程序,使我们可以方便的使用,并且也可以自定义日志的处理。
配置
应用程序的日志系统的所有配置都存储在配置文件config/logging.php
中。该文件允许我们配置应用程序的日志通道。我们将在下面介绍一些常见的选项。
默认情况下,Laravel在记录消息时将使用stack
通道。stack
通道用于将多个日志channel聚合为一个channel。
配置channel名称
默认情况下,Monolog
用与当前环境匹配的“channel name”实例化,例如production
或local
。要更改此值,可以channel配置中添加一个选项name
:
'stack' => [
'driver' => 'stack',
'name' => 'channel-name',
'channels' => ['single', 'slack'],
],
可用的channel驱动程序
名称 | 描述 |
---|---|
stack | 包装器,以帮助创建“多渠道”渠道 |
single | 基于单个文件或路径的记录器通道(StreamHandler) |
daily | 一个RotatingFileHandler基础的Monolog驱动程序,每天旋转 |
slack | 一个SlackWebhookHandler基础的Monolog驱动程序 |
papertrail | 一个SyslogUdpHandler基础的Monolog驱动程序 |
syslog | 一个SyslogHandler基础的Monolog驱动程序 |
errorlog | 一个ErrorLogHandler基础的Monolog驱动程序 |
monolog | 一个Monolog工厂驱动程序,可以使用任何受支持的Monolog处理程序 |
custom | 调用指定工厂创建通道的驱动程序 |
配置单通道和日常通道
在single和daily渠道有三种可选配置选项:bubble,permission,和locking。
名称 | 描述 | 默认 |
---|---|---|
bubble | 指示在处理消息后是否应将消息冒泡到其他渠道 | true |
permission | 日志文件的权限 | 0644 |
locking | 尝试在写入日志文件之前将其锁定 | false |
配置 Papertrail 通道
papertrail
通道需要url和port配置项。
配置 Slack 通道
slack
通道需要一个url配置选项。此URL应该与为Slack团队配置的传入Webhook的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选项汇总了两个其他频道:syslog
和slack
。因此,在记录消息时,这两个渠道都将有机会记录消息。
日志级别
请注意上例中 syslog 和 slack 通道配置上的level
配置选项。此选项确定消息必须由通道记录的最低“级别”。提供Laravel日志服务的Monolog提供RFC 5424规范中定义的所有日志级别:emergency
, alert
, critical
, error
, warning
, notice
, info
和 debug
。
因此,假设我们使用debug方法记录了一条消息:
Log::debug('An informational message.');
根据我们的配置,syslog
通道会将消息写入系统日志。但是,由于错误消息级别不是critical或以上,因此不会将其发送到Slack。但是,如果我们记录一条emergency
消息,则该消息将同时发送到系统日志和Slack,因为该emergency级别高于两个通道的最低级别阈值:
Log::emergency('The system is down!');
编写日志消息
我们可以使用Log Facade
将信息写入日志。如前所述,系统提供了RFC 5424规范中定义的八个记录级别:emergency
, alert
, critical
, error
, warning
, notice
, info
和 debug
:
Log::emergency($message);
Log::alert($message);
Log::critical($message);
Log::error($message);
Log::warning($message);
Log::notice($message);
Log::info($message);
Log::debug($message);
因此,我们可以调用这些方法中的任何一种来记录相应级别的消息。默认情况下,消息将被写入config/logging.php
配置文件配置的默认日志通道:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Support\Facades\Log;
class UserController extends Controller
{
/**
* Show the profile for the given user.
*
* @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 Facade中的channel方法检索并登录到配置文件中定义的任何通道:
Log::channel('slack')->info('Something happened!');
如果要创建由多个通道组成的按需日志记录堆栈,则可以使用stack
方法:
Log::stack(['single', 'slack'])->info('Something happened!');
高级Monolog频道自定义
自定义频道的Monolog
有时,我们可能需要完全控制如何为现有通道配置Monolog。例如,我们想为Monolog自定义一个FormatterInterface
接口的实现类,并且为该类配置选项。
首先,在channel配置项中定义一个tap数组,该tap数组应该包含我们自己对FormatterInterface
接口的实现类:
'single' => [
'driver' => 'single',
'tap' => [App\Logging\CustomizeFormatter::class],
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
],
通道上配置了tap选项之后,就可以去实现相关的类了。此类仅需要一个方法:__invoke
,即可接收Illuminate\Log\Logger
实例。Illuminate\Log\Logger
实例代理对底层Monolog实例的所有方法的调用:
<?php
namespace App\Logging;
use Monolog\Formatter\LineFormatter;
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有多种可用的处理程序。在某些情况下,我们希望创建的looger类型仅仅是具有特定处理程序实例的Monolog驱动程序。可以使用monolog驱动程序创建这些通道。
使用monolog驱动程序时,handler
配置选项用于指定将实例化哪个处理程序。可以使用with配置选项指定处理程序需要的任何构造函数参数:
'logentries' => [
'driver' => 'monolog',
'handler' => Monolog\Handler\SyslogUdpHandler::class,
'with' => [
'host' => 'my.logentries.internal.datahubhost.company.com',
'port' => '10000',
],
],
Monolog格式化
使用monolog驱动程序时,Monolog LineFormatter
将用作默认格式化程序。但是,我们可以使用formatter
和formatter_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实例的类。此类仅需要一个方法:__invoke
,该方法应返回Monolog实例:
<?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(...);
}
}