使用 Laravel 在 Stdout 和 Stderr 之间拆分日志级别

2024 年 10 月 1 日

您是否曾想过在 Laravel 中记录特定级别?当然,您可以使用 level 配置选项来指定 最低限度 级别来记录,但如果你只想要 DebugInfo 日志是否进入特定的记录器?

假设你正在编写一个 CLI,并希望将日志记录拆分为 stdoutstderr 。使用 Laravel Zero 或 Artisan 之类的程序,您可以使用以下命令来演示仅将 stderr 日志发送到某处:

php artisan my-command 2> storage/logs/stderr.log

[2024-10-01 02:48:34] development.INFO: Daemon started.
[2024-10-01 02:48:34] development.INFO: The daemon has run 1 times.
[2024-10-01 02:48:37] development.INFO: The daemon has run 2 times.
[2024-10-01 02:48:40] development.INFO: The daemon has run 3 times.
[2024-10-01 02:48:43] development.INFO: The daemon has run 4 times.

然后 stderr 日志可能看起来像下面这样:

[2024-10-01 02:48:49] development.ERROR: The daemon has run too many times. (6 times now, come on!)  
[2024-10-01 02:48:52] development.ERROR: The daemon has run too many times. (7 times now, come on!)  
[2024-10-01 02:48:55] development.ERROR: The daemon has run too many times. (8 times now, come on!)  
[2024-10-01 02:48:58] development.ERROR: The daemon has run too many times. (9 times now, come on!)  
[2024-10-01 02:49:01] development.ERROR: The daemon has run too many times. (10 times now, come on!)  
[2024-10-01 02:49:04] development.ERROR: The daemon has run too many times. (11 times now, come on!)  
[2024-10-01 02:49:07] development.ERROR: The daemon has run too many times. (12 times now, come on!)  
[2024-10-01 02:49:10] development.ERROR: The daemon has run too many times. (13 times now, come on!)  
[2024-10-01 02:49:13] development.ERROR: The daemon has run too many times. (14 times now, come on!)

配置 Laravel 过滤日志级别

配置 Laravel 的记录器来分割日志的技巧是使用 Monolog 的 过滤处理器 ,它只允许给定级别的记录通过包装的处理程序。一个直接的示例可能如下所示:

use Monolog\Handler\FilterHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Level;

// Using minimum and maximum level parameters
$handler = new FilterHandler(
    handler: new StreamHandler('php://stdout'),
    minLevelOrList: Level::Debug,
    maxLevel: Level::Info,
);

// Using a list
$handler = new FilterHandler(
    handler: new StreamHandler('php://stdout'),
    minLevelOrList: [Level::Debug, Level::Info]
);

我使用了命名参数来帮助说明如何在 Laravel 中配置 FilterHandler logging.php 配置文件。我们可以更改 stderrstdout 使用以下配置记录通道(或创建新通道),使用 stack 司机:

<?php

return [ 
    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => explode(',', env('LOG_STACK', 'stdout,stderr')),
            'ignore_exceptions' => false,
        ],

        'stdout' => [
            'driver' => 'monolog',
            'handler' => \Monolog\Handler\FilterHandler::class,
            'formatter' => env('LOG_STDOUT_FORMATTER'),
            'with' => [
                'handler' => fn () => new StreamHandler('php://stdout'),
                'minLevelOrList' => [Monolog\Level::Debug, Monolog\Level::Info],
            ],
            'processors' => [PsrLogMessageProcessor::class],
        ],

        'stderr' => [
            'driver' => 'monolog',
            'handler' => StreamHandler::class,
            'formatter' => env('LOG_STDERR_FORMATTER'),
            'with' => [
                'stream' => 'php://stderr',
            ],
            'level' => 'notice',
            'processors' => [PsrLogMessageProcessor::class],
        ],
    ],
];

注意 with 键是否与 FilterLogger 构造函数命名参数相匹配? stdout 记录器将记录调试和信息日志,而 stderr 记录器有 level 设置 notice 捕获任何 CLI 错误(通知或更高版本)。

我还想指出,Monolog 接受 Closure 来 FilterHandler 处理程序,以便包装 StreamHandler 直到使用日志通道时才会创建实例:

'handler' => fn () => new StreamHandler('php://stdout'),

当我们将日志从容器发送到日志服务时,以这种方式捕获日志对于无头/守护进程 CLI 命令很有帮助。例如,使用 JSON 格式化错误日志以供 DataDog 等服务使用。以下是您可能拥有的环境设置示例,如下所示 compose.yaml 文件:

services:
  cli:
    build:
      context: .
      dockerfile: build/Dockerfile
    # Do not output any messages to the console.
    # Only logs will be sent.
    command: ["daemon", "--quiet"]
    environment:
      LOG_CHANNEL: "stack"
      LOG_LEVEL: "info"
      LOG_STACK: "stdout,stderr"
      LOG_STDOUT_FORMATTER: "\\Monolog\\Formatter\\JsonFormatter"
      LOG_STDERR_FORMATTER: "\\Monolog\\Formatter\\JsonFormatter"

Monolog 有很多 处理程序、格式化程序和处理器 您可以在 Laravel 中配置可用的功能,并且所有常见用例都已在 logging.php 配置文件。

您可以在以下位置了解有关 Laravel 应用程序登录的更多信息 官方文档


帖子 使用 Laravel 在 Stdout 和 Stderr 之间拆分日志级别 首先出现在 Laravel 新闻

加入 Laravel 时事通讯 获取最新信息 类似这样的 Laravel 文章将直接发送到您的收件箱。