diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index b4ba6d8..185e138 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,3 +1,5 @@ 0b3432d95fa080f1ceda922d0b95bd7a3cdcf0ee 2c9660debe53324156654726ddecf5bb04137c51 0b4771d854aa254e7e618e02e82d8f909aa3a003 +3bd1a83d82ecd2ba335c084e85a837aa81bdf5ab +66cd5bd2cfb3463dfd7da224a15b043d0173a10e diff --git a/composer.json b/composer.json index 9156c4b..f4efb35 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,7 @@ "extra": { "laravel": { "providers": [ - "TahsinGokalp\\Lett\\LettServiceProvider" + "TahsinGokalp\\Lett\\ServiceProvider" ], "aliases": { "Lett": "TahsinGokalp\\Lett\\Facades\\Lett" diff --git a/config/lett.php b/config/lett.php index 30e5a4c..6dec560 100644 --- a/config/lett.php +++ b/config/lett.php @@ -83,6 +83,8 @@ 'sleep' => env('LETT_SLEEP', 60), + 'timeout' => env('LETT_CLIENT_TIMEOUT', 15), + /* |-------------------------------------------------------------------------- | Skip exceptions diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 768d487..519ad0f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,7 +2,7 @@ includes: - phpstan-baseline.neon parameters: - level: 5 + level: 6 paths: - src - config diff --git a/src/Client.php b/src/Client.php new file mode 100644 index 0000000..2c9fed9 --- /dev/null +++ b/src/Client.php @@ -0,0 +1,74 @@ +login = $login; + $this->project = $project; + $this->timeout = config('lett.timeout'); + $this->client = $client ?: Http::timeout($this->timeout); + } + + public function report(array $exception): PromiseInterface|ResponseInterface|null + { + try { + return $this->getHttpClient() + ->withToken($this->login) + ->asJson() + ->acceptJson() + ->withUserAgent('Lett-Package') + ->when( + ! config('lett.verify_ssl'), + function ($client) { + $client->withoutVerifying(); + } + ) + ->post( + config('lett.server'), + array_merge( + [ + 'project' => $this->project, + 'additional' => [], + ], + $exception + ) + )->toPsrResponse(); + } catch (RequestException $e) { + return $e->getResponse(); + } catch (GuzzleException|Exception) { + return null; + } + } + + public function getHttpClient(): PendingRequest|ClientInterface + { + return $this->client; + } + + public function setHttpClient(\GuzzleHttp\Client $client): self + { + $this->client = Http::timeout($this->timeout)->setClient($client)->buildClient(); + + return $this; + } +} diff --git a/src/Handler/LettHandler.php b/src/Handler/LogHandler.php similarity index 82% rename from src/Handler/LettHandler.php rename to src/Handler/LogHandler.php index 9c32ca7..9bc7156 100644 --- a/src/Handler/LettHandler.php +++ b/src/Handler/LogHandler.php @@ -4,10 +4,11 @@ use Monolog\Handler\AbstractProcessingHandler; use Monolog\Level; +use Monolog\LogRecord; use TahsinGokalp\Lett\Lett; use Throwable; -class LettHandler extends AbstractProcessingHandler +class LogHandler extends AbstractProcessingHandler { protected Lett $lett; @@ -18,7 +19,7 @@ public function __construct(Lett $lett, Level $level = Level::Error, bool $bubbl parent::__construct($level, $bubble); } - protected function write($record): void + protected function write(LogRecord $record): void { if (isset($record['context']['exception']) && $record['context']['exception'] instanceof Throwable) { $this->lett->handle( diff --git a/src/Http/Client.php b/src/Http/Client.php deleted file mode 100644 index 78343cc..0000000 --- a/src/Http/Client.php +++ /dev/null @@ -1,74 +0,0 @@ -login = $login; - $this->project = $project; - $this->client = $client; - } - - /** - * @throws GuzzleException - */ - public function report(array $exception): PromiseInterface|ResponseInterface|null - { - if ($this->getGuzzleHttpClient() === null) { - return null; - } - - try { - return $this->getGuzzleHttpClient()->request('POST', config('lett.server'), [ - 'headers' => [ - 'Authorization' => 'Bearer ' . $this->login, - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', - 'User-Agent' => 'Lett-Package', - ], - 'json' => array_merge([ - 'project' => $this->project, - 'additional' => [], - ], $exception), - 'verify' => config('lett.verify_ssl'), - ]); - } catch (RequestException $e) { - return $e->getResponse(); - } catch (Exception $e) { - return null; - } - } - - public function getGuzzleHttpClient(): \GuzzleHttp\Client|ClientInterface|null - { - if (! isset($this->client)) { - $this->client = new \GuzzleHttp\Client([ - 'timeout' => 15, - ]); - } - - return $this->client; - } - - public function setGuzzleHttpClient($client): static - { - $this->client = $client; - - return $this; - } -} diff --git a/src/Lett.php b/src/Lett.php index 474a236..5519f51 100755 --- a/src/Lett.php +++ b/src/Lett.php @@ -2,7 +2,6 @@ namespace TahsinGokalp\Lett; -use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Promise\PromiseInterface; use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Application; @@ -15,7 +14,6 @@ use JsonException; use Psr\Http\Message\ResponseInterface; use TahsinGokalp\Lett\Concerns\Lettable; -use TahsinGokalp\Lett\Http\Client; use Throwable; class Lett @@ -24,8 +22,6 @@ class Lett private array $blacklist; - private ?string $lastExceptionId; - public function __construct(Client $client) { $this->client = $client; @@ -35,7 +31,7 @@ public function __construct(Client $client) }, config('lett.blacklist', [])); } - public function handle(Throwable $exception, string $fileType = 'php', array $customData = []) + public function handle(Throwable $exception, string $fileType = 'php', array $customData = []): mixed { $data = $this->getExceptionData($exception); @@ -44,7 +40,7 @@ public function handle(Throwable $exception, string $fileType = 'php', array $cu return false; } - if ((string) $fileType === 'javascript') { + if ($fileType === 'javascript') { $data['fullUrl'] = $customData['url']; $data['file'] = $customData['file']; $data['file_type'] = $fileType; @@ -88,14 +84,10 @@ public function handle(Throwable $exception, string $fileType = 'php', array $cu try { $response = json_decode($rawResponse->getBody()->getContents(), false, 512, JSON_THROW_ON_ERROR); - } catch (JsonException $e) { + } catch (JsonException) { return false; } - if (isset($response->id)) { - $this->setLastExceptionId($response->id); - } - if (config('lett.sleep') !== 0) { $this->addExceptionToSleep($data); } @@ -116,11 +108,6 @@ public function isSkipEnvironment(): bool return true; } - public function getLastExceptionId(): ?string - { - return $this->lastExceptionId ?? null; - } - public function getExceptionData(Throwable $exception): array { $data = []; @@ -165,12 +152,12 @@ public function getExceptionData(Throwable $exception): array } for ($i = -1 * abs($count); $i <= abs($count); $i++) { - $data['executor'][] = $this->getLineInfo($lines, $data['line'], $i); + $data['executor'][] = $this->getLineInfo($lines, (int) $data['line'], $i); } $data['executor'] = array_filter($data['executor']); // Get project version - $data['project_version'] = config('lett.project_version', null); + $data['project_version'] = config('lett.project_version'); // to make symfony exception more readable if ($data['class'] === 'Symfony\Component\Debug\Exception\FatalErrorException') { @@ -199,7 +186,7 @@ public function shouldParameterValueBeFiltered(mixed $value): bool return $value instanceof UploadedFile; } - public function filterVariables($variables): array + public function filterVariables(mixed $variables): array { if (is_array($variables)) { array_walk($variables, function ($val, $key) use (&$variables) { @@ -219,7 +206,7 @@ public function filterVariables($variables): array return []; } - public function isSkipException($exceptionClass): bool + public function isSkipException(string $exceptionClass): bool { return in_array((string) $exceptionClass, config('lett.except'), true); } @@ -257,12 +244,7 @@ public function addExceptionToSleep(array $data): bool return Cache::put($exceptionString, $exceptionString, config('lett.sleep')); } - private function setLastExceptionId(?string $id): void - { - $this->lastExceptionId = $id; - } - - private function getLineInfo($lines, $line, $i): array + private function getLineInfo(array $lines, int $line, int $i): array { $currentLine = $line + $i; @@ -285,15 +267,11 @@ private function createExceptionString(array $data): string . $data['file'] . '_' . $data['class']); } - private function logError($exception): PromiseInterface|ResponseInterface|null + private function logError(array $exception): PromiseInterface|ResponseInterface|null { - try { - return $this->client->report([ - 'exception' => $exception, - 'user' => $this->getUser(), - ]); - } catch (GuzzleException $e) { - return null; - } + return $this->client->report([ + 'exception' => $exception, + 'user' => $this->getUser(), + ]); } } diff --git a/src/LettServiceProvider.php b/src/ServiceProvider.php similarity index 89% rename from src/LettServiceProvider.php rename to src/ServiceProvider.php index e956374..eec65f8 100644 --- a/src/LettServiceProvider.php +++ b/src/ServiceProvider.php @@ -8,10 +8,9 @@ use Monolog\Logger; use TahsinGokalp\Lett\Commands\DoctorCommand; use TahsinGokalp\Lett\Commands\TestCommand; -use TahsinGokalp\Lett\Handler\LettHandler; -use TahsinGokalp\Lett\Http\Client; +use TahsinGokalp\Lett\Handler\LogHandler; -class LettServiceProvider extends BaseServiceProvider +class ServiceProvider extends BaseServiceProvider { public function boot(): void { @@ -48,7 +47,7 @@ public function register(): void if ($this->app['log'] instanceof LogManager) { $this->app['log']->extend('lett', function ($app) { - $handler = new LettHandler( + $handler = new LogHandler( $app['lett'] ); diff --git a/tests/Fakes/LettFake.php b/tests/Fakes/LettFake.php index 8e9c2c4..cd16127 100644 --- a/tests/Fakes/LettFake.php +++ b/tests/Fakes/LettFake.php @@ -4,7 +4,6 @@ use GuzzleHttp\Psr7\Response; use JsonException; -use PHPUnit\Framework\Assert as PHPUnit; use TahsinGokalp\Lett\Lett; use Throwable; @@ -17,45 +16,10 @@ public function requestsSent(): array return $this->exceptions; } - public function assertNotSent(mixed $throwable, callable $callback = null): void - { - $collect = collect($this->exceptions[$throwable] ?? []); - - $callback = $callback ?: static function () { - return true; - }; - - $filtered = $collect->filter(function ($arguments) use ($callback) { - return $callback($arguments); - }); - - PHPUnit::assertEquals($filtered->count(), 0); - } - - public function assertNothingSent(): void - { - PHPUnit::assertCount(0, $this->exceptions); - } - - public function assertSent(mixed $throwable, callable $callback = null): void - { - $collect = collect($this->exceptions[$throwable] ?? []); - - $callback = $callback ?: static function () { - return true; - }; - - $filtered = $collect->filter(function ($arguments) use ($callback) { - return $callback($arguments); - }); - - PHPUnit::assertTrue($filtered->count() > 0); - } - /** * @throws JsonException */ - public function handle(Throwable $exception, $fileType = 'php', array $customData = []) + public function handle(Throwable $exception, $fileType = 'php', array $customData = []): mixed { $this->exceptions[get_class($exception)][] = $exception; diff --git a/tests/LettTest.php b/tests/LettTest.php index ea638ed..b82fc71 100644 --- a/tests/LettTest.php +++ b/tests/LettTest.php @@ -16,7 +16,7 @@ config()->set('lett.environments', ['testing']); - $client->setGuzzleHttpClient(new Client([ + $client->setHttpClient(new Client([ 'handler' => MockHandler::createWithMiddleware([ new Response(500, [], '{}'), ]), @@ -35,7 +35,7 @@ config()->set('lett.environments', ['testing']); - $client->setGuzzleHttpClient(new Client([ + $client->setHttpClient(new Client([ 'handler' => MockHandler::createWithMiddleware([ new Exception, ]), diff --git a/tests/Mocks/LettClient.php b/tests/Mocks/LettClient.php index 2264271..80cfc30 100644 --- a/tests/Mocks/LettClient.php +++ b/tests/Mocks/LettClient.php @@ -4,7 +4,7 @@ use GuzzleHttp\Psr7\Response; use JsonException; -use TahsinGokalp\Lett\Http\Client; +use TahsinGokalp\Lett\Client; class LettClient extends Client { diff --git a/tests/TestCase.php b/tests/TestCase.php index 8066dca..4074ee7 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -3,7 +3,7 @@ namespace TahsinGokalp\Lett\Tests; use Orchestra\Testbench\TestCase as Orchestra; -use TahsinGokalp\Lett\LettServiceProvider; +use TahsinGokalp\Lett\ServiceProvider; class TestCase extends Orchestra { @@ -15,7 +15,7 @@ public function getEnvironmentSetUp($app): void protected function getPackageProviders($app): array { return [ - LettServiceProvider::class, + ServiceProvider::class, ]; } }