andreacivita / heimdal
Requires
- laravel/framework: ~5.3|~6.0
Requires (Dev)
- bugsnag/bugsnag-laravel: ^2.4
- mockery/mockery: 0.9.*
- orchestra/testbench: ~3.1
- phpunit/phpunit: ~4.7
- satooshi/php-coveralls: ~2.1
Suggests
- asm89/stack-cors: Needed to add CORS headers if add_cors_headers configuration is true
- rollbar/rollbar: Needed to report exceptions to Rollbar.com
- sentry/sentry: Needed to report exceptions to Sentry.io
README
本项目是基于 esbenp/heimdal 的分支。分支的目的是支持 Laravel 6+ 版本。所有功劳都归功于 Esbenp
简介
Heimdal 是专门为 API 构建而构建的 Laravel 异常处理器。
为什么需要它?
在构建 API 时,有关如何将错误发送回用户的特定格式规范。像 Laravel 这样的框架并非专门为 API 构建者构建。这个小库只是填补了这个差距。例如,像 JSON API 这样的规范有 关于错误应如何格式化的指南。
安装
composer require andreacivita/heimdal ~1.0
将服务提供者添加到 config/app.php
// other providers...
Andreacivita\Heimdal\Provider\LaravelServiceProvider::class,
发布配置。
php artisan vendor:publish --provider="Andreacivita\Heimdal\Provider\LaravelServiceProvider"
将异常处理器添加到 bootstrap/app.php
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
Andreacivita\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/andreacivita.heimdal.php
中的 reporters
部分
'sentry' => [ 'class' => \Andreacivita\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 Andreacivita\Heimdal\Reporters\ReporterInterface; class BugsnagReporter implements ReporterInterface { public function __construct(array $config) { // initialize with config } public function report(Exception $e) { // report to bugsnag } }
然后将它添加到 config/andreacivita.heimdal.php
'bugsnag' => [ 'class' => \My\Namespace\Exceptions\Reporters\BugsnagReporter::class, 'config' => [ // config. ] ]
格式化
Heimdal 已经提供了合理的格式化器。在 config/andreacivita.heimdal.php
中定义了一个格式化器优先级的部分。
'formatters' => [ SymfonyException\UnprocessableEntityHttpException::class => Formatters\UnprocessableEntityHttpExceptionFormatter::class, SymfonyException\HttpException::class => Formatters\HttpExceptionFormatter::class, Exception::class => Formatters\ExceptionFormatter::class, ],
条目越高,优先级越高。在这个例子中,UnprocessableEntityHttpException
将使用 UnprocessableEntityHttpExceptionFormatter
进行格式化,因为它是最先的条目。然而,NotFoundHttpException
不会匹配 UnprocessableEntityHttpException
,但会匹配 HttpException
(因为它是子类),因此将使用 HttpExceptionFormatter
进行格式化。
您可以轻松编写自定义格式化器
<?php namespace My\Namespace\Exceptions\Formatters; use Exception; use Illuminate\Http\JsonResponse; use Andreacivita\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/andreacivita.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/andreacivita.heimdal.php
中添加以下报告器配置。
'reporters' => [
'sentry' => [
'class' => \Andreacivita\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' => []
]
]
]
在运行时添加上下文
有时您需要在运行时添加信息,例如请求数据、用户信息或类似内容。为此,您可以将 add_context
键添加到 config
数组中。以下是如何实现的示例。
'reporters' => [
'sentry' => [
'class' => \Andreacivita\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添加支持
要将异常发送到Bugsnag,请在 config/andreacivita.heimdal.php
中添加以下报告器配置。
'reporters' => [
'bugsnag' => [
'class' => \Andreacivita\Heimdal\Reporters\BugsnagReporter::class,
'config' => []
]
]
Rollbar
要将异常发送到Rollbar,请在 config/andreacivita.heimdal.php
中添加以下报告器配置。
'reporters' => [
'rollbar' => [
'class' => \Andreacivita\Heimdal\Reporters\RollbarReporter::class,
'config' => [
'access_token' => '',
'environment' => 'production'
]
]
]
完整的配置选项列表可以在 这里 找到
标准
此软件包符合 PSR-1、PSR-2 和 PSR-4 标准。如果您发现遵守标准的问题,请通过pull request发送补丁。
测试
$ phpunit
贡献
有关详细信息,请参阅 CONTRIBUTING
许可
MIT许可(MIT)。有关更多信息,请参阅 许可文件