Monolog-PHP日志记录

标准

GitHub:https://github.com/Seldaek/monolog

Monolog可以将您的日志写入到文件,套接字,收件箱,数据库和各种Web服务。请参阅下面的完整处理程序列表。特殊处理程序允许您构建高级日志记录策略。

该库继承并实现了PSR-3 接口,使您可以在自己的库中保持类型约束,以确保最大的互通性。您也可以在应用程序中使用它,以确保以后可以随时使用其他兼容的日志记录。从1.11.0开始,Monolog公共API也将接受PSR-3日志级别。内部Monolog仍然使用自己的级别方案,因为它出现早于PSR-3规范。

说明

  • Monolog 2.x适用于PHP 7.1或更高版本,Monolog ^1.0 适用于PHP 5.3+。

安装

安装最新版本

$ composer require monolog/monolog

基本用法

<?php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

// create a log channel
$log = new Logger('name');
$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));

// add records to the log
$log->warning('Foo');
$log->error('Bar'

使用说明

安装

Monolog可以在Packagist(monolog/monolog)上找到,并可以通过Composer安装。

composer require monolog/monolog

如果您不使用Composer,您可以从GitHub获取代码,并使用任何兼容PSR-0的自动加载器(例如Symfony2 ClassLoader组件)来加载Monolog类。

核心概念

每个Logger实例都有一个通道(名称)和一个处理程序堆栈。每当您向记录器添加记录时,它都会遍历处理程序堆栈。每个处理程序通过判断是否完全处理了记录来做出决定,如果完成,则停止记录的传播。

这允许灵活的日志记录设置,例如在堆栈的底部有一个处理程序StreamHandler可以记录任何内容到磁盘,而堆栈的顶部添加一个处理程序MailHandler仅在记录错误消息时发送电子邮件。处理程序还有一个$bubble属性,用于定义在处理记录时该不该阻止传播。有这样一个例子,将MailHandler‘s$bubble参数设置为false意味着,由MailHandler处理的记录将不再传到StreamHandler处理程序。

您可以创建多个Logger,每定义一个通道(例如:db,request,router,..),都会组合了各种处理程序,这些处理程序可以共享或不共享。通道在日志中反映,使您可以轻松查看或过滤记录。

每个处理程序还有一个格式化程序,默认情况下,如果您没有设置,将自动创建一个有意义的格式。格式化程序会对传入记录进行规范化和格式化,以便处理程序可以使用它们来输出有用的信息。

自定义严重性级别不可用。出于基本过滤目的,仅存在八个 RFC 5424级别(调试,信息,通知,警告,错误,严重,警报,紧急),但是对于需要灵活性的排序和其他目的,您可以添加处理器到Logger实例中,以便在处理记录之前添加一些额外信息(标签,用户IP,..)。

日志级别

Monolog支持RFC 5424描述的日志级别。

  • DEBUG(100):详细的调试信息。
  • INFO(200):有兴趣的事件。例如:用户登录,SQL日志。
  • NOTICE (250):正常但重要的事件。
  • WARNING (300):非错误的异常情况。例如:使用不推荐的API,使用不当的API,不一定错误的不良内容。
  • ERROR (400):运行错误,不需要立即处理,但需要记录和监视。
  • CRITICAL (500):危急情况。例如:应用程序组件不可用,意外异常。
  • ALERT (550):必须立即处理。例如:整个网站崩掉,数据库不可用等。这应该触发SMS警报并提醒您。
  • EMERGENCY (600):紧急情况:系统无法使用。

配置记录器

以下是一个DEBUG级别的日志记录文件和PHP调试信息的基本设置:

<?php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;

// Create the logger
$logger = new Logger('my_logger');
// Now add some handlers
$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());

// You can now use your logger
$logger->info('My logger is now ready');

我们来解释一下吧。第一步是创建将在代码中使用的记录器实例。参数是一个通道名称,当您使用多个记录器时这很有用(有关它的更多详细信息,请参见下文)。

