shays / logger
一个简单且无偏见的日志库
Requires
- php: ^7.2
- psr/log: ^1.1
- symfony/filesystem: ^4.3
- symfony/property-access: ^4.3
- symfony/serializer: ^4.3
Requires (Dev)
- phpstan/phpstan: ^0.12.9
- phpstan/phpstan-phpunit: ^0.12.6
- phpunit/phpunit: 8
- squizlabs/php_codesniffer: *
This package is auto-updated.
Last update: 2024-09-09 20:25:01 UTC
README
这是一个简单高效的日志库的最小可行性产品(MVP)。
遵循PSR-3 日志标准,并受Monolog的启发,该库提供了一些方便的功能来帮助您开始,尽管它非常无偏见(如果您希望它是的话),并且可以调整以适应各种技术需求。
这意味着您只需几行代码就可以拥有一个日志记录器,它可以捕获和存储所有PHP错误和异常到您选择的路径,以及您可能在应用程序中想要做的任何自定义日志记录。再添加几行代码,您就可以覆盖或添加您能想到的任何自定义修改,这本质上是在钩子到库的内部处理过程。
该文档假设您熟悉PHP中的日志记录以及PSR-3标准。
安装
您可以使用composer安装最新版本
composer require shays/logger
开始使用
日志库使用构建者设计模式,这有助于提供库可能使用的灵活性和可扩展性,下面的例子将很快帮助您明确这一点。
要开始使用最基本的简单日志记录器
基本示例
use Shays\Logger; use Shays\Logger\Stream\FileStream; $log = (new Logger('MyApp'))->addStream(new FileStream('application.log')); $log->notice('Log message');
就是这样。在示例中,我们创建了一个带有应用程序名称的logger
实例,该实例将应用程序中发生的任何PHP通知/警告/错误和异常存储到您选择的路径,格式为JSON,包括错误消息、日志严重性和时间戳。任何异常也会以详细信息添加。
时区
您可能需要指定日志时间戳将生成的时区。您可以使用setTimezone
方法,并传递一个DateTimeZone
实例来完成。
use DateTimeZone; use Shays\Logger; use Shays\Logger\Stream\FileStream; $log = (new Logger('MyApp')) ->addStream(new FileStream('application.log')) ->setTimezone(new DateTimeZone('Europe/London')); $log->notice('Log message');
附加上下文
您可能希望在日志中包含附加数据,例如环境或用户相关的信息。您可以使用addContext
指定这些信息,该函数接受一个包含您要添加的信息的关联数组。
use Shays\Logger; use Shays\Logger\Stream\FileStream; $log = (new Logger('MyApp')) ->addStream(new FileStream('application.log')) ->addContext([ 'environment' => 'local', ]); $log->notice('Log message');
在logger
实例级别添加的上下文将被添加到每个单独的日志条目。
向日志添加上下文
您可以为单个日志添加上下文,例如添加相关信息、异常对象等。
// Simple log context added $log->notice('User not found', ['id' => 123]);
捕获异常
异常可以作为上下文添加,然后由日志记录器解析和提取以提供相关详细信息。
// Adding captured exception information try { // Trying an API connection } catch (\Throwable $e) { $log->error('API connection failed', ['exception' => $e]); }
仅记录错误
例如,您可以将第二个参数设置为addStream
方法的参数,以告诉文件日志记录器您感兴趣的最低严重性日志级别(在这种情况下,将存储所有从错误到最严重错误的日志级别,跳过通知、警告等)。
use Shays\Logger; use Shays\Logger\LogLevel; use Shays\Logger\Stream\FileStream; $log = (new Logger('MyApp')) ->addStream(new FileStream('application.log', LogLevel::ERROR)); // This won't be logged to the file $log->notice('Log message');
高级用法
日志库提供强大的扩展功能。几乎一切都是可定制的,您甚至可以创建自己的Log
对象,该对象由处理器和日志流使用,并可以按您希望的方式重命名字段和序列化数据。
让我们从一些基本示例开始。
自定义日志级别
您可以通过addLogLevel
方法动态添加自定义日志级别,该方法接受日志级别编号和名称(该名称将用于从logger
实例调用它)。
建议为自定义级别创建一个新的类,然后可以在需要时将其传递到应用程序中。
// CustomLogLevel.php class CustomLogLevel { /** @var int New progress log level (e.g. for logging cron task requests) */ const PROGRESS = 50; }
在应用程序中
use CustomLogLevel; use Shays\Logger; use Shays\Logger\Stream\FileStream; $log = (new Logger('MyApp')) ->addStream(new FileStream('application.log', CustomLogLevel::PROGRESS)) ->addLogLevel(CustomLogLevel::PROGRESS, 'PROGRESS'); // This is now possible to call it directly $log->progress('Log message');
自定义处理器
您可以将自定义处理器添加到logger
实例中,每当创建日志时都会调用它们。自定义处理器应遵循LogHandlerInterface,它由两个方法组成,分别是handle
和shouldHandle
。
// MyCustomHandler.php use Shays\Logger\Handlers\LogHandlerInterface; use Shays\Logger\LogInterface; use Shays\Logger\LogLevel; class MyCustomHandler implements LogHandlerInterface { public function handle(LogInterface $log): void { // Do anything with the log object // (e.g. get the message, context, etc) // (read more about the Log object below) } public function shouldHandle(LogInterface $log): bool { // e.g. handle notices and the more severe logs return $log->getLevel() >= LogLevel::NOTICE; } }
在应用程序中
use MyCustomHandler; use Shays\Logger; $log = (new Logger('MyApp')) ->addHandler(new MyCustomHandler());
使用自定义处理器,您可以向Slack发送消息或使用任何第三方集成来监控应用程序的健康状况。
自定义流式处理器
自定义流式处理器与自定义处理器类似,但它们旨在进行流式传输和保存序列化日志。自定义流式处理器应遵循StreamInterface,它由两个方法组成:write
和shouldWrite
。
在上面的示例中,我们使用了库的FileStream
类将日志存储到特定文件中,尽管我们也可以使用自己的Stream类来创建独特功能
// XmlStream.php use Shays\Logger\LogInterface; use Shays\Logger\Stream\StreamInterface; class XmlStream implements StreamInterface { /** @var int Lowest log level for handling log */ private $lowestLevel; public function __construct(int $lowestLevel) { $this->lowestlevel = $lowestLevel; } public function write(string $log): void { // Write the serialized log to the database or system file } public function shouldWrite(LogInterface $log): bool { return $log->getLevel() >= $this->lowestLevel; } }
在应用程序中
use Shays\Logger; use XmlStream; $log = (new Logger('MyApp')) ->addStream(new XmlStream(LogLevel::ERROR));
流式序列化器
默认情况下,当日志传递给write
方法时,它会被序列化为JSON,尽管可以添加更多序列化器,并且只要它们遵循SerializerInterface,就可以传递给Logger实例。
// XmlSerializer.php use Shays\Logger\LogInterface; use Shays\Logger\Serializer\SerializerInterface; use Symfony\Component\Serializer\Encoder\XmlEncoder; class XmlSerializer implements SerializerInterface { private $encoder; public function __construct() { $this->encoder = new XmlEncoder(); } public function serialize(LogInterface $log) { // Serialize the data to XML format which would // be then passed to the streaming classes. // The $log->toArray() method is transforming the // log object to an array with the relevant // log information, ready to be serialized return $this->encoder->encode($log->toArray(), 'xml'); } }
在应用程序中
use XmlSerializer; use XmlStream; use Shays\Logger; $log = (new Logger('MyApp', new XmlSerializer())) ->addStream(new XmlStream(LogLevel::ERROR));
现在所有自定义流式处理器都将通过XML处理。
日志对象
库的日志对象提供了一些方便的方法来获取每个单独日志中存储的数据。
考虑到前面的自定义处理器示例
class MyCustomHandler implements LogHandlerInterface { public function handle(LogInterface $log): void { // Handle log } }
现在您可以使用日志对象来访问其数据,例如日志消息
$log->getMessage();
日志通道
$log->getChannel();
日志级别
$log->getLevel();
日志级别名称(例如,警告、错误等)
$log->getLevelName();
日志时间戳
$log->getTimestamp();
您还可以获取上下文字符数组
$log->getAllContext();
或单个上下文
// Check if exists $log->hasContext('userId'); // Get the context $log->getContext('userId');
您还可以使用动态简写方法get
// Gets the log message $log->get('message'); // Gets the log level $log->get('level'); // Gets the userId context (fallback to context) $log->get('userId');
自定义日志对象
自定义日志对象为传递给处理器和流式处理器的数据提供了额外的灵活性。默认情况下,库的Log对象涵盖了从每个日志条目中可以期望得到的最小数据,尽管没有对结构(例如,上下文中的内容始终在上下文中!)进行控制。
当日志传递给序列化器(例如,将日志写入JSON文件)时,在数据被序列化之前,会调用$log->toArray()
方法来确定我们感兴趣传递的数据。
虽然默认提供的基本结构对于大多数情况已经足够,但扩展它可以帮助我们创建所需的数据结构,该数据结构最终将以相同的方式存储。这对于作为重要全局上下文传递非常重要,因为它始终会被包含。例如
// CustomLog.php use Shays\Logger\Log; class CustomLog extends Log { public function toArray(): array { $context = $this->getAllContext(); // Remove environment from context (which will be used on the top array level) unset($context['environment']); return [ 'timestamp' => $this->getTimestamp(), 'level' => $this->getLevel(), 'message' => $this->getMessage(), 'levelName' => $this->getLevelName(), 'environment' => $this->getContext('environment'), 'additionalData' => $context, ]; } }
现在我们可以在应用程序中传递新的对象
use CustomLog; use Shays\Logger; use Shays\Logger\Stream\FileStream; $log = (new Logger('MyApp', null, CustomLog::class)) ->addStream(new FileStream('application.log')) ->addContext([ 'environment' => 'debug', 'ipAddress' => '127.0.0.1', ]); $log->info('Info message');