PHPMonolog教程展示了如何使用Monolog在PHP中进行日志记录。
$ php -v php -v PHP 8.1.2 (cli) (built: Aug 8 2022 07:28:23) (NTS) ...
我们使用PHP版本8.1.2。
记录
Logging是将信息写入日志文件的过程。日志文件包含有关操作系统、软件或通信中发生的各种事件的信息。
记录的目的
记录是为了以下目的:
- 信息收集
- 故障排除
- 生成统计数据
- 审计
- 分析
日志记录不仅限于识别软件开发中的错误。它还用于检测安全事件、监控策略违规、在出现问题时提供信息、查找应用程序瓶颈或生成使用数据。
要记录的事件
应记录的事件包括输入验证失败、身份验证和授权失败、应用程序错误、配置更改以及应用程序启动和关闭。
不记录的事件
不应记录的事件包括应用程序源代码、会话标识值、访问令牌、敏感的个人数据、密码、数据库连接字符串、加密密钥、银行账户和持卡人数据。
记录最佳实践
以下是日志记录的一些最佳实践:
- 日志应该有意义。
- 日志应该包含上下文。
- 日志应该是平衡的;它不应该包含太少或太多的信息。
- 记录消息应该是人类可以理解的并且可以被机器解析。
- 记录应该是结构化的并且在不同的级别完成。
- 日志记录应适应开发和生产。
- 应将更复杂的应用程序的日志记录到多个日志文件中。
PHP独白
Monolog是一个流行的PHP日志库。它允许将日志发送到文件、套接字、收件箱、数据库和各种Web服务。它实现了PSR-3接口。
$ composer req monolog/monolog
我们用composer安装Monolog。
独白结构
一个Monolog记录器实例有一个通道(名称)和一堆处理程序。处理程序负责将消息保存到文件、数据库或发送它发送邮件。
记录的消息通过处理程序堆栈。最后一个处理程序首先执行。消息的进一步传播由bubble
变量控制,该变量默认设置为true
。
消息记录是将要写入日志的一条信息。消息记录有以下几个部分:
Key | Type | Description |
---|---|---|
message | string | 日志信息。 |
level | int | 日志消息的严重性。 |
level_name | string | 日志级别的字符串表示。 |
context | array | 构造消息时传递的任意数据。 |
channel | string | 这条消息记录到的频道。 |
Monolog\DateTimeImmutable | 记录消息的日期和时间。 | |
extra | array | 一个占位符数组,处理器可以在其中放置额外的数据。 |
处理器是可用于处理日志消息的任何PHP可调用对象。它可以向记录中添加一些额外的数据。
context
是数组数据,其中包含不适合主字符串的附加信息。上下文是日志记录方法的参数(例如info
或warn
)。
Formatters用于格式化消息记录。
Monolog日志级别
日志级别用于按紧急程度对日志消息进行分类。Monolog具有以下日志级别:
- DEBUG-详细的调试信息
- INFO-有趣的事件
- NOTICE-正常但重要的事件
- WARNING-非错误的异常事件
- ERROR-不需要立即采取行动的运行时错误
- CRITICAL-关键条件
- ALERT-必须立即采取行动的事件
- EMERGENCY-紧急事件
较不严重的日志不会由具有较严重日志记录级别的处理程序处理。通过将日志级别设置为ERROR,我们会收到ERROR级别及更高级别的消息。
每个处理程序都指定了一个日志级别;默认是DEBUG
。要生成具有特定日志级别的消息,我们有方法包括info
、warn
、error和关键。由于Monolog早于PSR-3,它包含重复的方法(例如
addInfo
或addWarning
)。
独白简单例子
在第一个示例中,我们使用Streamhandler
将消息记录到文件中。
<?php require __DIR__ . '/vendor/autoload.php'; use Monolog\Handler\StreamHandler; use Monolog\Logger; $logger = new Logger('main'); $logger->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log', Logger::DEBUG)); $logger->info('First message');
该示例将信息消息写入logs/app.log
文件。
$logger = new Logger('main');
创建了一个名为main
的新记录器。
$logger->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log', Logger::DEBUG));
我们使用pushHandler
向记录器添加一个StreamHandler
。处理程序将消息写入具有DEBUG严重性的指定文件。
$logger->info('First message');
我们使用info
方法记录一条信息消息。
$ cat logs\app.log [2019-05-15 15:49:48] main.INFO: First message [] []
这是书面信息。日志消息以当前日期时间开始。其后是日志通道名称和级别。然后是消息记录。两对方括号是我们可以指定上下文和额外数据的地方。我们可以使用Monolog格式化程序自定义此输出。
Monolog控制台日志记录
我们可以将日志消息写入终端。
<?php require __DIR__ . '/vendor/autoload.php'; use Monolog\Logger; use Monolog\Handler\StreamHandler; $logger = new Logger('stderr'); $logger->pushHandler(new StreamHandler('php://stderr', Logger::WARNING)); $logger->warn('A warning message');
我们通过将php://stderr
指定给StreamHandler
来写入控制台。
独白上下文数组
Monolog上下文数组允许在用户级级别向消息记录添加信息。
<?php require __DIR__ . '/vendor/autoload.php'; use Monolog\Handler\StreamHandler; use Monolog\Logger; $logger = new Logger('main'); $logger->pushHandler(new StreamHandler('php://stderr')); $logger->info('Information message', ['user' => get_current_user()]);
info
方法的第二个参数是上下文数组。我们将当前用户添加到消息中。
$ php context_array.php [2019-05-15 15:37:56] main.INFO: Information message {"user":"Jano"} []
这是输出。
Monolog日志处理程序栈
我们可以将多个处理程序添加到堆栈中。最后添加的处理程序最先执行。
<?php require __DIR__ . '/vendor/autoload.php'; use Monolog\Handler\StreamHandler; use Monolog\Logger; $main = new Logger('main'); $main->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log')); $main->pushHandler(new StreamHandler('php://stdout', $level = Logger::DEBUG, $bubble = true)); $main->info('Information message');
在示例中,我们有两个记录器处理程序:一个文件和一个控制台处理程序。如果我们将$bubble
更改为false
,消息将不会写入logs/app.log
文件。
Monolog自定义处理器
可以使用pushProcessor
添加自定义处理器。
<?php require __DIR__ . '/vendor/autoload.php'; use Monolog\Handler\StreamHandler; use Monolog\Logger; $logger = new Logger('main'); $logger->pushHandler(new StreamHandler('php://stderr')); $logger->pushProcessor(function ($record) { $record['extra']['user'] = get_current_user(); return $record; }); $logger->info('Information message');
在示例中,我们向处理器中的消息记录添加了一些额外信息。根据文档,context和extra数据之间的区别在于context是在用户空间中提供的,而extra仅供内部使用,可以由处理器填充。
$ php custom_processor.php [2019-05-15 17:24:48] main.INFO: Information message [] {"user":"Jano"}
额外的信息被添加到输出的末尾。
MonologJsonFormatter
JsonFormatter
以JSON格式写入记录。
<?php require __DIR__ . '/vendor/autoload.php'; use Monolog\Formatter\JsonFormatter; use Monolog\Handler\StreamHandler; use Monolog\Logger; $logger = new Logger('main'); $formatter = new JsonFormatter(); $stream = new StreamHandler(__DIR__ . '/logs/app-json.log'); $stream->setFormatter($formatter); $logger->pushHandler($stream); $logger->info('Information message', ['user' => get_current_user()]);
该示例使用JsonFormatter
将信息消息写入JSON格式的文件。
$ cat logs\app-json.log {"message":"Information message","context":{"user":"Jano"},"level":200,"level_name":"INFO", "channel":"main","datetime":{"date":"2019-05-15 17:37:40.433222","timezone_type":3, "timezone":"Europe/Berlin"},"extra":[]}
这是记录的消息。
MonologLineFormatter
LineFormatter
将日志记录格式化为单行字符串。
<?php require __DIR__ . '/vendor/autoload.php'; use Monolog\Logger; use Monolog\Handler\StreamHandler; use Monolog\Formatter\LineFormatter; use Monolog\Processor\ProcessIdProcessor; $output = "[%datetime%] %channel%.%level_name%: %message% %context.user%\n"; $formatter = new LineFormatter($output); $streamHandler = new StreamHandler('php://stdout'); $streamHandler->setFormatter($formatter); $logger = new Logger('main'); $logger->pushHandler($streamHandler); $logger->info('Information message from', ['user' => get_current_user()]);
在示例中,我们使用LineFormatter
自定义消息记录。
$output = "[%datetime%] %channel%.%level_name%: %message% %context.user%\n"; $formatter = new LineFormatter($output);
我们创建自定义记录消息。它包含日期时间、通道名称、级别名称、消息和上下文数据。
$streamHandler->setFormatter($formatter);
我们使用setFormatter
将格式化程序添加到处理程序。
$ php line_format.php [2019-05-15 17:43:36] main.INFO: Information message from Jano
这是一个示例输出。
Monolog邮件日志消息
可以使用SwiftMailerHandler
发送电子邮件
$ composer req swiftmailer/swiftmailer
对于这个例子,我们需要安装swiftmailer/swiftmailer
包。
在我们的示例中,我们使用Mailtrap服务。
<?php require __DIR__ . '/vendor/autoload.php'; use Monolog\Handler\StreamHandler; use Monolog\Logger; use Monolog\Handler\SwiftMailerHandler; $transporter = new Swift_SmtpTransport('smtp.mailtrap.io', 2525, 'tls'); $transporter->setUsername('3178491df14b6d'); $transporter->setPassword('7c1d6fa59a5v08'); $mailer = new Swift_Mailer($transporter); $message = new Swift_Message('Critical message'); $message->setFrom(['approot@example.com' => 'App root']); $message->setTo(['support@example.com' => 'Support']); $logger = new Logger('main'); $logger->pushHandler(new SwiftMailerHandler($mailer, $message, Logger::CRITICAL)); $logger->critical('Could not connect to the database');
在示例中,我们使用SwiftMailerHandler
将消息记录发送到邮件收件箱。
$transporter = new Swift_SmtpTransport('smtp.mailtrap.io', 2525, 'tls'); $transporter->setUsername('3178491df14b6d'); $transporter->setPassword('7c1d6fa59a5v08');
使用Mailtrap连接详细信息,我们构建传输器。
$mailer = new Swift_Mailer($transporter);
创建了一个Swinf_Mailer
。
$message = new Swift_Message('Critical message'); $message->setFrom(['approot@example.com' => 'App root']); $message->setTo(['support@example.com' => 'Support']);
创建了一个Swift_Message
。它包含从到字段。
$logger = new Logger('main'); $logger->pushHandler(new SwiftMailerHandler($mailer, $message, Logger::CRITICAL)); $logger->critical('Could not connect to the database');
我们将SwiftMailerHandler
添加到记录器中,并使用critical
创建一条关键消息。
在本教程中,我们使用Monolog在PHP中进行日志记录。
列出所有PHP教程。