sturents/sentry-light

PHP官方Sentry客户端的轻量级替代方案。从kodus/sentry分支而来

3.0.1 2024-09-02 14:37 UTC

This package is auto-updated.

Last update: 2024-09-20 12:17:32 UTC


README

轻量级无依赖的Sentry客户端。由于原包不再维护且在较新版本的PHP中导致中断,因此从kodus/sentry分支而来。

PHP Version Build Status

关于

本包是Sentry官方PHP客户端的替代方案。

库包括一个客户端类、一个与Sentry API形状匹配的事件模型,以及一个用于扩展的接口。

API与统一API建议不同 - 我们的目标是记录详细的异常,并捕获导致这些异常的日志条目,尽可能减少与客户端的耦合和依赖。

大多数成员声明为protected,您可以通过简单修改(完全类型提示的)模型来进一步扩展和覆盖/增强异常/错误/请求处理的各个方面。

功能

此客户端具有官方客户端的大部分功能,还有一些额外功能。

所有功能都是可选的,该包附带以下扩展

  • EnvironmentReporter:报告PHP和操作系统版本、服务器名称、站点名称等。
  • RequestReporter:报告关于(PSR-7)HTTP请求的详细信息。
  • ExceptionReporter:提供具有源代码上下文、路径/文件名、行号等详细堆栈跟踪。
  • ClientSniffer:解析客户端(浏览器或机器人)名称/版本/操作系统并添加有用的标记。
  • ClientIPDetector:解析代理后面的用户IP的X-Forwarded-ForForwarded头。
  • BreadcrumbLogger:将PSR-3日志事件报告为面包屑

非功能

  • 没有内置的错误处理程序:您的框架/堆栈/应用程序可能已经有了,并且此客户端几乎可以轻松地集成到任何地方。
  • 没有记录后数据:清除/消毒不可靠。(如果您愿意承担风险,模型中提供了字段,您可以实现自己的扩展。)

使用方法

现在,大多数现代框架都有某种类型的DI容器和错误处理程序。

为了避免陷入各种框架的具体细节,在本节中,我们将展示如何独立于任何特定框架启动和集成客户端。

要启动客户端本身,您需要一个Sentry DSN、一个EventCapture实现以及您选择的扩展 - 此示例使用DirectEventCapture和大多数内置扩展

$client = new SentryClient(
    new DirectEventCapture(
        new DSN("https://0123456789abcdef0123456789abcdef@sentry.io/1234567"),
        "tcp://proxy.example.com:5100" // optional: required if you're behind a proxy
    ),
    [
        new EnvironmentReporter(),
        new RequestReporter(),
        new ExceptionReporter(),
        new ClientSniffer(),
        new ClientIPDetector(),
    ]
);

$client->sample_rate = 50; // optional: percentage of calls to `captureException()` to actually capture

一些扩展支持额外的选项,这些选项将在配置部分中描述。

要捕获PHP错误,我们需要添加一个将错误映射到内置的ErrorException类实例的错误处理程序。

请注意,大多数框架和错误处理器已经内置了类似的功能 - 现有的错误处理器可能设计为唯一的全局错误处理器,并且可能提供对 set_error_handler() 的抽象和一些类型的API。

以下简化的错误处理器会抛出所有错误级别(除了 E_NOTICEE_WARNING),后者它静默地捕获到我们上面创建的 $client 实例。

set_error_handler(
    function ($severity, $message, $file, $line) use ($client) {
        $error = new ErrorException($message, 0, $severity, $file, $line);
        
        if ($severity & (E_ALL & ~E_NOTICE & ~E_WARNING)) {
            throw $error;
        } else {
            $client->captureException($error);
        }
    },
);

现在我们已经将 ErrorException 抛出作为 PHP 错误,我们可以通过在顶层脚本中的任何语句周围使用 try/catch-语句一致地处理任何错误/异常。

try {
    // ... dispatch your router or middleware-stack, etc. ...
} catch (Throwable $error) {
    $client->captureException($error);
    
    // ... render an apology page for disappointed users ...
}

现在我们有了基本的错误处理,以及静默捕获警告和通知。

PSR-15 中间件上下文中,我们可以捕获有关引发错误的 ServerRequestInterface 实例的更多有用信息 - 通常,我们将在中间件栈的顶部使用中间件来完成此操作,该中间件将从 try/catch-块委托给下一个中间件。

以下是将匿名中间件添加到中间件数组的基本示例。

$middlewares = [
    new class ($client) implements MiddlewareInterface {
        /**
         * @var SentryClient
         */
        private $client;
    
        public function __construct(SentryClient $client)
        {
            $this->client = $client;
        }
    
        public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
        {
            try {
                return $handler->handle($request);
            } catch (Throwable $error) {
                $this->client->captureException($error, $request);
    
                // ... return an apology response for disappointed users ...
            }
        }
    },
    // ... the rest of your middleware stack ...
];

此中间件捕获到的任何错误 不会 泡泡到顶层脚本中的第一个 try/catch-语句 - 相反,中间件中 captureException() 的调用包含了 $error$request(在顶层脚本中尚不存在)从其中客户端可以捕获更多详细信息。