记录器本身不知道如何处理记录。它将它委托给一些处理程序。上面的代码在堆栈中注册了两个处理程序,以允许以两种不同的方式处理记录。

请注意,FirePHPHandler首先被调用,因为它被添加到堆栈顶部。如果要覆盖其他已配置的记录器,则允许您临时添加禁用冒泡的记录器。

如果您使用Monolog独立并且正在寻找一种简单的方法来配置许多处理程序,那么theorchard / monolog-cascade 可以帮助您通过PHP数组,yaml或json配置构建复杂的日志记录配置。

在记录中添加额外数据

Monolog提供了两种不同的方法来在简单的文本消息中添加额外的信息。

使用日志记录上下文

第一种方式是上下文,允许根据上文传入数组:

<?php

$logger->info('Adding a new user', array('username' => 'Seldaek'));

简单的处理程序(例如StreamHandler)可以简单地将数组格式化为字符串,但更丰富的处理程序可以利用上下文(例如,FirePHP能够以很好的方式显示数组)。

使用处理器

第二种方法是使用处理器为所有记录添加额外数据。处理器可以是任何可调用的。他们将获取记录作为参数,并且在更改完它的extra部分后必须返回它。让我们写一个处理器并在记录中添加一些虚拟数据:

<?php

$logger->pushProcessor(function ($record) {
    $record['extra']['dummy'] = 'Hello world!';

    return $record;
});

Monolog提供了一些可在项目中使用的内置处理器。查看列表的专用章节

提示:处理器也可以在特定处理程序而不是记录器上注册,以仅应用于此处理程序。

利用渠道

通道是识别记录与应用程序的哪个部分相关的好方法。这在大型应用程序中很有用(在Symfony2中也使用MonologBu​​ndle)。

下面代码是两个记录器共享一个写入单个日志文件的处理程序。通道允许您识别发出每条记录的记录器。您可以轻松地浏览过滤此频道或该频道的日志文件。

<?php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;

// Create some handlers
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
$firephp = new FirePHPHandler();

// Create the main logger of the app
$logger = new Logger('my_logger');
$logger->pushHandler($stream);
$logger->pushHandler($firephp);

// Create a logger for the security-related stuff with a different channel
$securityLogger = new Logger('security');
$securityLogger->pushHandler($stream);
$securityLogger->pushHandler($firephp);

// Or clone the first one to only change the channel
$securityLogger = $logger->withName('security');

自定义日志格式

在Monolog中,可以轻松自定义写入文件,套接字,邮件,数据库和其他处理程序的日志格式。大多数处理程序使用

$record['formatted']

值自动放入日志设备。此值取决于格式化程序设置。您可以在预定义的格式化程序类之间进行选择,也可以自己编写(例如,用于人类可读输出的多行文本文件)。

要配置预定义的格式化程序类,只需将其设置为处理程序的字段:

// the default date format is "Y-m-d H:i:s"
$dateFormat = "Y n j, g:i a";
// the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
$output = "%datetime% > %level_name% > %message% %context% %extra%\n";
// finally, create a formatter
$formatter = new LineFormatter($output, $dateFormat);

// Create a handler
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
$stream->setFormatter($formatter);
// bind it to a logger object
$securityLogger = new Logger('security');
$securityLogger->pushHandler($stream);

您还可以在多个处理程序之间重用相同的格式化程序,并在多个记录程序之间共享这些处理程序。

处理程序,格式化程序和处理器

记录到文件和系统日志

发送提醒和电子邮件

记录特定服务器和联网日志记录

开发日志

日志记录到数据库

