日志记录¶
概览¶
Phalcon\Logger\Logger是一个为应用程序提供日志服务的组件。它使用不同的适配器提供向不同后端的日志记录功能。它还提供了事务日志、配置选项和不同的日志格式。您可以使用Phalcon\Logger\Logger来满足应用程序中任何日志需求,从调试过程到跟踪应用程序流程。
The Phalcon\Logger\Logger实现的方法符合PSR-3的标准,但没有实现特定的接口。有一个实现了PSR-3的包可用,该包使用了Phalcon\Logger\Logger。该包位于点击这里。要使用它,你需要安装 Phalcon,然后通过 Composer 安装代理包。
使用代理类可以让你遵循PSR-3并在需要该接口的其他包中使用它。
The Phalcon\Logger\Logger仅实现了日志功能,并接受一个或多个负责执行日志记录工作的适配器。这种实现方式将组件的职责分离,并提供了一种简便的方法将多个适配器附加到日志组件上,从而实现向多个适配器进行日志记录。
适配器¶
此组件利用适配器存储已记录的消息。适配器的使用允许使用通用的日志接口,这提供了轻松切换后端的能力,或者在必要时使用多个适配器。支持的适配器包括:
适配器 | 描述 |
---|---|
Phalcon\Logger\Adapter\Noop | 黑洞适配器(主要用于测试) |
Phalcon\Logger\Adapter\Stream | 在文件流中记录消息 |
Phalcon\Logger\Adapter\Syslog | 向系统日志记录消息 |
流¶
当我们想将消息记录到特定文件流时会使用此适配器。该适配器结合了v3版本的Stream
和File
的特性。通常,这是最常用的一个:在文件系统中对文件进行日志记录。
系统日志¶
此适配器将消息发送至系统日志。Syslog的行为可能因操作系统不同而有所差异。
无操作¶
这是一个黑洞适配器。它将消息发送至无限且更远的地方! 此适配器主要用于测试或者如果你想要与同事开玩笑时使用。
工厂¶
您可以使用Phalcon\Logger\LoggerFactory组件用于创建日志记录器。对于Phalcon\Logger\LoggerFactory要使其正常工作,需要用一个Phalcon\Logger\AdapterFactory:
<?php
use Phalcon\Logger\LoggerFactory;
use Phalcon\Logger\AdapterFactory;
$adapterFactory = new AdapterFactory();
$loggerFactory = new LoggerFactory($adapterFactory);
load()
¶
Phalcon\Logger\LoggerFactory提供了load
方法,该方法根据提供的配置构建日志记录器。配置可以是数组,也可以是 [Phalcon\Config\Config][config] 对象。
注意
使用案例:创建一个带有两个流适配器的日志记录器。其中一个适配器将被命名为main
用于记录所有消息,而第二个适配器将被命名为admin
,仅用于记录我们应用程序管理区域生成的消息。
<?php
use Phalcon\Logger\AdapterFactory;
use Phalcon\Logger\LoggerFactory;
use Phalcon\Storage\SerializerFactory;
$config = [
"name" => "prod-logger",
"options" => [
"adapters" => [
"main" => [
"adapter" => "stream",
"name" => "/storage/logs/main.log",
"options" => []
],
"admin" => [
"adapter" => "stream",
"name" => "/storage/logs/admin.log",
"options" => []
],
],
],
];
$serializerFactory = new SerializerFactory();
$adapterFactory = new AdapterFactory();
$loggerFactory = new LoggerFactory($adapterFactory);
$logger = $loggerFactory->load($config);
newInstance()
¶
The Phalcon\Logger\LoggerFactory还提供了newInstance()
方法,该方法根据提供的名称和相关适配器数组来构建日志记录器。使用上面的用例:
<?php
use Phalcon\Logger\Adapter\Stream;
use Phalcon\Logger\AdapterFactory;
use Phalcon\Logger\LoggerFactory;
use Phalcon\Storage\SerializerFactory;
$adapters = [
"main" => new Stream("/storage/logs/main.log"),
"admin" => new Stream("/storage/logs/admin.log"),
];
$serializerFactory = new SerializerFactory();
$adapterFactory = new AdapterFactory($serializerFactory);
$loggerFactory = new LoggerFactory($adapterFactory);
$logger = $loggerFactory->newInstance('prod-logger', $adapters);
创建日志记录器¶
创建一个日志记录器是一个多步骤的过程。首先,您创建日志记录器对象,然后将其与一个适配器绑定。之后,您可以根据应用程序的需求开始记录消息。
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
$adapter = new Stream('/storage/logs/main.log');
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$logger->error('Something went wrong');
上述示例创建了一个流适配器。接着我们创建一个日志记录器对象并将其与此适配器绑定。每个绑定到日志记录器的适配器都需要具有唯一的名称,以便日志记录器能够知道将消息记录到哪里。当调用error()
方法时,消息将会被保存到/storage/logs/main.log
.
中。
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
$adapter = new Stream('/storage/logs/main.log');
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$logger->alert("This is an alert message");
$logger->critical("This is a critical message");
$logger->debug("This is a debug message");
$logger->error("This is an error message");
$logger->emergency("This is an emergency message");
$logger->info("This is an info message");
$logger->log(Logger::CRITICAL, "This is a log message");
$logger->notice("This is a notice message");
$logger->warning("This is a warning message");
[Tue, 25 Dec 18 12:13:14 -0400][ALERT] This is an alert message
[Tue, 25 Dec 18 12:13:14 -0400][CRITICAL] This is a critical message
[Tue, 25 Dec 18 12:13:14 -0400][DEBUG] This is a debug message
[Tue, 25 Dec 18 12:13:14 -0400][ERROR] This is an error message
[Tue, 25 Dec 18 12:13:14 -0400][EMERGENCY] This is an emergency message
[Tue, 25 Dec 18 12:13:14 -0400][INFO] This is an info message
[Tue, 25 Dec 18 12:13:14 -0400][CRITICAL] This is a log message
[Tue, 25 Dec 18 12:13:14 -0400][NOTICE] This is a notice message
[Tue, 25 Dec 18 12:13:14 -0400][WARNING] This is warning message
多个适配器¶
Phalcon\Logger\Logger可以通过一次调用将消息发送给多个适配器:
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
$adapter1 = new Stream('/logs/first-log.log');
$adapter2 = new Stream('/remote/second-log.log');
$adapter3 = new Stream('/manager/third-log.log');
$logger = new Logger(
'messages',
[
'local' => $adapter1,
'remote' => $adapter2,
'manager' => $adapter3,
]
);
$logger->error('Something went wrong');
消息按照通过先进先出原则注册的顺序发送给处理程序。
排除适配器¶
Phalcon\Logger\Logger还提供了在记录消息时排除一个或多个适配器的能力。这在需要将某个manager
相关消息记录到manager
日志中但不记录到local
日志中的情况下特别有用,无需实例化新的日志记录器即可完成这一操作。
使用以下设置:
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
$adapter1 = new Stream('/logs/first-log.log');
$adapter2 = new Stream('/remote/second-log.log');
$adapter3 = new Stream('/manager/third-log.log');
$logger = new Logger(
'messages',
[
'local' => $adapter1,
'remote' => $adapter2,
'manager' => $adapter3,
]
);
我们有如下情况:
记录到所有适配器 仅记录到 remote 和 manager注意
在内部,组件会遍历注册的适配器并调用相关的日志记录方法以实现对多个适配器的日志记录。如果其中任何一个适配器失败,遍历过程将中断,其余适配器(在循环中)将不会记录此消息。在未来的 Phalcon 版本中,我们将引入异步日志记录以解决这个问题。
常量¶
该类提供了一系列常量,可用于区分不同的日志级别。这些常量还可以作为log()
方法设置容器。
常量 | 值 |
---|---|
EMERGENCY | 0 |
CRITICAL | 1 |
ALERT | 2 |
ERROR | 3 |
WARNING | 4 |
NOTICE | 5 |
INFO | 6 |
DEBUG | 7 |
CUSTOM | 8 |
日志级别¶
Phalcon\Logger\Logger允许您设置日志记录器的日志最低级别。如果您设置了这个整数值,则高于设定值的任何级别都不会被记录。请参阅前一节中的常量值以了解级别的排序。
在下面的示例中,我们将日志级别设置为ALERT
。我们只能看到EMERGENCY
, CRITICAL
, 和 ALERT
消息。
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
$adapter = new Stream('/storage/logs/main.log');
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$logger->setLogLevel(Logger::ALERT);
$logger->alert("This is an alert message");
$logger->critical("This is a critical message");
$logger->debug("This is a debug message");
$logger->error("This is an error message");
$logger->emergency("This is an emergency message");
$logger->info("This is an info message");
$logger->log(Logger::CRITICAL, "This is a log message");
$logger->notice("This is a notice message");
$logger->warning("This is a warning message");
[Tue, 25 Dec 18 12:13:14 -0400][ALERT] This is an alert message
[Tue, 25 Dec 18 12:13:14 -0400][CRITICAL] This is a critical message
[Tue, 25 Dec 18 12:13:14 -0400][EMERGENCY] This is an emergency message
[Tue, 25 Dec 18 12:13:14 -0400][CRITICAL] This is a log message
上述方法可用于根据您的应用程序条件(例如开发模式与生产模式)只记录某个严重程度以上的消息的情况。
注意
设置的日志级别包含在日志记录中。任何低于该级别的内容(即数字更大)将不会被记录
注意
这是永远都不建议在应用中抑制日志级别,因为即使是警告错误也需要消耗 CPU 周期来处理,忽略这些错误可能会导致意外情况的发生
事务¶
Phalcon\Logger\Logger同时也提供了将消息排队到你的日志记录器中的能力,然后提交所有消息一起写入日志文件。这类似于数据库事务中的begin
和commit
。每个适配器暴露了以下方法:
名称 | 描述 |
---|---|
begin(): void | 开始日志事务 |
inTransaction(): bool | 是否处于事务中 |
commit(): void | 将所有排队的消息写入日志文件 |
由于该功能是在适配器级别提供的,你可以基于每个适配器来编程你的日志记录器使用事务。
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
$adapter1 = new Stream('/logs/first-log.log');
$adapter2 = new Stream('/remote/second-log.log');
$adapter3 = new Stream('/manager/third-log.log');
$logger = new Logger(
'messages',
[
'local' => $adapter1,
'remote' => $adapter2,
'manager' => $adapter3,
]
);
$logger->getAdapter('manager')->begin();
$logger->error('Something happened');
$logger->getAdapter('manager')->commit();
manager
日志记录器设置为事务模式。当我们调用: 消息将在两个local
和remote
适配器中都被记录。它将被排队到manager
适配器,并且直到我们调用commit
方法,在manager
适配器之前都不会被记录。 注意
如果你将一个或多个适配器设置为事务模式(例如,调用begin
),但忘记调用commit
,则适配器会在被销毁前自动为你调用commit
。
消息格式化¶
此组件利用formatters
在发送到后端之前对消息进行格式化。可用的格式化器包括:
适配器 | 描述 |
---|---|
Phalcon\Logger\Formatter\Line | 将消息格式化为单行文本 |
Phalcon\Logger\Formatter\Json | 将消息格式化为 JSON 字符串 |
行格式化器¶
使用一行字符串格式化消息。默认的日志格式是:
消息格式¶
如果默认的消息格式不符合你的应用需求,可以使用setFormat()
方法更改它。允许使用的日志格式变量如下:
变量 | 描述 |
---|---|
%message% | 预期要记录的消息本身 |
%date% | 添加消息的时间日期 |
%level% | 大写的消息级别字符串 |
下面的示例演示如何更改消息格式:
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
use Phalcon\Logger\Formatter\Line;
$formatter = new Line('[%level%] - [%date%] - %message%');
$adapter = new Stream('/storage/logs/main.log');
$adapter->setFormatter($formatter);
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$logger->error('Something went wrong');
输出结果为:
如果你不想使用构造函数来更改消息格式,你可以在格式化器上使用setFormat()
方法:
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
use Phalcon\Logger\Formatter\Line;
$formatter = new Line();
$formatter->setFormat('[%level%] - [%date%] - %message%');
$adapter = new Stream('/storage/logs/main.log');
$adapter->setFormatter($formatter);
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$logger->error('Something went wrong');
日期格式¶
默认的日期格式是:
如果默认的消息格式不符合你的应用需求,可以使用setDateFormat()
方法来更改。该方法接受一个包含与日期格式相对应字符的字符串参数。有关所有可用格式,请参考此页面.
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
use Phalcon\Logger\Formatter\Line;
$formatter = new Line();
$formatter->setDateFormat('Ymd-His');
$adapter = new Stream('/storage/logs/main.log');
$adapter->setFormatter($formatter);
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$logger->error('Something went wrong');
JSON 格式化器¶
接口。此外,你还可以复用
{
"level" : "Level of the message",
"message" : "The message",
"timestamp" : "The date as defined in the date format"
}
注意
The format()
方法默认以以下选项编码 JSON(79):-JSON_HEX_TAG
- JSON_HEX_APOS
- JSON_HEX_AMP
- JSON_HEX_QUOT
- JSON_UNESCAPED_SLASHES
- JSON_THROW_ON_ERROR
日期格式¶
默认的日期格式是:
如果默认的消息格式不符合你的应用需求,可以使用setDateFormat()
方法来更改。该方法接受一个包含与日期格式相对应字符的字符串参数。有关所有可用格式,请参考此页面.
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
use Phalcon\Logger\Formatter\Line;
$formatter = new Line();
$formatter->setDateFormat('Ymd-His');
$adapter = new Stream('/storage/logs/main.log');
$adapter->setFormatter($formatter);
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$logger->error('Something went wrong');
输出结果为:
自定义格式化器¶
The 要想创建自己的格式化器或扩展现有的格式化器,必须实现 interface must be implemented in order to create your own formatter or extend the existing ones. Additionally, you can reuse the Phalcon\Logger\Formatter\AbstractFormatter抽象类中的功能。
插值¶
日记记录器还支持插值功能。有时候你可能需要注入由你的应用程序动态生成的额外文本到日志消息中;这可以通过将数组作为日志记录方法(例如error
, info
, alert
等)的第二个参数传入来轻松实现。这个数组包含键值对,其中键是消息中的占位符,而值则是将被插入到消息中的内容。
下面的示例演示了通过注入 "framework" 和 "secs" 参数到消息中进行插值。
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
$adapter = new Stream('/storage/logs/main.log');
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$message = '%framework% executed the "Hello World" test in %secs% second(s)';
$context = [
'framework' => 'Phalcon',
'secs' => 1,
];
$logger->info($message, $context);
注意
当前,无法更改插值占位符。我们将在 Phalcon 的未来版本中引入此功能。
条目¶
上述格式化类接受一个Phalcon\Logger\Item对象。该对象包含日志记录过程所需的所有必要数据。它是从日志记录器传输数据到格式化器的数据载体。
注意
在 v5 中,该对象现在接受一个\DateTimeImmutable
对象作为$dateTime
参数
异常¶
Logger 组件中抛出的任何异常都将是类型Phalcon\Logger\Exception。你可以使用此异常选择性地捕获仅从此组件抛出的异常。
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
use Phalcon\Logger\Exception;
try {
$adapter = new Stream('/storage/logs/main.log');
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
// Log to all adapters
$logger->error('Something went wrong');
} catch (Exception $ex) {
echo $ex->getMessage();
}
示例¶
流¶
日志记录到文件:
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
$adapter = new Stream('/storage/logs/main.log');
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
// Log to all adapters
$logger->error('Something went wrong');
流日志记录器会将消息写入 PHP 中注册的一个有效流。流列表可在以下位置获取点击这里。向流中记录日志
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
$adapter = new Stream('php://stderr');
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$logger->error('Something went wrong');
系统日志¶
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Syslog;
// Setting identity/mode/facility
$adapter = new Syslog(
'ident-name',
[
'option' => LOG_NDELAY,
'facility' => LOG_MAIL,
]
);
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$logger->error('Something went wrong');
无操作¶
<?php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Noop;
$adapter = new Noop('nothing');
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$logger->error('Something went wrong');
自定义适配器¶
The Phalcon\Logger\AdapterInterface要想创建自己的日志记录器适配器或扩展现有适配器,必须实现Phalcon\Logger\Adapter\AbstractAdapter抽象类中的功能。
抽象类¶
创建自定义对象时,有三个提供有用功能的抽象类:-Phalcon\Logger\AbstractLogger - Phalcon\Logger\Adapter\AbstractAdapter - Phalcon\Logger\Formatter\AbstractFormatter.
依赖注入¶
你可以在 [Phalcon\Di\FactoryDefault][factorydefault] 容器中注册任意数量的日志记录器。下面是一个服务注册以及访问它的示例:
<?php
use Phalcon\Di\Di;
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
$container = new Di();
$container->set(
'logger',
function () {
$adapter = new Stream('/storage/logs/main.log');
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
return $logger;
}
);
// accessing it later:
$logger = $container->getShared('logger');