kodus/sentry

PHP官方Sentry客户端的轻量级替代方案

2.1.1 2022-09-13 10:59 UTC

This package is auto-updated.

Last update: 2024-09-13 15:24:53 UTC


README

无依赖的轻量级Sentry客户端。

PHP Version Build Status

关于

此包是Sentry官方PHP客户端的替代品。

该库由一个客户端类、一个与Sentry API形状匹配的事件模型以及一个扩展接口组成。

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

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

特性

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

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

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

非特性

  • 没有内置的错误处理器:你的框架/堆栈/应用程序可能已经有了,而这个客户端应该可以轻松集成到任何地方。
  • 没有记录后数据:清理/净化是不可靠的。(如果你愿意承担风险,字段在模型中,你可以实现自己的扩展。)

用法

现在大多数现代框架都有某种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);
        }
    },
);

现在我们已经为PHP错误抛出了ErrorException,我们就可以使用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

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

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值,而我们的模型正式描述JSON体形状,使用实现JsonSerializable的普通PHP类层次结构。

请注意,我们只模拟在PHP环境中有意义的JSON体形状的一部分 - 如果您发现缺少或错误的东西,欢迎提出拉取请求。