mensbeam / logger
简单且可配置的记录器
Requires
- php: >=8.1
- mensbeam/filesystem: >=1.0
- psr/log: ^3.0
Requires (Dev)
- ext-pcov: *
- mikey179/vfsstream: ^1.6
- phpunit/phpunit: ^10.0
README
Logger 是一个简单且可配置的 PHP 记录器。它是 PSR-3 记录器接口 的有意见实现。它使用称为 处理器 的类来处理要记录的消息。目前只有一个处理器:StreamHandler
,它允许将日志记录到文件或到流,例如 php://stdout
或 php://stderr
。处理器可以轻松编写并插入到记录器中。
有意见吗?
这个库试图实现我们所说的“有意见”的 PSR-3 实现。这是因为虽然它成功实现了 Psr\Log\LoggerInterface
,但 Logger 在许多方面偏离了规范的真正精神。
-
在 PSR-3 的 1.1 节 中,PSR-3 指出,在调用具有日志级别常量之一的
log
方法时(稍后显示为Psr\Log\LogLevel
),必须具有与调用特定级别方法相同的结果。在Psr\Log\LogLevel
中的日志级别常量是字符串,但Psr\Log\LoggerInterface
中log
方法的$level
参数是无类型的。规范中的话暗示$level
参数应该是一个字符串,但实际上代码实现者没有指定类型。同样,该部分还引用了 RFC 5424 来提及日志级别方法,但为什么使用字符串,而可以使用用于标识严重性的标准化整数呢?由于接口允许任何类型的$level
,Logger 将优先使用实际的 RFC 标准的整数,但将接受并内部将 PSR-3 的字符串转换为整数,以便保持与 PSR-3 兼容。 -
在规范的 1.2 节 中,它描述了一个可选功能,占位符,并要求实现者编写代码来解析和替换占位符,使用的是 PHP 整体中任何地方都没有的语法和方法。 Logger 不会支持此功能,因为日志库的位置是记录消息,而不是插值模板字符串。应该使用单独的库或内置函数,如
sprintf
。但是,Logger 提供了一种转换消息的方法,如果需要,可以用来挂钩首选的插值方法。 -
规范中的 1.3 节 还指定,如果
Exception
对象传递给$context
参数,它必须在exception
键中。这是有道理的,但奇怪的是,没有提到Error
对象的处理方法。它们自 PHP 7 以来就存在,可以像异常一样抛出。《Logger》将接受exception
键中的任何Throwable
,但目前对此不采取任何行动。理论上,将来可以编写处理器来利用它进行结构化数据。 -
在第一项的第1.3节中,它明确指出,实现者必须在
$context
数组中存在错误数据时不要触发警告,并尽可能宽容地处理。然后,在下一条中提到,如果上下文数据中存在异常,它必须位于exception
键中,并且实现者必须验证exception
键。这是矛盾的。在没有错误或异常时验证exception
键不会引发错误或异常,用户应该被告知他们犯了错误;否则设计是不好的。我们解决这个问题的方案是从$context
中删除错误的可抛出对象,并在遇到它们时触发警告。然而,提供了Logger->$warnOnInvalidContextThrowables
以方便必要时抑制警告。
要求
- PHP >= 8.1
- mensbeam/filesystem >= 1.0
- ext-ctype 或 symfony/polyfill-ctype >= 1.8
- ext-mbstring 或 symfony/polyfill-mbstring >= 1.8
- psr/log ^3.0
注意
此库使用mensbeam/filesystem,该库为ext-ctype
和ext-mbstring
提供填充。如果您已安装这些扩展,则不会使用填充。但是,它们仍然被安装。如果您不想无谓地安装填充,可以将此添加到项目的composer.json
中。
{ "require": { "ext-ctype": "*", "ext-mbstring": "*" }, "provide": { "symfony/polyfill-ctype": "*", "symfony/polyfill-mbstring": "*" } }
安装
composer require mensbeam/logger
用法
此库无需配置即可使用,但它可能不完全符合您的默认预期
use MensBeam\Logger; $logger = new Logger();
这将创建一个将所有调试、信息、通知和警告条目输出到STDOUT
的记录器,而任何错误、关键、警报和紧急条目则输出到STDERR
。这似乎会是一个奇怪的默认设置,因为它会在错误时向shell输出重复输出。然而,如果与Catcher
之类的错误处理程序一起使用,它突然就有意义了。
use MensBeam\{ Catcher, Logger }; use MensBeam\Catcher\PlainTextHandler; $catcher = new Catcher(new PlainTextHandler([ 'logger' => new Logger('log'), 'silent' => true ]));
现在,Logger将负责打印。但是,Logger可以做更多。
文档
MensBeam\Logger
namespace MensBeam; use MensBeam\Logger\{ Handler, Level }; class Logger implements Psr\Log\LoggerInterface { public bool $warnOnInvalidContextThrowables = true; public function __construct(?string $channel = null, Handler ...$handlers); public function getChannel(): ?string; public function getHandlers(): array; public function popHandler(): Handler; public function pushHandler(Handler ...$handlers): void; public function setChannel(?string $value): void; public function setHandlers(Handler ...$handlers): void; public function shiftHandler(): Handler; public function unshiftHandler(Handler ...$handlers): void; public function emergency(string|\Stringable $message, array $context = []): void; public function alert(string|\Stringable $message, array $context = []): void; public function critical(string|\Stringable $message, array $context = []): void; public function error(string|\Stringable $message, array $context = []): void; public function warning(string|\Stringable $message, array $context = []): void; public function notice(string|\Stringable $message, array $context = []): void; public function info(string|\Stringable $message, array $context = []): void; public function debug(string|\Stringable $message, array $context = []): void; public function log(int|string|Level $level, string|\Stringable $message, array $context = []): void; }
属性
warnOnInvalidContextThrowables:当设置为true时,Logger将在日志方法中的$context
数组中存在无效的Throwable
时触发警告。
MensBeam\Logger::getChannel
返回Logger实例的通道名称。
MensBeam\Logger::getHandlers
返回用于Logger实例的处理器定义的数组。
MensBeam\Logger::popHandler
从堆栈中删除最后一个处理器并返回它
MensBeam\Logger::pushHandler
将指定的处理器推送到堆栈上
MensBeam\Logger::setChannel
将通道设置为指定的字符串
MensBeam\Logger::setHandlers
用参数指定的处理器替换处理器堆栈
MensBeam\Logger::shiftHandler
从处理器堆栈中移除第一个处理器并返回它
MensBeam\Logger::unshiftHandler
将指定的处理器推送到堆栈的开始位置
MensBeam\Logger::emergency
向日志中添加紧急条目
MensBeam\Logger::alert
向日志中添加警报条目
MensBeam\Logger::critical
向日志中添加关键条目
MensBeam\Logger::error
向日志中添加错误条目
MensBeam\Logger::warning
向日志中添加警告条目
MensBeam\Logger::notice
向日志中添加通知条目
MensBeam\Logger::info
向日志中添加信息条目
MensBeam\Logger::debug
向日志中添加调试条目
MensBeam\Logger::log
在指定级别向日志中添加条目
MensBeam\Logger\Level
这是一个枚举,包含每个日志级别的RFC 5424整数值;同时也提供了转换到和从PSR-3字符串值的方法。
namespace MensBeam; enum Level: int { case Emergency = 0; case Alert = 1; case Critical = 2; case Error = 3; case Warning = 4; case Notice = 5; case Info = 6; case Debug = 7; public static function fromPSR3(string $level): self; public function toPSR3(): string; }
MensBeam\Logger\Level::fromPSR3
接收一个提供的PSR-3字符串级别并返回一个Level
枚举。
MensBeam\Logger\Level::toPSR3
返回枚举的PSR-3字符串级别表示。
MensBeam\Logger\Handler
处理器继承自这个抽象类。因为这个抽象类是为了构建处理器,所以保护方法和属性也会在这里进行文档说明。
namespace MensBeam\Logger; abstract class Handler { protected array $levels; protected bool $_bubbles = true; protected callable $_messageTransform = null; protected string $_timeFormat = 'M d H:i:s'; public function __construct(array $levels = [ 0, 1, 2, 3, 4, 5, 6, 7 ], array $options = []); public function getLevels(); public function getOption(string $name): mixed; public function setLevels(int ...$levels): void; public function setOption(string $name, mixed $value): void; public function __invoke(int $level, ?string $channel, string $message, array $context = []): void; abstract protected function invokeCallback(string $time, int $level, string $channel, string $message, array $context = []): void; }
属性(保护)
levels:这是处理器配置要支持级别的存储位置
选项
以下划线开头的属性都是选项。它们可以通过构造函数设置,也可以通过setHandler
按名称设置,去掉开头的下划线(_)。所有处理器都继承这些选项。继承类中的选项也应该以下划线开头(_)。
bubbles:当设置为true时,堆栈循环将转到下一个处理器;如果为false则不会。默认为true
messageTransform:用于在输出前转换消息的可调用对象。默认为null
timeFormat:用于输出时间所用的PHP标准日期格式。默认为"M d H:i:s"
消息转换
messageTransform选项允许对日志消息进行操作。它接受任何具有以下结构的可调用对象
function (string $message, array $context): string;
此功能的一个常见用途是对字符串进行插值,这不是库所处理的。通过提供消息转换,可以使用任何首选的插值方法
$handler = new StreamHandler(options: [ 'messageTransform' => function (string $message, array $context): string { return vsprintf($message, $context); } ]);
当然,这是一个简单的例子。在将$context
数组转换为数值键(或直接使用数值键)之前,可以在vsprintf
中使用它,但如所见,这是完全可能的。
MensBeam\Logger\Handler::getLevels
返回处理器配置要支持的级别
MensBeam\Logger\Handler::getOption
返回提供的选项名称的值
MensBeam\Logger\Handler::setLevels
设置处理器将支持的级别
MensBeam\Logger\Handler::setOption
设置提供的选项及其值
MensBeam\Logger\Handler::__invoke
输出/分发日志条目
MensBeam\Logger\Handler::invokeCallback (protected)
这是一个回调方法,由继承类扩展以输出/分发日志条目
MensBeam\Logger\StreamHandler
namespace MensBeam\Logger; class StreamHandler extends Handler { public function __construct(resource|string $stream = 'php://stdout', array $levels = [ 0, 1, 2, 3, 4, 5, 6, 7 ], array $options = []); public function getStream(): ?resource; public function getURI(): ?string; public function setStream(resource|string $value): void; }
选项
entryTransform:一个可调用对象,其中可以操作日志条目。默认为null
条目转换
function (string $time, int $level, string $levelName, string $channel, string $message, array $context): string;
参数
- time
- 日志条目被分发时的戳记;可以使用timeFormat选项进行更改
- level
- 日志条目的RFC 5424级别整数
- levelName
- 日志条目的RFC 5424级别名称
- channel
- 在创建记录器时定义的通道
- message
- 消息字符串;可以使用messageTransform选项进行操作
- context
- 在分发条目时使用的上下文数组
以下是如何使用entryTransform选项将条目输出到php://stdout
作为JSONLines/NDJSON等的示例(哦,天哪)
use MensBeam\Logger, MensBeam\Logger\StreamHandler; $handler = new StreamHandler(options: [ 'entryTransform' => function (string $time, int $level, string $levelName, string $channel, string $message, array $context): string { $entry = [ 'time' => $time, 'level' => $level, 'levelName' => $levelName, 'channel' => $channel, 'message' => $message ]; return json_encode($entry, \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); } ]); $logger = new Logger('ook', $handler); $logger->info("ook\neek"); // {"time":"Feb 03 22:45:17","level":6,"levelName":"Info","channel":"ook","message":"ook\neek"}
MensBeam\Logger\StreamHandler::getStream
返回处理器将输出的资源
MensBeam\Logger\StreamHandler::getURI
返回处理器将输出的URI
MensBeam\Logger\StreamHandler::setStream
设置处理器将输出的位置