334 lines
8.5 KiB
PHP
334 lines
8.5 KiB
PHP
<?php
|
|
|
|
namespace Facade\FlareClient;
|
|
|
|
use Error;
|
|
use ErrorException;
|
|
use Exception;
|
|
use Facade\FlareClient\Concerns\HasContext;
|
|
use Facade\FlareClient\Context\ContextContextDetector;
|
|
use Facade\FlareClient\Context\ContextDetectorInterface;
|
|
use Facade\FlareClient\Enums\MessageLevels;
|
|
use Facade\FlareClient\Glows\Glow;
|
|
use Facade\FlareClient\Glows\Recorder;
|
|
use Facade\FlareClient\Http\Client;
|
|
use Facade\FlareClient\Middleware\AddGlows;
|
|
use Facade\FlareClient\Middleware\AnonymizeIp;
|
|
use Facade\FlareClient\Middleware\CensorRequestBodyFields;
|
|
use Illuminate\Contracts\Container\Container;
|
|
use Illuminate\Pipeline\Pipeline;
|
|
use Throwable;
|
|
|
|
class Flare
|
|
{
|
|
use HasContext;
|
|
|
|
/** @var \Facade\FlareClient\Http\Client */
|
|
protected $client;
|
|
|
|
/** @var \Facade\FlareClient\Api */
|
|
protected $api;
|
|
|
|
/** @var array */
|
|
protected $middleware = [];
|
|
|
|
/** @var \Facade\FlareClient\Glows\Recorder */
|
|
protected $recorder;
|
|
|
|
/** @var string */
|
|
protected $applicationPath;
|
|
|
|
/** @var \Illuminate\Contracts\Container\Container|null */
|
|
protected $container;
|
|
|
|
/** @var ContextDetectorInterface */
|
|
protected $contextDetector;
|
|
|
|
/** @var callable|null */
|
|
protected $previousExceptionHandler;
|
|
|
|
/** @var callable|null */
|
|
protected $previousErrorHandler;
|
|
|
|
/** @var callable|null */
|
|
protected $determineVersionCallable;
|
|
|
|
/** @var int|null */
|
|
protected $reportErrorLevels;
|
|
|
|
/** @var callable|null */
|
|
protected $filterExceptionsCallable;
|
|
|
|
/** @var callable|null */
|
|
protected $filterReportsCallable;
|
|
|
|
public static function register(string $apiKey, string $apiSecret = null, ContextDetectorInterface $contextDetector = null, Container $container = null)
|
|
{
|
|
$client = new Client($apiKey, $apiSecret);
|
|
|
|
return new static($client, $contextDetector, $container);
|
|
}
|
|
|
|
public function determineVersionUsing($determineVersionCallable)
|
|
{
|
|
$this->determineVersionCallable = $determineVersionCallable;
|
|
}
|
|
|
|
public function reportErrorLevels(int $reportErrorLevels)
|
|
{
|
|
$this->reportErrorLevels = $reportErrorLevels;
|
|
}
|
|
|
|
public function filterExceptionsUsing(callable $filterExceptionsCallable)
|
|
{
|
|
$this->filterExceptionsCallable = $filterExceptionsCallable;
|
|
}
|
|
|
|
public function filterReportsUsing(callable $filterReportsCallable)
|
|
{
|
|
$this->filterReportsCallable = $filterReportsCallable;
|
|
}
|
|
|
|
/**
|
|
* @return null|string
|
|
*/
|
|
public function version()
|
|
{
|
|
if (! $this->determineVersionCallable) {
|
|
return null;
|
|
}
|
|
|
|
return ($this->determineVersionCallable)();
|
|
}
|
|
|
|
public function __construct(Client $client, ContextDetectorInterface $contextDetector = null, Container $container = null, array $middleware = [])
|
|
{
|
|
$this->client = $client;
|
|
$this->recorder = new Recorder();
|
|
$this->contextDetector = $contextDetector ?? new ContextContextDetector();
|
|
$this->container = $container;
|
|
$this->middleware = $middleware;
|
|
$this->api = new Api($this->client);
|
|
|
|
$this->registerDefaultMiddleware();
|
|
}
|
|
|
|
public function getMiddleware(): array
|
|
{
|
|
return $this->middleware;
|
|
}
|
|
|
|
public function registerFlareHandlers()
|
|
{
|
|
$this->registerExceptionHandler();
|
|
$this->registerErrorHandler();
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function registerExceptionHandler()
|
|
{
|
|
$this->previousExceptionHandler = set_exception_handler([$this, 'handleException']);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function registerErrorHandler()
|
|
{
|
|
$this->previousErrorHandler = set_error_handler([$this, 'handleError']);
|
|
|
|
return $this;
|
|
}
|
|
|
|
private function registerDefaultMiddleware()
|
|
{
|
|
return $this->registerMiddleware(new AddGlows($this->recorder));
|
|
}
|
|
|
|
public function registerMiddleware($callable)
|
|
{
|
|
$this->middleware[] = $callable;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getMiddlewares(): array
|
|
{
|
|
return $this->middleware;
|
|
}
|
|
|
|
public function glow(
|
|
string $name,
|
|
string $messageLevel = MessageLevels::INFO,
|
|
array $metaData = []
|
|
) {
|
|
$this->recorder->record(new Glow($name, $messageLevel, $metaData));
|
|
}
|
|
|
|
public function handleException(Throwable $throwable)
|
|
{
|
|
$this->report($throwable);
|
|
|
|
if ($this->previousExceptionHandler) {
|
|
call_user_func($this->previousExceptionHandler, $throwable);
|
|
}
|
|
}
|
|
|
|
public function handleError($code, $message, $file = '', $line = 0)
|
|
{
|
|
$exception = new ErrorException($message, 0, $code, $file, $line);
|
|
|
|
$this->report($exception);
|
|
|
|
if ($this->previousErrorHandler) {
|
|
return call_user_func(
|
|
$this->previousErrorHandler,
|
|
$message,
|
|
$code,
|
|
$file,
|
|
$line
|
|
);
|
|
}
|
|
}
|
|
|
|
public function applicationPath(string $applicationPath)
|
|
{
|
|
$this->applicationPath = $applicationPath;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function report(Throwable $throwable, callable $callback = null): ?Report
|
|
{
|
|
if (! $this->shouldSendReport($throwable)) {
|
|
return null;
|
|
}
|
|
|
|
$report = $this->createReport($throwable);
|
|
|
|
if (! is_null($callback)) {
|
|
call_user_func($callback, $report);
|
|
}
|
|
|
|
$this->sendReportToApi($report);
|
|
|
|
return $report;
|
|
}
|
|
|
|
protected function shouldSendReport(Throwable $throwable): bool
|
|
{
|
|
if ($this->reportErrorLevels && $throwable instanceof Error) {
|
|
return $this->reportErrorLevels & $throwable->getCode();
|
|
}
|
|
|
|
if ($this->reportErrorLevels && $throwable instanceof ErrorException) {
|
|
return $this->reportErrorLevels & $throwable->getSeverity();
|
|
}
|
|
|
|
if ($this->filterExceptionsCallable && $throwable instanceof Exception) {
|
|
return call_user_func($this->filterExceptionsCallable, $throwable);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function reportMessage(string $message, string $logLevel, callable $callback = null)
|
|
{
|
|
$report = $this->createReportFromMessage($message, $logLevel);
|
|
|
|
if (! is_null($callback)) {
|
|
call_user_func($callback, $report);
|
|
}
|
|
|
|
$this->sendReportToApi($report);
|
|
}
|
|
|
|
public function sendTestReport(Throwable $throwable)
|
|
{
|
|
$this->api->sendTestReport($this->createReport($throwable));
|
|
}
|
|
|
|
private function sendReportToApi(Report $report)
|
|
{
|
|
if ($this->filterReportsCallable) {
|
|
if (! call_user_func($this->filterReportsCallable, $report)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
try {
|
|
$this->api->report($report);
|
|
} catch (Exception $exception) {
|
|
}
|
|
}
|
|
|
|
public function reset()
|
|
{
|
|
$this->api->sendQueuedReports();
|
|
|
|
$this->userProvidedContext = [];
|
|
$this->recorder->reset();
|
|
}
|
|
|
|
private function applyAdditionalParameters(Report $report)
|
|
{
|
|
$report
|
|
->stage($this->stage)
|
|
->messageLevel($this->messageLevel)
|
|
->setApplicationPath($this->applicationPath)
|
|
->userProvidedContext($this->userProvidedContext);
|
|
}
|
|
|
|
public function anonymizeIp()
|
|
{
|
|
$this->registerMiddleware(new AnonymizeIp());
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function censorRequestBodyFields(array $fieldNames)
|
|
{
|
|
$this->registerMiddleware(new CensorRequestBodyFields($fieldNames));
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function createReport(Throwable $throwable): Report
|
|
{
|
|
$report = Report::createForThrowable(
|
|
$throwable,
|
|
$this->contextDetector->detectCurrentContext(),
|
|
$this->applicationPath,
|
|
$this->version()
|
|
);
|
|
|
|
return $this->applyMiddlewareToReport($report);
|
|
}
|
|
|
|
public function createReportFromMessage(string $message, string $logLevel): Report
|
|
{
|
|
$report = Report::createForMessage(
|
|
$message,
|
|
$logLevel,
|
|
$this->contextDetector->detectCurrentContext(),
|
|
$this->applicationPath
|
|
);
|
|
|
|
return $this->applyMiddlewareToReport($report);
|
|
}
|
|
|
|
protected function applyMiddlewareToReport(Report $report): Report
|
|
{
|
|
$this->applyAdditionalParameters($report);
|
|
|
|
$report = (new Pipeline($this->container))
|
|
->send($report)
|
|
->through($this->middleware)
|
|
->then(function ($report) {
|
|
return $report;
|
|
});
|
|
|
|
return $report;
|
|
}
|
|
}
|