跳到内容

日志记录

编辑此页

Symfony 带有两个极简的 PSR-3 日志记录器:Logger 用于 HTTP 上下文,ConsoleLogger 用于 CLI 上下文。根据 十二要素应用方法,它们将从 WARNING 级别开始的消息发送到 stderr

可以通过设置 SHELL_VERBOSITY 环境变量来更改最小日志级别

SHELL_VERBOSITY 最小日志级别
-1 ERROR
1 NOTICE
2 INFO
3 DEBUG

最小日志级别、默认输出和日志格式也可以通过将适当的参数传递给 LoggerConsoleLogger 的构造函数来更改。

Logger 类通过 logger 服务提供。要传递您的配置,您可以覆盖 “logger” 服务定义

有关 ConsoleLogger 的更多信息,请参阅使用 Logger

记录消息

要记录消息,请在您的控制器或服务中注入默认的 logger

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use Psr\Log\LoggerInterface;
// ...

public function index(LoggerInterface $logger): Response
{
    $logger->info('I just got the logger');
    $logger->error('An error occurred');

    // log messages can also contain placeholders, which are variable names
    // wrapped in braces whose values are passed as the second argument
    $logger->debug('User {userId} has logged in', [
        'userId' => $this->getUserId(),
    ]);

    $logger->critical('I left the oven on!', [
        // include extra "context" info in your logs
        'cause' => 'in_hurry',
    ]);

    // ...
}

建议向日志消息添加占位符,因为

  • 检查日志消息更容易,因为许多日志工具将除了其中一些变量值之外相同的日志消息分组在一起;
  • 翻译这些日志消息要容易得多;
  • 这对安全性更好,因为转义可以由实现以上下文感知的方式完成。

logger 服务对于不同的日志级别/优先级有不同的方法。有关 logger 上所有方法的列表,请参阅 LoggerInterface

Monolog

Symfony 与 Monolog(最流行的 PHP 日志记录库)无缝集成,以创建日志消息并将其存储在各种不同的位置,并触发各种操作。

例如,使用 Monolog,您可以配置 logger 根据消息的级别执行不同的操作(例如,当发生错误时发送电子邮件)。

运行此命令以在安装 Monolog 之前安装基于 Monolog 的 logger

1
$ composer require symfony/monolog-bundle

以下部分假设已安装 Monolog。

日志存储位置

默认情况下,当您处于 dev 环境时,日志条目会写入 var/log/dev.log 文件。

prod 环境中,日志将写入 STDERR PHP 流,这在部署到没有磁盘写入权限的服务器的现代容器化应用程序中效果最佳。

如果您希望将生产日志存储在文件中,请将日志处理器 (handler) 的 path 设置为您要使用的文件路径(例如 var/log/prod.log)。

处理器:将日志写入不同位置

logger 有一个处理器堆栈,每个处理器都可以用于将日志条目写入不同的位置(例如,文件、数据库、Slack 等)。

提示

可以配置日志“通道”,它们类似于类别。每个通道都可以有其自己的处理器,这意味着您可以将不同的日志消息存储在不同的位置。请参阅如何将消息记录到不同的文件

Symfony 在默认的 monolog.yaml 配置文件中预先配置了一些基本处理器。查看这些文件以获取一些实际示例。

此示例使用两个处理器:stream(用于写入文件)和 syslog,用于使用 syslog 函数写入日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# config/packages/prod/monolog.yaml
monolog:
    handlers:
        # this "file_log" key could be anything
        file_log:
            type: stream
            # log to var/log/(environment).log
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            # log *all* messages (debug is lowest level)
            level: debug

        syslog_handler:
            type: syslog
            # log error-level messages and higher
            level: error

这定义了一个处理器堆栈,每个处理器都按照定义的顺序调用。

注意

如果您想通过另一个配置文件覆盖 monolog 配置,您将需要重新定义整个 handlers 堆栈。两个文件中的配置无法合并,因为顺序很重要,并且合并不允许您控制顺序。

修改日志条目的处理器

一些处理器不是将日志文件写入某个位置,而是用于在将日志条目发送到其他处理器之前对其进行过滤或修改。一个强大的内置处理器称为 fingers_crossed,默认情况下在 prod 环境中使用。它存储请求期间的所有日志消息,但仅当其中一条消息达到 action_level 时才将它们传递给第二个处理器。以下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# config/packages/prod/monolog.yaml
monolog:
    handlers:
        filter_for_errors:
            type: fingers_crossed
            # if *one* log is error or higher, pass *all* to file_log
            action_level: error
            handler: file_log

        # now passed *all* logs, but only if one log is error or higher
        file_log:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"

        # still passed *all* logs, and still only logs error or higher
        syslog_handler:
            type: syslog
            level: error

现在,如果甚至一个日志条目具有 LogLevel::ERROR 级别或更高,那么该请求的所有日志条目都将通过 file_log 处理器保存到文件中。这意味着您的日志文件将包含有关问题请求的所有详细信息 - 使调试变得更加容易!

提示

名为 “file_log” 的处理器将不会包含在堆栈本身中,因为它用作 fingers_crossed 处理器的嵌套处理器。

所有内置处理器

Monolog 附带许多内置处理器,用于通过电子邮件发送日志、将日志发送到 Loggly 或在 Slack 中通知您。这些都在 MonologBundle 本身中进行了文档记录。有关完整列表,请参阅Monolog 配置

如何轮换您的日志文件

随着时间的推移,日志文件可能会变得巨大,无论是在开发过程中还是在生产环境中。一个最佳实践解决方案是使用诸如 logrotate Linux 命令之类的工具来轮换日志文件,以防止它们变得太大。

另一种选择是让 Monolog 为您轮换文件,方法是使用 rotating_file 处理器。此处理器每天创建一个新的日志文件,并且还可以自动删除旧文件。要使用它,请将您的处理器的 type 选项设置为 rotating_file

1
2
3
4
5
6
7
8
9
10
# config/packages/prod/monolog.yaml
monolog:
    handlers:
        main:
            type:  rotating_file
            path:  '%kernel.logs_dir%/%kernel.environment%.log'
            level: debug
            # max number of log files to keep
            # defaults to zero, which means infinite files
            max_files: 10

在服务中使用 Logger

如果您的应用程序使用服务自动配置,则任何类实现 Psr\Log\LoggerAwareInterface 的服务都将收到对其 setLogger() 方法的调用,并将默认的 logger 服务作为服务传递。

如果您想在自己的服务中使用预配置的 logger,该 logger 使用特定通道(默认情况下为 app),您可以自动装配 monolog 通道,或者使用带有 channel 属性的 monolog.logger 标签,如 依赖注入参考中所述。

向每个日志添加额外数据(例如,唯一的请求令牌)

Monolog 还支持处理器:可以动态地向您的日志条目添加额外信息的函数。

有关详细信息,请参阅如何通过处理器向日志消息添加额外数据

处理长时间运行进程中的日志

在长时间运行的进程中,日志可能会累积到 Monolog 中,并导致一些缓冲区溢出、内存增加,甚至不合逻辑的日志。可以使用 Monolog\Logger 实例上的 reset() 方法清除 Monolog 内存中的数据。这通常应该在长时间运行的进程正在处理的每个作业或任务之间调用。

本作品,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本