包装/特殊处理程序

  • FingersCrossedHandler:一个非常有趣的包装器。它将记录器作为参数,并将累积所有级别的日志记录,直到记录超过定义的严重性级别。此时,它将所有记录(包括较低严重性的记录)传递给它包装的处理程序。这意味着在实际发生错误之前,您将不会在日志中看到任何内容,但是当它发生时,您将获得完整信息,包括调试和信息记录。这为您提供了所需的所有信息,但仅在您需要时提供。
  • DeduplicationHandler:如果您在发生严重错误时发送通知或电子邮件,则非常有用。它将记录器作为参数,并将累积所有级别的日志记录,直到请求结束(或被 flush()调用)。此时,它将所有记录传递给它包装的处理程序,但前提是记录在给定时间段内是唯一的(默认为60秒)。如果记录是重复的,则简单地丢弃它们。这种情况的主要用途是出现严重故障,例如您的数据库无法访问,例如,您的所有请求都将失败,并且可能导致发送大量通知。添加此处理程序可将通知量减少到可管理级别。
  • WhatFailureGroupHandler:此处理程序扩展 GroupHandler,忽略每个子处理程序引发的异常。这允许您忽略远程tcp连接可能已经死亡但您不希望整个应用程序崩溃并且可能希望继续记录到其他处理程序的问题。
  • BufferHandler:这个处理程序将缓冲它收到的所有日志记录,直到close()被调用,此时它将调用handleBatch()它一次包装所有日志消息的处理程序。这对于一次发送包含所有记录的电子邮件非常有用,例如,而不是每个日志记录都有一封邮件。
  • GroupHandler:此处理程序将其他处理程序分组。收到的每条记录都会发送给配置的所有处理程序。
  • FilterHandler:此处理程序仅允许给定级别的记录到包装的处理程序。
  • SamplingHandler:绕过另一个处理程序,如果您只想存储其中的一些,则可以对记录进行采样。
  • NoopH​​andler:这个处理程序通过什么都不做来处理任何事情。它不会停止处理堆栈的其余部分。这可用于测试,或在覆盖配置时禁用处理程序。
  • NullHandler:它可以处理的任何记录都将被丢弃。这可以用于放置现有的处理程序堆栈以暂时禁用它。
  • PsrHandler:可用于将日志记录转发到现有的PSR-3记录器
  • TestHandler:用于测试,它记录发送给它的所有内容,并具有读取信息的访问器。
  • HandlerWrapper:一个简单的处理程序包装器,您可以继承它来轻松创建自己的包装器。

格式化程序

  • LineFormatter:将日志记录格式化为单行字符串。
  • HtmlFormatter:用于将日志记录格式化为人类可读的html表,主要适用于电子邮件。
  • NormalizerFormatter:将对象/资源规范化为字符串,以便可以轻松地序列化/编码记录。
  • ScalarFormatter:用于将日志记录格式化为标量值的关联数组。
  • JsonFormatter:将日志记录编码为json。
  • WildfireFormatter:用于将日志记录格式化为Wildfire / FirePHP协议,仅对FirePHPHandler有用。
  • ChromePHPFormatter:用于将日志记录格式化为ChromePHP格式,仅对ChromePHPHandler有用。
  • GelfMessageFormatter:用于将日志记录格式化为Gelf消息实例,仅对GelfHandler有用。
  • LogstashFormatter:用于将日志记录格式化为 logstash事件json,对于此处输入下列出的任何处理程序非常有用。
  • ElasticaFormatter:用于将日志记录格式化为Elastica \ Document对象,仅对ElasticSearchHandler有用。
  • LogglyFormatter:用于将日志记录格式化为Loggly消息,仅对LogglyHandler有用。
  • FlowdockFormatter:用于将日志记录格式化为Flowdock消息,仅对FlowdockHandler有用。
  • MongoDBFormatter:将\ DateTime实例转换为\ MongoDate,并将对象递归转换为数组,仅对MongoDBHandler有用。
  • LogmaticFormatter:用户将日志记录格式化为 Logmatic消息,仅对LogmaticHandler有用。

处理器

第三方包

文档中列出了第三方处理程序,格式化程序和处理程序 。如果您发布一个,也可以在那里添加自己的。

