Merge branch 'trunk'
This commit is contained in:
commit
972ce0cf6f
5 changed files with 1540 additions and 36 deletions
|
|
@ -4,8 +4,6 @@ namespace App\Exceptions;
|
||||||
|
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
use Illuminate\Auth\AuthenticationException;
|
use Illuminate\Auth\AuthenticationException;
|
||||||
use Illuminate\Support\Facades\Mail;
|
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
class Handler extends ExceptionHandler
|
class Handler extends ExceptionHandler
|
||||||
{
|
{
|
||||||
|
|
@ -33,6 +31,12 @@ class Handler extends ExceptionHandler
|
||||||
*/
|
*/
|
||||||
public function register()
|
public function register()
|
||||||
{
|
{
|
||||||
|
$this->reportable(function (\Throwable $e) {
|
||||||
|
if (app()->bound('sentry')) {
|
||||||
|
app('sentry')->captureException($e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -61,37 +65,4 @@ class Handler extends ExceptionHandler
|
||||||
// Session::forget('url.intented'); .
|
// Session::forget('url.intented'); .
|
||||||
return redirect()->guest(route($login));
|
return redirect()->guest(route($login));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Report or log an exception.
|
|
||||||
*
|
|
||||||
* @param \Throwable $e
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function report(Throwable $e)
|
|
||||||
{
|
|
||||||
if (get_class($e) == RedirectTo::class) {
|
|
||||||
abort(redirect($e->url));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config('app.debug') === false) {
|
|
||||||
if ($this->shouldntReport($e)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Mail::send([
|
|
||||||
'html' => 'emails.exception',
|
|
||||||
'text' => 'emails.exception-plain'
|
|
||||||
], [
|
|
||||||
'exception' => $e,
|
|
||||||
'appName' => config('app.name')
|
|
||||||
], function ($m) {
|
|
||||||
$m->to(
|
|
||||||
config('mail.contactsList.serviceweb'),
|
|
||||||
sprintf('%s Exception Handler', config('app.name'))
|
|
||||||
)->subject('Need help !, an error occured in your application, please check Logs ASAP');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
parent::report($e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
190
app/Lib/ExceptionsHelper.php
Normal file
190
app/Lib/ExceptionsHelper.php
Normal file
|
|
@ -0,0 +1,190 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Lib;
|
||||||
|
|
||||||
|
class ExceptionsHelper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle sentry event
|
||||||
|
*
|
||||||
|
* @param \Sentry\Event $event
|
||||||
|
* @return null|\Sentry\Event
|
||||||
|
*/
|
||||||
|
public static function sentryEventHandler(\Sentry\Event $event): ?\Sentry\Event
|
||||||
|
{
|
||||||
|
// Remove unwanted reports.
|
||||||
|
$event->setModules([]);
|
||||||
|
$event->setOsContext(null);
|
||||||
|
|
||||||
|
/** @var \Sentry\ExceptionDataBag[] */
|
||||||
|
$exceptionBag = [];
|
||||||
|
foreach ($event->getExceptions() as $exceptionDataBag) {
|
||||||
|
$exceptionBag[] = self::getAnonymizedSentryException($exceptionDataBag);
|
||||||
|
}
|
||||||
|
$event->setExceptions($exceptionBag);
|
||||||
|
return $event;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anonimize Sentry Exception bag
|
||||||
|
*
|
||||||
|
* @param \Sentry\ExceptionDataBag $exceptionDataBag
|
||||||
|
* @return \Sentry\ExceptionDataBag
|
||||||
|
*/
|
||||||
|
private static function getAnonymizedSentryException(
|
||||||
|
\Sentry\ExceptionDataBag $exceptionDataBag
|
||||||
|
): \Sentry\ExceptionDataBag {
|
||||||
|
$exceptionDataBag->setValue(self::getAnonymizedMessage($exceptionDataBag->getValue()));
|
||||||
|
if ($stackTrace = $exceptionDataBag->getStacktrace()) {
|
||||||
|
$exceptionDataBag->setStacktrace(self::getAnonymizedSentryStackTrace($stackTrace));
|
||||||
|
}
|
||||||
|
return $exceptionDataBag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anonymise sentry stacktrace
|
||||||
|
*
|
||||||
|
* @param \Sentry\Stacktrace $stackTrace
|
||||||
|
* @return \Sentry\Stacktrace
|
||||||
|
*/
|
||||||
|
private static function getAnonymizedSentryStackTrace(\Sentry\Stacktrace $stackTrace): \Sentry\Stacktrace
|
||||||
|
{
|
||||||
|
/** @var \Sentry\Frame[] */
|
||||||
|
$frames = \array_reverse($stackTrace->getFrames(), true);
|
||||||
|
$i = \count($frames) - 1;
|
||||||
|
// * Remove all but keep first (index.php).
|
||||||
|
while ($i-- > 0) {
|
||||||
|
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
|
||||||
|
}
|
||||||
|
foreach ($frames as $index => $frame) {
|
||||||
|
$frame->setPostContext([]);
|
||||||
|
$frame->setPreContext([]);
|
||||||
|
$frame->setContextLine('');
|
||||||
|
$frame->setVars(self::getAnonymizedSentryParams($frame->getVars()));
|
||||||
|
$stackTrace->addFrame($frame);
|
||||||
|
if ($index === 0) {
|
||||||
|
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $stackTrace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get anonymized sentry params
|
||||||
|
*
|
||||||
|
* @param mixed[] $params
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
private static function getAnonymizedSentryParams(array $params): array
|
||||||
|
{
|
||||||
|
foreach ($params as &$param) {
|
||||||
|
$type = \strtolower(\gettype($param));
|
||||||
|
if (\is_string($param)) {
|
||||||
|
$type = \explode(' ', \trim($param))[0] ?? null;
|
||||||
|
}
|
||||||
|
switch ($type) {
|
||||||
|
case 'Lambda':
|
||||||
|
case 'Object':
|
||||||
|
continue 2;
|
||||||
|
case 'array':
|
||||||
|
$param = sprintf('Array(%d)', \count($param));
|
||||||
|
continue 2;
|
||||||
|
default:
|
||||||
|
if (\is_numeric($param)) {
|
||||||
|
$param = \ucfirst($type);
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
if (\is_string($param)) {
|
||||||
|
$param = sprintf('String(%d)', \strlen($param));
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
} //end switch
|
||||||
|
} //end foreach
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anonymize at least Sql queries
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getAnonymizedMessage(string $message): string
|
||||||
|
{
|
||||||
|
$message = \preg_replace('/^(.*)( \(SQL:.*\))$/', '$1', $message) ?? $message;
|
||||||
|
if ($sqlPos = \strpos($message, 'to use near')) {
|
||||||
|
$message = \mb_strcut($message, 0, $sqlPos);
|
||||||
|
}
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anonymize stack trace
|
||||||
|
*
|
||||||
|
* @param \Throwable $e
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getAnonymizedStackTrace(\Throwable $e): string
|
||||||
|
{
|
||||||
|
$projectPath = \realpath(\sprintf('%s/../', \app_path()));
|
||||||
|
$traceStack = $e->getTrace();
|
||||||
|
$traceStr = '';
|
||||||
|
$maxStackStage = 0;
|
||||||
|
foreach ($traceStack as $stackStage => $stack) {
|
||||||
|
$maxStackStage = $stackStage;
|
||||||
|
$traceStr .= \sprintf(
|
||||||
|
'#%s %s(%d): ',
|
||||||
|
$stackStage,
|
||||||
|
str_replace($projectPath, '', $stack['file'] ?? ''),
|
||||||
|
$stack['line'] ?? ''
|
||||||
|
);
|
||||||
|
if (isset($stack['class'])) {
|
||||||
|
$traceStr .= "{$stack['class']}->{$stack['function']}(";
|
||||||
|
if (isset($stack['args'])) {
|
||||||
|
$traceStr .= self::handleArgs($stack);
|
||||||
|
}
|
||||||
|
$traceStr .= ")\n";
|
||||||
|
} elseif (isset($stack['function'])) {
|
||||||
|
$traceStr .= "{$stack['function']}(";
|
||||||
|
if (isset($stack['args'])) {
|
||||||
|
$traceStr .= self::handleArgs($stack);
|
||||||
|
}
|
||||||
|
$traceStr .= ")\n";
|
||||||
|
}
|
||||||
|
} //end foreach
|
||||||
|
$maxStackStage++;
|
||||||
|
$traceStr .= "#$maxStackStage {main}";
|
||||||
|
return $traceStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle Args
|
||||||
|
*
|
||||||
|
* @param array $stack
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function handleArgs(array $stack): string
|
||||||
|
{
|
||||||
|
$traceArgs = '';
|
||||||
|
$argsCount = count($stack['args']);
|
||||||
|
for ($i = 0; $i < $argsCount; $i++) {
|
||||||
|
$type = \gettype($stack['args'][$i]);
|
||||||
|
switch ($type) {
|
||||||
|
case 'object':
|
||||||
|
$traceArgs .= sprintf('Object(%s)', \get_class($stack['args'][$i]));
|
||||||
|
break;
|
||||||
|
case 'array':
|
||||||
|
$traceArgs .= sprintf('Array(%d)', \count($stack['args'][$i]));
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
$traceArgs .= sprintf('String(%d)', \strlen($stack['args'][$i]));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$traceArgs .= \gettype($stack['args'][$i]);
|
||||||
|
}
|
||||||
|
$traceArgs .= ($i !== ($argsCount - 1) ? ',' : '');
|
||||||
|
}
|
||||||
|
return $traceArgs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
"laravel/framework": "^8.12",
|
"laravel/framework": "^8.12",
|
||||||
"laravel/tinker": "^2.5",
|
"laravel/tinker": "^2.5",
|
||||||
"ldc/ldccrmv2client": "^3.0",
|
"ldc/ldccrmv2client": "^3.0",
|
||||||
|
"sentry/sentry-laravel": "^3.1",
|
||||||
"spatie/laravel-sitemap": "^5.8"
|
"spatie/laravel-sitemap": "^5.8"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|
|
||||||
1282
composer.lock
generated
1282
composer.lock
generated
File diff suppressed because it is too large
Load diff
62
config/sentry.php
Normal file
62
config/sentry.php
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
'dsn' => env('SENTRY_LARAVEL_DSN', env('SENTRY_DSN')),
|
||||||
|
|
||||||
|
// The release version of your application
|
||||||
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')).
|
||||||
|
'release' => env('SENTRY_RELEASE'),
|
||||||
|
|
||||||
|
// When left empty or `null` the Laravel environment will be used.
|
||||||
|
'environment' => env('SENTRY_ENVIRONMENT'),
|
||||||
|
|
||||||
|
'breadcrumbs' => [
|
||||||
|
// Capture Laravel logs in breadcrumbs.
|
||||||
|
'logs' => true,
|
||||||
|
|
||||||
|
// Capture SQL queries in breadcrumbs.
|
||||||
|
'sql_queries' => true,
|
||||||
|
|
||||||
|
// Capture bindings on SQL queries logged in breadcrumbs.
|
||||||
|
'sql_bindings' => false,
|
||||||
|
|
||||||
|
// Capture queue job information in breadcrumbs.
|
||||||
|
'queue_info' => true,
|
||||||
|
|
||||||
|
// Capture command information in breadcrumbs.
|
||||||
|
'command_info' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'tracing' => [
|
||||||
|
// Trace queue jobs as their own transactions.
|
||||||
|
'queue_job_transactions' => env('SENTRY_TRACE_QUEUE_ENABLED', false),
|
||||||
|
|
||||||
|
// Capture queue jobs as spans when executed on the sync driver.
|
||||||
|
'queue_jobs' => true,
|
||||||
|
|
||||||
|
// Capture SQL queries as spans.
|
||||||
|
'sql_queries' => true,
|
||||||
|
|
||||||
|
// Try to find out where the SQL query originated from and add it to the query spans.
|
||||||
|
'sql_origin' => true,
|
||||||
|
|
||||||
|
// Capture views as spans.
|
||||||
|
'views' => true,
|
||||||
|
|
||||||
|
// Indicates if the tracing integrations supplied by Sentry should be loaded.
|
||||||
|
'default_integrations' => true,
|
||||||
|
|
||||||
|
// Indicates that requests without a matching route should be traced.
|
||||||
|
'missing_routes' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send-default-pii
|
||||||
|
'send_default_pii' => env('SENTRY_SEND_DEFAULT_PII', false),
|
||||||
|
|
||||||
|
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#traces-sample-rate
|
||||||
|
'traces_sample_rate' => env('SENTRY_TRACES_SAMPLE_RATE') === null ? null : (float)env('SENTRY_TRACES_SAMPLE_RATE'),
|
||||||
|
|
||||||
|
'before_send' => [\App\Lib\ExceptionsHelper::class, 'sentryEventHandler'],
|
||||||
|
|
||||||
|
];
|
||||||
Loading…
Add table
Reference in a new issue