此外,您的应用程序可能在正常操作期间记录一些有用的信息(例如数据库查询) - 在失败的情况下,这些信息可以帮助您诊断导致错误的事件。

这些日志条目可以使用提供的 BreadcrumbLogger 捕获,作为所谓的“面包屑”,它既是 PSR-3 LoggerInterface 实现,也是 SentryClientExtension

您可能希望将其作为主日志记录器启动 - 也许您只关心导致错误条件的日志条目。然而,更有可能您想要另一个日志记录器将日志事件发送到持久日志,并记录为面包屑。(例如,您可能尝试 monolog/monolog 包,该包允许您将日志记录到任何组合的 PSR-3 和 monolog 处理器,过滤日志条目等 - 或者如果您喜欢简单的东西,尝试 mouf/utils.log.psr.multi-logger。)

请注意,日志条目将在捕获异常之前在日志记录器中缓冲 - 如果您的应用程序是处理多个请求的 CLI 脚本,您需要在成功的请求结束时手动调用日志记录器实例的 clear(),否则日志条目将累积在请求之间。

注意:PHP 7.4 引入了一个新的 ini 设置zend.exception_ignore_args),用于从堆栈跟踪中排除参数。如果您希望将参数传递给 Sentry,则需要关闭此设置。

配置

一些扩展支持可选的构造函数参数来配置一些可选功能。

ExceptionReporter

构造函数接受两个可选参数

  • $root_path - 如果指定,项目根路径将不会出现在堆栈跟踪中可见的文件名中。
  • $max_string_length - 指定报告的 PHP 值将被截断的最大长度。
  • $filters - 指定要从堆栈跟踪中过滤的一个或多个文件名模式。

此外,公共 $error_levels 属性允许您自定义 PHP 错误级别映射到 Sentry 严重级别的方式。默认配置与官方 2.0 客户端相同。

ClientSniffer

如果您的客户群使用稀有或异国客户端,您可以将自己的正则表达式模式添加到公共的$browser_patterns$os_patterns属性中,以增强浏览器分类。默认配置将识别大多数常见的浏览器和版本、操作系统和爬虫。

ClientIPDetector

替换或添加到$user_ip_headers,以在特殊环境中检测客户端IP地址。内置模式支持大多数常规缓存/代理服务器。

BreadcrumbLogger

默认的$log_levels与官方(2.0)客户端匹配 - 如果需要,您可以自定义PSR-5日志级别到Sentry严重级别的映射。

BufferedEventCapture

有可用的缓冲EventCapture实现。

如果您只捕获异常/错误,可能不需要这个 - 但如果您将警告和通知映射到具有错误处理程序的ErrorException,可能希望避免在向Sentry发送时阻塞响应。

您可以使用BufferedEventCapture装饰器来实现这一点,它允许您在向用户发送响应后延迟实际的HTTP请求。

在这种情况下,您需要分别启动捕获和客户端实例。

$buffer = new BufferedEventCapture(
   new DirectEventCapture(
       new DSN("https://0123456789abcdef0123456789abcdef@sentry.io/1234567")
   ),
);

$client = new SentryClient($buffer);

由于事件现在将缓冲而不是直接发送到Sentry,您需要在请求结束时手动刷新事件。

在一个典型的PHP FCGI SAPI环境中,您可以通过在将事件刷新到Sentry之前明确关闭HTTP响应来实现这一点 - 例如,从index.php文件。

register_shutdown_function(function () use ($buffer) {
    fastcgi_finish_request();
    
    $buffer->flush();
});

定制

客户端类和扩展旨在考虑项目特定的扩展,并包含许多用于您扩展和覆盖其行为的protected方法。

使用protected重写,您可以自定义事件创建和捕获的方式、异常和请求的处理方式、客户端IP检测和过滤、PHP值在堆栈跟踪中的格式化,以及其他许多细节。

请参考源代码以获取可用的protected方法 - 并请注意,我们致力于以语义版本化此包:对protected方法的任何重大更改都将作为主要版本发布。

为什么?

公开表达的看法

官方Sentry PHP客户端的1.x版本已经过时,并不适合现代(PSR-7/15)应用程序堆栈。

2.0版本(目前正在开发中)是建筑杰作 - 这并不是我们从本质上收集一些数据和执行简单的JSON POST请求的所需/想要的东西。

特别是

  • 我们不需要错误处理程序 - 每个现代应用程序堆栈都已经有一个。
  • 我们不想有一个复杂的架构和自定义中间件 - 简单的函数就可以。
  • 我们不想记录POST数据 - 存在太多的风险。
  • 更少的代码 ~> 更少的错误(希望如此;您不希望错误记录器本身崩溃。)
  • 无依赖项:无冲突,无麻烦。

我们想要简单、快速和透明的东西。

我们还坚持良好的IDE支持代码,这为阅读/修改代码的人提供了更好的洞察力,并减少了静默错误的可能性 - 官方客户端处理array值,而我们的模型以实现JsonSerializable的简单PHP类层次结构正式描述JSON体形状。

请注意,我们只模拟在PHP环境中有意义的JSON体形状部分 - 如果您发现某些内容缺失或不正确,欢迎提交pull-requests。