原文: https://zetcode.com/php/monolog/

PHP Monolog 教程展示了如何使用 Monolog 在 PHP 中进行日志记录。

记录

日志记录是将信息写入日志文件的过程。 日志文件包含有关在操作系统,软件或通信中发生的各种事件的信息。

记录目的

完成记录是出于以下目的:

  • 信息收集
  • 故障排除
  • 产生统计数据
  • 审计
  • 性能分析

记录不仅限于识别软件开发中的错误。 它还可用于检测安全事件,监视策略违规,在出现问题时提供信息,查找应用瓶颈或生成使用情况数据。

要记录的事件

应记录的事件包括输入验证失败,认证和授权失败,应用错误,配置更改以及应用启动和关闭。

不记录的事件

不应记录的事件包括应用源代码,会话标识值,访问令牌,敏感的个人数据,密码,数据库连接字符串,加密密钥,银行帐户和持卡人数据。

记录最佳做法

以下是一些日志记录最佳做法:

  • 日志记录应该有意义。
  • 日志应包含上下文。
  • 日志应保持平衡; 它不应包含过多或过多的信息。
  • 记录消息应该是人类可以理解的,并且可以被机器解析。
  • 日志记录应在不同级别进行结构化和完成。
  • 日志应适应开发和生产。
  • 记录更复杂的应用应产生几个日志文件。

PHP Monolog

Monolog 是流行的 PHP 日志记录库。 它允许将日志发送到文件,套接字,收件箱,数据库和各种 Web 服务。 它实现了 PSR-3 接口。

  1. $ composer req monolog/monolog

我们用 Composer 安装 Monolog。

Monolog 结构

Monolog 记录器实例具有通道(名称)和处理器的栈。 处理器负责将消息保存到文件,数据库或将其发送到邮件。

记录的消息在处理器栈中传播。 最后一个处理器首先执行。 消息的进一步传播由bubble变量控制,该变量默认设置为true

消息记录是一条将要写入日志的信息。 消息记录包含以下部分:

类型 描述
info string 日志消息。
level integer 日志消息的严重性。
level_name string 日志级别的字符串表示形式。
context array 随消息的构造传递任意数据。
channel string 此消息被登录到的频道。
datetime Monolog/DateTimeImmutable 消息记录的日期和时间。
extra array 处理器可在其中放置其他数据的占位符数组。

处理器是可用于处理日志消息的任何 PHP 可调用对象。 它可以向记录中添加一些额外的数据。

context是数组数据,其中包含的附加信息不太适合主字符串。 上下文是日志记录方法的参数(例如info()warn())。

格式化程序用于格式化消息记录。

Monolog 日志级别

日志记录级别用于按紧急程度对日志消息进行分类。 Monolog 具有以下日志级别:

  • DEBUG - 详细的调试信息
  • INFO - 有趣的事件
  • NOTICE - 正常但重要的事件
  • WARNING - 并非错误的特殊情况
  • ERROR - 不需要立即采取措施的运行时错误
  • CRITICAL - 关键条件
  • ALERT - 必须立即采取措施的事件
  • EMERGENCY - 紧急事件

日志级别较低的处理器将不处理不太严重的日志。 通过将日志级别设置为ERROR,我们将获得ERROR级别及更高级别的消息。

每个处理器都指定了一个日志级别; 默认值为DEBUG。 为了产生具有特定日志级别的消息,我们有包括info()warn()error()critical()的方法。 由于 Monolog 早于 PSR-3,因此它包含重复的方法(例如addInfo()addWarning())。

Monolog 简单示例

在第一个示例中,我们使用Streamhandler将消息记录到文件中。

simple.php

  1. <?php
  2. require __DIR__ . '/vendor/autoload.php';
  3. use Monolog\Handler\StreamHandler;
  4. use Monolog\Logger;
  5. $logger = new Logger('main');
  6. $logger->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log', Logger::DEBUG));
  7. $logger->info('First message');

该示例将信息消息写入logs/app.log文件。

  1. $logger = new Logger('main');

创建了一个名为main的新记录器。

  1. $logger->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log', Logger::DEBUG));

