thunken/heimdal

此软件包已被废弃,不再维护。没有建议替代软件包。

2.0.1 2020-01-22 10:39 UTC

This package is auto-updated.

Last update: 2022-03-13 15:20:14 UTC


README

Latest Version Software License Build Status Coverage Status Total Downloads

简介

Heimdal 是一个专门为 API 构建而设计的 Laravel 异常处理器。

为什么需要它?

在构建 API 时,有关于如何向用户发送错误的具体格式规范。像 Laravel 这样的框架并不是专门为 API 构建者设计的。这个小库只是填补了这个空白。例如,像 JSON API 这样的规范有 关于错误格式的指南

安装

composer require thunken/heimdal ^2.0

将服务提供者添加到 config/app.php

// other providers...
Thunken\Heimdal\Provider\LaravelServiceProvider::class,

发布配置。

php artisan vendor:publish --provider="Thunken\Heimdal\Provider\LaravelServiceProvider"

将异常处理器添加到 bootstrap/app.php

$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    Thunken\Heimdal\ExceptionHandler::class
);

它做了什么?

想象一下,你有一段代码抛出了 InvalidArgumentException。这是一个服务器错误(500)。它将按照以下描述的流程进行处理。

1. Exception is thrown
2. The Exception is parsed through reports. A reporter is a class that reports the Exception. Log it in logs, send to external trackers like Sentry, Bugsnag etc.
3. The Exception is parsed through an appropriate formatter that formats the response in accordance to the error type.
4. The response is sent to the user.

这不是 Laravel 做的吗?

是的,基本上是这样。然而,如果你想要向 Sentry 这样的服务报告,通常你会通过像 Monolog 这样的服务来完成。Monolog 的问题是难以 获取报告者的响应。例如,Sentry 为每个报告的异常返回一个唯一的 ID,这对于用户来说非常有用,因为他们可以将它提供给客户支持。Heimdal 通过将所有报告者的响应提供给格式化类来实现这一点,这使得格式化类能够轻松地在其最终用户响应中使用报告者的响应。

其次,Heimdal 预设了不同错误类型应该如何报告给用户的合理的默认值,并使得为特定异常类型实现替代响应变得非常简单。

配置

Heimdal 有两样东西需要配置:格式化和报告者。

报告者

你应该确定你的异常应该报告到哪个地方。Heimdal 仍然调用 Laravel 中的基础报告函数,因此你的异常仍然会像平常一样被记录。然而,添加外部报告很容易。Heimdal 默认集成了 Sentry。要将异常发送到 Sentry,只需将此条目添加到 config/heimdal.php 中的 reporters 部分即可。

'sentry' => [
    'class'  => \Thunken\Heimdal\Reporters\SentryReporter::class,
    'config' => [
        'dsn' => '',
        // For extra options see https://docs.sentry.io/clients/php/config/
        // php version and environment are automatically added.
        'sentry_options' => []
    ]
]

添加一个自定义报告者,例如 Bugsnag,就像写一个这样的小报告者类一样简单

<?php

namespace My\Namespace\Exceptions\Reporters;

use Thunken\Heimdal\Reporters\ReporterInterface;

class BugsnagReporter implements ReporterInterface
{
    public function __construct(array $config)
    {
        // initialize with config
    }

    public function report(Exception $e)
    {
        // report to bugsnag
    }
}

然后将其添加到 config/heimdal.php

'bugsnag' => [
    'class'  => \My\Namespace\Exceptions\Reporters\BugsnagReporter::class,
    'config' => [
        // config.
    ]
]

格式化器

Heimdal 默认已包含合理的格式化器。在 config/heimdal.php 中有一个定义格式化器优先级的部分。

'formatters' => [
    SymfonyException\UnprocessableEntityHttpException::class => Formatters\UnprocessableEntityHttpExceptionFormatter::class,
    SymfonyException\HttpException::class => Formatters\HttpExceptionFormatter::class,
    Exception::class => Formatters\ExceptionFormatter::class,
],

条目越高,优先级越高。在这个例子中,由于是第一个条目,所以会使用 UnprocessableEntityHttpExceptionFormatter 格式化 UnprocessableEntityHttpException。然而,NotFoundHttpException 不会与 UnprocessableEntityHttpException 匹配,但会与 HttpException 匹配(因为它是这里的子类),因此将使用 HttpExceptionFormatter 进行格式化。

可以轻松地编写自定义格式化程序

