mirror of
https://github.com/jikan-me/jikan-rest.git
synced 2025-02-20 11:23:35 +08:00
improves sentry integration and order of exceptions
This commit is contained in:
parent
91ced83394
commit
072409410e
@ -121,12 +121,12 @@ INSIGHTS_MAX_STORE_TIME=172800
|
|||||||
###
|
###
|
||||||
# Error reporting
|
# Error reporting
|
||||||
###
|
###
|
||||||
REPORTING=true
|
REPORTING=false
|
||||||
REPORTING_DRIVER=sentry
|
REPORTING_DRIVER=sentry
|
||||||
SENTRY_LARAVEL_DSN="https://examplePublicKey@o0.ingest.sentry.io/0"
|
SENTRY_LARAVEL_DSN="https://examplePublicKey@o0.ingest.sentry.io/0"
|
||||||
SENTRY_TRACES_SAMPLE_RATE=1
|
SENTRY_TRACES_SAMPLE_RATE=0.5
|
||||||
|
|
||||||
###
|
###
|
||||||
# Endpoints
|
# Endpoints
|
||||||
###
|
###
|
||||||
DISABLE_USER_LISTS=false
|
DISABLE_USER_LISTS=false
|
||||||
|
@ -15,54 +15,54 @@ class GithubReport
|
|||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $name;
|
private string $name;
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $code;
|
private string $code;
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $error;
|
private string $error;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $requestUri;
|
private string $requestUri;
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $requestMethod;
|
private string $requestMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $repo;
|
private string $repo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $trace;
|
private string $trace;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $jikanVersion;
|
private string $jikanVersion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $redisRunning;
|
private string $redisRunning;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $instanceType;
|
private string $instanceType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $phpVersion;
|
private string $phpVersion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Exception $exception
|
* @param \Exception $exception
|
||||||
|
@ -3,10 +3,7 @@
|
|||||||
namespace App\Exceptions;
|
namespace App\Exceptions;
|
||||||
|
|
||||||
use App\Events\SourceHeartbeatEvent;
|
use App\Events\SourceHeartbeatEvent;
|
||||||
use App\Http\HttpHelper;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use GuzzleHttp\Exception\ClientException;
|
|
||||||
use GuzzleHttp\Exception\ConnectException;
|
|
||||||
use Illuminate\Auth\Access\AuthorizationException;
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
@ -16,11 +13,9 @@ use Jikan\Exception\BadResponseException;
|
|||||||
use Jikan\Exception\ParserException;
|
use Jikan\Exception\ParserException;
|
||||||
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
|
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
|
||||||
use Predis\Connection\ConnectionException;
|
use Predis\Connection\ConnectionException;
|
||||||
use Symfony\Component\Debug\Exception\FlattenException;
|
|
||||||
use Symfony\Component\HttpClient\Exception\TimeoutException;
|
use Symfony\Component\HttpClient\Exception\TimeoutException;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Handler
|
* Class Handler
|
||||||
@ -41,6 +36,13 @@ class Handler extends ExceptionHandler
|
|||||||
BadResponseException::class
|
BadResponseException::class
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
protected array $acceptableForReportingDriver = [
|
||||||
|
ParserException::class
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Throwable $e
|
* @param \Throwable $e
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
@ -55,13 +57,10 @@ class Handler extends ExceptionHandler
|
|||||||
* @param \Throwable $e
|
* @param \Throwable $e
|
||||||
* @return JsonResponse|Response
|
* @return JsonResponse|Response
|
||||||
*/
|
*/
|
||||||
public function render($request, \Throwable $e)
|
public function render($request, \Throwable $e): JsonResponse|Response
|
||||||
{
|
{
|
||||||
$githubReport = GithubReport::make($e, $request);
|
$githubReport = GithubReport::make($e, $request);
|
||||||
|
$this->reportToSentry($e);
|
||||||
if (app()->bound('sentry') && $this->shouldReport($e)) {
|
|
||||||
app('sentry')->captureException($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConnectionException from Redis server
|
// ConnectionException from Redis server
|
||||||
if ($e instanceof ConnectionException) {
|
if ($e instanceof ConnectionException) {
|
||||||
@ -83,18 +82,6 @@ class Handler extends ExceptionHandler
|
|||||||
], 500);
|
], 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($e instanceof ConnectException) {
|
|
||||||
event(new SourceHeartbeatEvent(SourceHeartbeatEvent::BAD_HEALTH, $e->getCode()));
|
|
||||||
|
|
||||||
return response()
|
|
||||||
->json([
|
|
||||||
'status' => $e->getCode(),
|
|
||||||
'type' => 'BadResponseException',
|
|
||||||
'message' => 'Jikan failed to connect to MyAnimeList.net. MyAnimeList.net may be down/unavailable, refuses to connect or took too long to respond.',
|
|
||||||
'error' => $e->getMessage()
|
|
||||||
], 503);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParserException from Jikan PHP API
|
// ParserException from Jikan PHP API
|
||||||
if ($e instanceof ParserException) {
|
if ($e instanceof ParserException) {
|
||||||
$githubReport->setRepo(env('GITHUB_API', 'jikan-me/jikan'));
|
$githubReport->setRepo(env('GITHUB_API', 'jikan-me/jikan'));
|
||||||
@ -108,9 +95,9 @@ class Handler extends ExceptionHandler
|
|||||||
], 500);
|
], 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BadResponseException from Guzzle dep via Jikan PHP API
|
// BadResponseException from Jikan PHP API
|
||||||
// This is basically the response MyAnimeList returns to Jikan
|
// This is basically the response MyAnimeList returns to Jikan
|
||||||
if ($e instanceof BadResponseException || $e instanceof ClientException) {
|
if ($e instanceof BadResponseException) {
|
||||||
switch ($e->getCode()) {
|
switch ($e->getCode()) {
|
||||||
case 404:
|
case 404:
|
||||||
// $this->set404Cache($request, $e);
|
// $this->set404Cache($request, $e);
|
||||||
@ -157,6 +144,28 @@ class Handler extends ExceptionHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($e instanceof TimeoutException) {
|
||||||
|
return response()
|
||||||
|
->json([
|
||||||
|
'status' => 408,
|
||||||
|
'type' => 'TimeoutException',
|
||||||
|
'message' => 'Request to MyAnimeList.net timed out (' .env('SOURCE_TIMEOUT', 5) . ' seconds)',
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
], 408);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($e instanceof Exception && $e->getMessage() === "Undefined index: url") {
|
||||||
|
event(new SourceHeartbeatEvent(SourceHeartbeatEvent::BAD_HEALTH, $e->getCode()));
|
||||||
|
|
||||||
|
return response()
|
||||||
|
->json([
|
||||||
|
'status' => $e->getCode(),
|
||||||
|
'type' => 'BadResponseException',
|
||||||
|
'message' => 'Jikan failed to connect to MyAnimeList.net. MyAnimeList.net may be down/unavailable, refuses to connect or took too long to respond. Retry the request!',
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
], 503);
|
||||||
|
}
|
||||||
|
|
||||||
// Bad REST API requests
|
// Bad REST API requests
|
||||||
if ($e instanceof HttpException) {
|
if ($e instanceof HttpException) {
|
||||||
return response()
|
return response()
|
||||||
@ -168,71 +177,32 @@ class Handler extends ExceptionHandler
|
|||||||
], $e->getStatusCode());
|
], $e->getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($e instanceof TimeoutException) {
|
return response()
|
||||||
return response()
|
->json([
|
||||||
->json([
|
'status' => 500,
|
||||||
'status' => 408,
|
'type' => "Exception",
|
||||||
'type' => 'TimeoutException',
|
'message' => 'Unhandled Exception. Please follow report_url to generate an issue on GitHub',
|
||||||
'message' => 'Request to MyAnimeList.net timed out (' .env('SOURCE_TIMEOUT', 5) . ' seconds)',
|
'trace' => "{$e->getFile()} at line {$e->getLine()}",
|
||||||
'error' => $e->getMessage()
|
'error' => $e->getMessage(),
|
||||||
], 408);
|
'report_url' => env('GITHUB_REPORTING', true) ? (string) $githubReport : null
|
||||||
}
|
], 500);
|
||||||
|
|
||||||
if ($e instanceof Exception) {
|
|
||||||
if ($e->getMessage() === "Undefined index: url") {
|
|
||||||
event(new SourceHeartbeatEvent(SourceHeartbeatEvent::BAD_HEALTH, $e->getCode()));
|
|
||||||
|
|
||||||
return response()
|
|
||||||
->json([
|
|
||||||
'status' => $e->getCode(),
|
|
||||||
'type' => 'BadResponseException',
|
|
||||||
'message' => 'Jikan failed to connect to MyAnimeList.net. MyAnimeList.net may be down/unavailable, refuses to connect or took too long to respond. Retry the request!',
|
|
||||||
'error' => $e->getMessage()
|
|
||||||
], 503);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return response()
|
|
||||||
->json([
|
|
||||||
'status' => 500,
|
|
||||||
'type' => "Exception",
|
|
||||||
'message' => 'Unhandled Exception. Please follow report_url to generate an issue on GitHub',
|
|
||||||
'trace' => "{$e->getFile()} at line {$e->getLine()}",
|
|
||||||
'error' => $e->getMessage(),
|
|
||||||
'report_url' => env('GITHUB_REPORTING', true) ? (string) $githubReport : null
|
|
||||||
], 500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Request $request
|
* @param Exception|\Throwable $e
|
||||||
* @param BadResponseException $e
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function set404Cache(Request $request, BadResponseException $e)
|
private function reportToSentry(\Exception|\Throwable $e): void
|
||||||
{
|
{
|
||||||
if (!env('CACHING') || env('MICROCACHING')) {
|
if (!app()->bound('sentry')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fingerprint = "request:404:".sha1(env('APP_URL') . $request->getRequestUri());
|
foreach ($this->acceptableForReportingDriver as $type) {
|
||||||
|
if ($e instanceof $type) {
|
||||||
if (Cache::has($fingerprint)) {
|
app('sentry')->captureException($e);
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$routeController = HttpHelper::requestControllerName($request);
|
|
||||||
$cacheTtl = env('CACHE_DEFAULT_EXPIRE', 86400);
|
|
||||||
|
|
||||||
if (\in_array($routeController, [
|
|
||||||
'AnimeController',
|
|
||||||
'MangaController',
|
|
||||||
'CharacterController',
|
|
||||||
'PersonController'
|
|
||||||
])) {
|
|
||||||
$cacheTtl = env('CACHE_404_EXPIRE', 604800);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Cache::put($fingerprint, $e->getMessage(), $cacheTtl);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,11 @@ if (env('REPORTING') && env('REPORTING_DRIVER') === 'sentry') {
|
|||||||
$app->register(\Sentry\Laravel\ServiceProvider::class);
|
$app->register(\Sentry\Laravel\ServiceProvider::class);
|
||||||
// Sentry Performance Monitoring (optional)
|
// Sentry Performance Monitoring (optional)
|
||||||
$app->register(\Sentry\Laravel\Tracing\ServiceProvider::class);
|
$app->register(\Sentry\Laravel\Tracing\ServiceProvider::class);
|
||||||
|
|
||||||
|
\Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
|
||||||
|
$scope->setTag('rest.jikan.version', env('APP_VERSION'));
|
||||||
|
$scope->setTag('parser.jikan.version', JIKAN_PARSER_VERSION);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guzzle removed as of lumen 8.x
|
// Guzzle removed as of lumen 8.x
|
||||||
|
@ -8,7 +8,7 @@ return [
|
|||||||
// 'release' => trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')),
|
// 'release' => trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')),
|
||||||
|
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => env('SENTRY_ENVIRONMENT'),
|
'environment' => env('APP_ENV'),
|
||||||
|
|
||||||
'breadcrumbs' => [
|
'breadcrumbs' => [
|
||||||
// Capture Laravel logs in breadcrumbs
|
// Capture Laravel logs in breadcrumbs
|
||||||
@ -54,4 +54,6 @@ return [
|
|||||||
|
|
||||||
'controllers_base_namespace' => env('SENTRY_CONTROLLERS_BASE_NAMESPACE', 'App\\Http\\Controllers'),
|
'controllers_base_namespace' => env('SENTRY_CONTROLLERS_BASE_NAMESPACE', 'App\\Http\\Controllers'),
|
||||||
|
|
||||||
|
'release' => env('APP_VERSION')
|
||||||
|
|
||||||
];
|
];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user