我们使用pushHandler()StreamHandler添加到记录器。 处理器以DEBUG严重性将消息写入指定的文件。

  1. $logger->info('First message');

我们使用info()方法记录一条信息消息。

  1. $ cat logs\app.log
  2. [2019-05-15 15:49:48] main.INFO: First message [] []

这是书面信息。 日志消息以当前日期时间开头。 后面是日志通道名称和级别。 然后是消息记录。 两对方括号是我们可以指定上下文和额外数据的位置。 我们可以使用 Monolog 格式化程序自定义此输出。

Monolog 控制台日志记录

我们可以将日志消息写入终端。

console_log.php

  1. <?php
  2. require __DIR__ . '/vendor/autoload.php';
  3. use Monolog\Logger;
  4. use Monolog\Handler\StreamHandler;
  5. $logger = new Logger('stderr');
  6. $logger->pushHandler(new StreamHandler('php://stderr', Logger::WARNING));
  7. $logger->warn('A warning message');

我们通过向StreamHandler指定php://stderr来写入控制台。

Monolog 上下文数组

Monolog 上下文数组允许在用户级级别将信息添加到消息记录中。

context_array.php

  1. <?php
  2. require __DIR__ . '/vendor/autoload.php';
  3. use Monolog\Handler\StreamHandler;
  4. use Monolog\Logger;
  5. $logger = new Logger('main');
  6. $logger->pushHandler(new StreamHandler('php://stderr'));
  7. $logger->info('Information message', ['user' => get_current_user()]);

info()方法的第二个参数是上下文数组。 我们将当前用户添加到消息中。

  1. $ php context_array.php
  2. [2019-05-15 15:37:56] main.INFO: Information message {"user":"Jano"} []

这是输出。

Monolog 记录器处理器栈

我们可以将多个处理器添加到栈中。 最后添加的处理器将首先执行。

handler_stack.php

  1. <?php
  2. require __DIR__ . '/vendor/autoload.php';
  3. use Monolog\Handler\StreamHandler;
  4. use Monolog\Logger;
  5. $main = new Logger('main');
  6. $main->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log'));
  7. $main->pushHandler(new StreamHandler('php://stdout', $level = Logger::DEBUG,
  8. $bubble = true));
  9. $main->info('Information message');

在示例中,我们有两个记录器处理器:一个文件和一个控制台处理器。 如果将$bubble更改为false,则消息将不会写入logs/app.log文件。

Monolog 定制处理器

可以向pushProcessor()添加自定义处理器。

custom_processor.php

  1. <?php
  2. require __DIR__ . '/vendor/autoload.php';
  3. use Monolog\Handler\StreamHandler;
  4. use Monolog\Logger;
  5. $logger = new Logger('main');
  6. $logger->pushHandler(new StreamHandler('php://stderr'));
  7. $logger->pushProcessor(function ($record) {
  8. $record['extra']['user'] = get_current_user();
  9. return $record;
  10. });
  11. $logger->info('Information message');

在示例中,我们向处理器中的消息记录添加了一些额外的信息。 根据文档,上下文和额外数据之间的区别在于上下文是在用户区域中提供的,而额外数据仅是内部的,可以由处理器填充。

  1. $ php custom_processor.php
  2. [2019-05-15 17:24:48] main.INFO: Information message [] {"user":"Jano"}

额外的信息将添加到输出的末尾。

Monolog JsonFormatter

JsonFormatter以 JSON 格式写入记录。

json_formatter.php

  1. <?php
  2. require __DIR__ . '/vendor/autoload.php';
  3. use Monolog\Formatter\JsonFormatter;
  4. use Monolog\Handler\StreamHandler;
  5. use Monolog\Logger;
  6. $logger = new Logger('main');
  7. $formatter = new JsonFormatter();
  8. $stream = new StreamHandler(__DIR__ . '/logs/app-json.log');
  9. $stream->setFormatter($formatter);
  10. $logger->pushHandler($stream);
  11. $logger->info('Information message', ['user' => get_current_user()]);

该示例使用JsonFormatter将信息消息以 JSON 格式写入文件。

  1. $ cat logs\app-json.log
  2. {"message":"Information message","context":{"user":"Jano"},"level":200,"level_name":"INFO",
  3. "channel":"main","datetime":{"date":"2019-05-15 17:37:40.433222","timezone_type":3,
  4. "timezone":"Europe/Berlin"},"extra":[]}