公用类

  • RegistryMonolog\Registry该类允许您配置全局记录器,然后可以从任何位置静态访问。它不是一个真正的最佳实践,但可以帮助一些较旧的代码库或易于使用。
  • ErrorHandlerMonolog\ErrorHandler该类允许您轻松地将Logger实例注册为异常处理程序,错误处理程序或致命错误处理程序。
  • ErrorLevelActivationStrategy:当达到某个日志级别时激活FingersCrossedHandler。
  • ChannelLevelActivationStrategy:但达到某个日志级别时激活FingersCrossedHandler,具体取决于接收日志记录的通道。

扩展Monolog

Monolog完全可扩展,允许您根据需要调整记录器。

了解日志记录

请参阅有关日志记录的页面,以了解在进一步操作之前构成日志记录的内容。这一点非常重要,因为所有处理程序/格式化程序/处理程序都需要以某种方式处理日志记录。

编写自己的处理程序

Monolog提供了许多内置处理程序。但如果您需要的那个不存在,您可以编写它并在记录器中使用它。唯一的要求是继承Monolog\Handler\HandlerInterface

让我们编写一个PDOHandler处理程序来将日志记录到数据库中。我们将扩展Monolog提供的抽象类以保持DRY(避免重复造轮子)。

<?php

use Monolog\Logger;
use Monolog\Handler\AbstractProcessingHandler;

class PDOHandler extends AbstractProcessingHandler
{
    private $initialized = false;
    private $pdo;
    private $statement;

    public function __construct(PDO $pdo, $level = Logger::DEBUG, bool $bubble = true)
    {
        $this->pdo = $pdo;
        parent::__construct($level, $bubble);
    }

    protected function write(array $record): void
    {
        if (!$this->initialized) {
            $this->initialize();
        }

        $this->statement->execute(array(
            'channel' => $record['channel'],
            'level' => $record['level'],
            'message' => $record['formatted'],
            'time' => $record['datetime']->format('U'),
        ));
    }

    private function initialize()
    {
        $this->pdo->exec(
            'CREATE TABLE IF NOT EXISTS monolog '
            .'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)'
        );
        $this->statement = $this->pdo->prepare(
            'INSERT INTO monolog (channel, level, message, time) VALUES (:channel, :level, :message, :time)'
        );

        $this->initialized = true;
    }
}

您现在可以在记录器中使用此处理程序:

<?php

$logger->pushHandler(new PDOHandler(new PDO('sqlite:logs.sqlite')));

// You can now use your logger
$logger->info('My logger is now ready');

Monolog\Handler\AbstractProcessingHandler类为处理程序提供所需的大部分逻辑,包括处理器的使用和记录的格式(这就是为什么我们用$record['formatted'],而不是$record['message'])。

日志记录结构

在monolog中,日志消息作为数组传递,例如传递给处理器或处理程序。下表描述了每条日志消息始终可用的字段。

字段类型描述
messagestring日志消息。当PsrLogMessageProcessor使用时,此字符串可能包含将被上下文中的变量替换的占位符,例如,“用户{username}登录” ['username' => 'John']作为上下文将被写为“用户John登录”。
levelint日志消息的严重级别。请参阅01-usage.md中描述的日志级别。
level_namestring日志级别的字符串表示。
contextarray随着消息的构造传递的任意数据。例如,当前用户的用户名或其IP地址。
channelstring消息将记录到的频道名称。这是使用new Logger($channel)创建记录器时传递的名称。
datetimeMonolog\DateTimeImmutable记录消息的日期和时间。类继承\DateTimeImmutable
extraarray占位符数组,处理器可以在其中放置其他数据。始终可用,但如果没有注册处理器,则为空。

contextextra看起来非常相似,他们在某种意义上说,他们都携带与日志消息有关的任意数据。主要区别在于context可以在用户区域中提供(它是Logger::addRecord()的第3个参数),而extra仅在内部并由处理器填充。处理器写入extra和不写入的原因context是为了防止覆盖任何用户提供的context数据。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

41 + = 48