<?php

namespace My\Namespace\Exceptions\Formatters;

use Exception;
use Illuminate\Http\JsonResponse;
use Thunken\Heimdal\Formatters\BaseFormatter;

class NotFoundHttpExceptionFormatter extends BaseFormatter
{
    public function format(JsonResponse $response, Exception $e, array $reporterResponses)
    {
        $response->setStatusCode(404);
        $data = $response->getData(true);

        if ($this->debug) {
            $data = array_merge($data, [
                'code'   => $e->getCode(),
                'message'   => $e->getMessage(),
                'exception' => (string) $e,
                'line'   => $e->getLine(),
                'file'   => $e->getFile()
            ]);
        } else {
            $data['message'] = [
                'message' => 'The resource was not found.',
                'log_id' => $reporterResponses['sentry']['sentry_id']
            ]
        }

        $response->setData($data);
    }
}

注意我们是如何轻松地使用 $reporterResponses 将 Sentry 日志的 ID附加到 JSON 响应中的。现在我们只需将其添加到 config/heimdal.php

'formatters' => [
    SymfonyException\UnprocessableEntityHttpException::class => Formatters\UnprocessableEntityHttpExceptionFormatter::class,
    SymfonyException\NotFoundHttpException::class => My\Namespace\Exceptions\Formatters\NotFoundHttpExceptionFormatter::class,
    SymfonyException\HttpException::class => Formatters\HttpExceptionFormatter::class,
    Exception::class => Formatters\ExceptionFormatter::class,
],

现在所有 NotFoundHttpException 都将使用我们自定义的格式化程序进行格式化。

可用报告器

Sentry

要将异常发送到 Sentry,请将以下报告器配置添加到 config/heimdal.php

'reporters' => [
    'sentry' => [
        'class'  => \Thunken\Heimdal\Reporters\SentryReporter::class,
        'config' => [
            'dsn' => '',
            // For extra options see https://docs.sentry.io/clients/php/config/
            // php version and environment are automatically added.
            'sentry_options' => []
        ]
    ]
]

在运行时添加上下文

有时您想在运行时添加信息,例如请求数据、用户信息等。为此,您可以在 config 数组中添加 add_context 键。下面是一个示例,说明如何实现。

'reporters' => [
    'sentry' => [
        'class'  => \Thunken\Heimdal\Reporters\SentryReporter::class,
        'config' => [
            'dsn' => env('SENTRY_DSN'),
            // For extra options see https://docs.sentry.io/clients/php/config/
            // php version and environment are automatically added.
            'add_context' => function (Exception $e) {
                $context = [
                    'environment' => app()->environment(),
                    'release' => \Infrastructure\Version::getGitTag()
                ];

                $user = \Auth::User();
                if ($user) {
                    $context['user'] = [
                        'id' => $user->id,
                        'email' => $user->email,
                    ];
                } else {
                    $context['user'] = [];
                }

                // When running in console request is not available
                if (substr(php_sapi_name(), 0, 3) !== 'cli') {
                    $request = app('request');

                    if (!isset($context['extra'])) {
                        $context['extra'] = [];
                    }

                    $context['extra']['request_data'] = json_encode($request->all());
                    $context['user']['ip_address'] = \Request::getClientIp();
                }

                return $context;
            }
        ]
    ]
]

Bugsnag

感谢 Nikolaj Løvenhardt Petersen 添加支持

使用 Laravel 安装指南安装 Bugsnag

要将异常发送到 Bugsnag,请将以下报告器配置添加到 config/heimdal.php

'reporters' => [
    'bugsnag' => [
        'class'  => \Thunken\Heimdal\Reporters\BugsnagReporter::class,
        'config' => []
    ]
]

Rollbar

要将异常发送到 Rollbar,请将以下报告器配置添加到 config/heimdal.php

'reporters' => [
'rollbar' => [
        'class'  => \Thunken\Heimdal\Reporters\RollbarReporter::class,
        'config' => [
            'access_token' => '',
            'environment' => 'production'
        ]
    ]
]

完整的配置选项列表可以在 这里 找到

标准

此包符合 PSR-1PSR-2PSR-4。如果您注意到符合性疏忽,请通过拉取请求发送补丁。

测试

$ phpunit

贡献

有关详细信息,请参阅 CONTRIBUTING

许可证

MIT 许可证(MIT)。有关更多信息,请参阅 许可证文件