这是记录的消息。

Monolog LineFormatter

LineFormatter将日志记录格式化为单行字符串。

line_format.php

  1. <?php
  2. require __DIR__ . '/vendor/autoload.php';
  3. use Monolog\Logger;
  4. use Monolog\Handler\StreamHandler;
  5. use Monolog\Formatter\LineFormatter;
  6. use Monolog\Processor\ProcessIdProcessor;
  7. $output = "[%datetime%] %channel%.%level_name%: %message% %context.user%\n";
  8. $formatter = new LineFormatter($output);
  9. $streamHandler = new StreamHandler('php://stdout');
  10. $streamHandler->setFormatter($formatter);
  11. $logger = new Logger('main');
  12. $logger->pushHandler($streamHandler);
  13. $logger->info('Information message from', ['user' => get_current_user()]);

在示例中,我们使用LineFormatter自定义消息记录。

  1. $output = "[%datetime%] %channel%.%level_name%: %message% %context.user%\n";
  2. $formatter = new LineFormatter($output);

我们创建一个自定义记录消息。 它包含日期时间,频道名称,级别名称,消息和上下文数据。

  1. $streamHandler->setFormatter($formatter);

我们使用setFormatter()将格式化程序添加到处理器中。

  1. $ php line_format.php
  2. [2019-05-15 17:43:36] main.INFO: Information message from Jano

这是一个示例输出。

Monolog 邮件日志消息

可以使用SwiftMailerHandler发送电子邮件

  1. $ composer req swiftmailer/swiftmailer

对于此示例,我们需要安装swiftmailer/swiftmailer包。

注意:Gmail 不是理想的测试应用。 我们应该使用诸如 Mailtrap 或 Mailgun 之类的在线服务,或者使用由网络托管公司提供的 SMTP 服务器。

在我们的示例中,我们使用 Mailtrap 服务。

mail_log.php

  1. <?php
  2. require __DIR__ . '/vendor/autoload.php';
  3. use Monolog\Handler\StreamHandler;
  4. use Monolog\Logger;
  5. use Monolog\Handler\SwiftMailerHandler;
  6. $transporter = new Swift_SmtpTransport('smtp.mailtrap.io', 2525, 'tls');
  7. $transporter->setUsername('3178491df14b6d');
  8. $transporter->setPassword('7c1d6fa59a5v08');
  9. $mailer = new Swift_Mailer($transporter);
  10. $message = new Swift_Message('Critical message');
  11. $message->setFrom(['approot@example.com' => 'App root']);
  12. $message->setTo(['support@example.com' => 'Support']);
  13. $logger = new Logger('main');
  14. $logger->pushHandler(new SwiftMailerHandler($mailer, $message, Logger::CRITICAL));
  15. $logger->critical('Could not connect to the database');

在示例中,我们使用SwiftMailerHandler将消息记录发送到邮件收件箱。

  1. $transporter = new Swift_SmtpTransport('smtp.mailtrap.io', 2525, 'tls');
  2. $transporter->setUsername('3178491df14b6d');
  3. $transporter->setPassword('7c1d6fa59a5v08');

使用 Mailtrap 连接详细信息,我们构建了传输器。

  1. $mailer = new Swift_Mailer($transporter);

创建了Swinf_Mailer

  1. $message = new Swift_Message('Critical message');
  2. $message->setFrom(['approot@example.com' => 'App root']);
  3. $message->setTo(['support@example.com' => 'Support']);

创建了Swift_Message。 它包含从到字段。

  1. $logger = new Logger('main');
  2. $logger->pushHandler(new SwiftMailerHandler($mailer, $message, Logger::CRITICAL));
  3. $logger->critical('Could not connect to the database');

我们将SwiftMailerHandler添加到记录器,并使用critical()创建关键消息。

您可能也对以下相关教程感兴趣: PHP Rakit 验证教程PHP PDO 教程PHP 教程或列出所有 PHP 教程。

在本教程中,我们使用 Monolog 在 PHP 中进行日志记录。