diff --git a/composer.json b/composer.json index d81a59a5..b1eef3d8 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "require": { "php": "^7.2 | ^8.0", "illuminate/support": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0", - "sentry/sentry": "^3.12", + "sentry/sentry": "^3.16", "sentry/sdk": "^3.3", "symfony/psr-http-message-bridge": "^1.0 | ^2.0", "nyholm/psr7": "^1.0" diff --git a/src/Sentry/Laravel/Features/ConsoleIntegration.php b/src/Sentry/Laravel/Features/ConsoleIntegration.php new file mode 100644 index 00000000..ba0b5cef --- /dev/null +++ b/src/Sentry/Laravel/Features/ConsoleIntegration.php @@ -0,0 +1,92 @@ + The list of checkins that are currently in progress. + */ + private $checkInStore = []; + + public function isApplicable(): bool + { + return $this->container()->make(Application::class)->runningInConsole(); + } + + public function setup(): void + { + $startCheckIn = function (string $mutex, string $slug) { + $this->startCheckIn($mutex, $slug); + }; + $finishCheckIn = function (string $mutex, CheckInStatus $status) { + $this->finishCheckIn($mutex, $status); + }; + + SchedulingEvent::macro('sentryMonitor', function (string $monitorSlug) use ($startCheckIn, $finishCheckIn) { + /** @var SchedulingEvent $this */ + return $this + ->before(function () use ($startCheckIn, $monitorSlug) { + /** @var SchedulingEvent $this */ + $startCheckIn($this->mutexName(), $monitorSlug); + }) + ->onSuccess(function () use ($finishCheckIn) { + /** @var SchedulingEvent $this */ + $finishCheckIn($this->mutexName(), CheckInStatus::ok()); + }) + ->onFailure(function () use ($finishCheckIn) { + /** @var SchedulingEvent $this */ + $finishCheckIn($this->mutexName(), CheckInStatus::error()); + }); + }); + } + + private function startCheckIn(string $mutex, string $slug): void + { + $options = SentrySdk::getCurrentHub()->getClient()->getOptions(); + + $checkIn = new CheckIn( + $slug, + CheckInStatus::inProgress(), + null, + $options->getEnvironment(), + $options->getRelease() + ); + + $this->checkInStore[$mutex] = $checkIn; + + $this->sendCheckIn($checkIn); + } + + private function finishCheckIn(string $mutex, CheckInStatus $status): void + { + $checkIn = $this->checkInStore[$mutex] ?? null; + + // This should never happen (because we should always start before we finish), but better safe than sorry + if ($checkIn === null) { + return; + } + + // We don't need to keep the checkin in memory anymore since we finished + unset($this->checkInStore[$mutex]); + + $checkIn->setStatus($status); + + $this->sendCheckIn($checkIn); + } + + private function sendCheckIn(CheckIn $checkIn): void + { + $event = SentryEvent::createCheckIn(); + $event->setCheckIn($checkIn); + + SentrySdk::getCurrentHub()->captureEvent($event); + } +} diff --git a/src/Sentry/Laravel/ServiceProvider.php b/src/Sentry/Laravel/ServiceProvider.php index 6774589a..dac85af9 100644 --- a/src/Sentry/Laravel/ServiceProvider.php +++ b/src/Sentry/Laravel/ServiceProvider.php @@ -45,6 +45,7 @@ class ServiceProvider extends BaseServiceProvider */ protected const FEATURES = [ Features\CacheIntegration::class, + Features\ConsoleIntegration::class, Features\LivewirePackageIntegration::class, ];