diff --git a/src/CheckIn.php b/src/CheckIn.php new file mode 100644 index 000000000..4257b5af0 --- /dev/null +++ b/src/CheckIn.php @@ -0,0 +1,117 @@ +setMonitorSlug($monitorSlug); + $this->setStatus($status); + + $this->setId($id ?? SentryUid::generate()); + $this->setRelease($release ?? ''); + $this->setEnvironment($environment ?? Event::DEFAULT_ENVIRONMENT); + $this->setDuration($duration); + } + + public function getId(): string + { + return $this->id; + } + + public function setId(string $id): void + { + $this->id = $id; + } + + public function getMonitorSlug(): string + { + return $this->monitorSlug; + } + + public function setMonitorSlug(string $monitorSlug): void + { + $this->monitorSlug = $monitorSlug; + } + + public function getStatus(): CheckInStatus + { + return $this->status; + } + + public function setStatus(CheckInStatus $status): void + { + $this->status = $status; + } + + public function getRelease(): ?string + { + return $this->release; + } + + public function setRelease(string $release): void + { + $this->release = $release; + } + + public function getEnvironment(): ?string + { + return $this->environment; + } + + public function setEnvironment(string $environment): void + { + $this->environment = $environment; + } + + public function getDuration(): ?int + { + return $this->duration; + } + + public function setDuration(?int $duration): void + { + $this->duration = $duration; + } +} diff --git a/src/CheckInStatus.php b/src/CheckInStatus.php new file mode 100644 index 000000000..c29547107 --- /dev/null +++ b/src/CheckInStatus.php @@ -0,0 +1,55 @@ + A list of cached enum instances + */ + private static $instances = []; + + private function __construct(string $value) + { + $this->value = $value; + } + + public static function ok(): self + { + return self::getInstance('ok'); + } + + public static function error(): self + { + return self::getInstance('error'); + } + + public static function inProgress(): self + { + return self::getInstance('in_progress'); + } + + public function __toString(): string + { + return $this->value; + } + + private static function getInstance(string $value): self + { + if (!isset(self::$instances[$value])) { + self::$instances[$value] = new self($value); + } + + return self::$instances[$value]; + } +} diff --git a/src/Event.php b/src/Event.php index 8f38d7aa5..41d93ef13 100644 --- a/src/Event.php +++ b/src/Event.php @@ -50,6 +50,11 @@ final class Event */ private $transaction; + /** + * @var CheckIn|null The check in data + */ + private $checkIn; + /** * @var string|null The name of the server (e.g. the host name) */ @@ -200,6 +205,11 @@ public static function createTransaction(EventId $eventId = null): self return new self($eventId, EventType::transaction()); } + public static function createCheckIn(?EventId $eventId = null): self + { + return new self($eventId, EventType::checkIn()); + } + /** * Gets the ID of this event. */ @@ -322,6 +332,16 @@ public function setTransaction(?string $transaction): void $this->transaction = $transaction; } + public function setCheckIn(?CheckIn $checkIn): void + { + $this->checkIn = $checkIn; + } + + public function getCheckIn(): ?CheckIn + { + return $this->checkIn; + } + /** * Gets the name of the server. */ diff --git a/src/EventType.php b/src/EventType.php index 0dc9e5398..c4e79c4d0 100644 --- a/src/EventType.php +++ b/src/EventType.php @@ -48,6 +48,11 @@ public static function transaction(): self return self::getInstance('transaction'); } + public static function checkIn(): self + { + return self::getInstance('check_in'); + } + public function __toString(): string { return $this->value; diff --git a/src/Serializer/PayloadSerializer.php b/src/Serializer/PayloadSerializer.php index 9eeaff0d7..09155fce4 100644 --- a/src/Serializer/PayloadSerializer.php +++ b/src/Serializer/PayloadSerializer.php @@ -53,6 +53,10 @@ public function serialize(Event $event): string return $transactionEnvelope; } + if (EventType::checkIn() === $event->getType()) { + return $this->serializeAsEnvelope($event); + } + return $this->serializeAsEvent($event); } @@ -63,6 +67,25 @@ private function serializeAsEvent(Event $event): string return JSON::encode($result); } + private function serializeAsCheckInEvent(Event $event): string + { + $result = []; + + $checkIn = $event->getCheckIn(); + if (null !== $checkIn) { + $result = [ + 'check_in_id' => $checkIn->getId(), + 'monitor_slug' => $checkIn->getMonitorSlug(), + 'status' => (string) $checkIn->getStatus(), + 'duration' => $checkIn->getDuration(), + 'release' => $checkIn->getRelease(), + 'environment' => $checkIn->getEnvironment(), + ]; + } + + return JSON::encode($result); + } + /** * @return array */ @@ -231,7 +254,15 @@ private function serializeAsEnvelope(Event $event): string 'content_type' => 'application/json', ]; - return sprintf("%s\n%s\n%s", JSON::encode($envelopeHeader), JSON::encode($itemHeader), $this->serializeAsEvent($event)); + $seralizedEvent = ''; + if (EventType::transaction() === $event->getType()) { + $seralizedEvent = $this->serializeAsEvent($event); + } + if (EventType::checkIn() === $event->getType()) { + $seralizedEvent = $this->serializeAsCheckInEvent($event); + } + + return sprintf("%s\n%s\n%s", JSON::encode($envelopeHeader), JSON::encode($itemHeader), $seralizedEvent); } private function seralizeProfileAsEnvelope(Event $event): ?string diff --git a/src/Transport/HttpTransport.php b/src/Transport/HttpTransport.php index c3ca0d07e..74186be85 100644 --- a/src/Transport/HttpTransport.php +++ b/src/Transport/HttpTransport.php @@ -112,7 +112,10 @@ public function send(Event $event): PromiseInterface return new RejectedPromise(new Response(ResponseStatus::rateLimit(), $event)); } - if (EventType::transaction() === $eventType) { + if ( + EventType::transaction() === $eventType || + EventType::checkIn() === $eventType + ) { $request = $this->requestFactory->createRequest('POST', $dsn->getEnvelopeApiEndpointUrl()) ->withHeader('Content-Type', 'application/x-sentry-envelope') ->withBody($this->streamFactory->createStream($this->payloadSerializer->serialize($event))); diff --git a/tests/CheckInTest.php b/tests/CheckInTest.php new file mode 100644 index 000000000..4380ebd40 --- /dev/null +++ b/tests/CheckInTest.php @@ -0,0 +1,59 @@ +assertEquals($checkInId, $checkIn->getId()); + $this->assertEquals('my-monitor', $checkIn->getMonitorSlug()); + $this->assertEquals('ok', $checkIn->getStatus()); + $this->assertEquals('1.0.0', $checkIn->getRelease()); + $this->assertEquals('dev', $checkIn->getEnvironment()); + $this->assertEquals(10, $checkIn->getDuration()); + } + + /** + * @dataProvider gettersAndSettersDataProvider + */ + public function testGettersAndSetters(string $getterMethod, string $setterMethod, $expectedData): void + { + $checkIn = new CheckIn( + 'my-monitor', + CheckInStatus::ok() + ); + $checkIn->$setterMethod($expectedData); + + $this->assertEquals($expectedData, $checkIn->$getterMethod()); + } + + public function gettersAndSettersDataProvider(): array + { + return [ + ['getId', 'setId', SentryUid::generate()], + ['getMonitorSlug', 'setMonitorSlug', 'my-monitor'], + ['getStatus', 'setStatus', CheckInStatus::ok()], + ['getRelease', 'setRelease', '1.0.0'], + ['getEnvironment', 'setEnvironment', 'dev'], + ['getDuration', 'setDuration', 10], + ]; + } +} diff --git a/tests/Serializer/PayloadSerializerTest.php b/tests/Serializer/PayloadSerializerTest.php index ea8663113..afafc33de 100644 --- a/tests/Serializer/PayloadSerializerTest.php +++ b/tests/Serializer/PayloadSerializerTest.php @@ -6,6 +6,8 @@ use PHPUnit\Framework\TestCase; use Sentry\Breadcrumb; +use Sentry\CheckIn; +use Sentry\CheckInStatus; use Sentry\Client; use Sentry\Context\OsContext; use Sentry\Context\RuntimeContext; @@ -27,6 +29,7 @@ use Sentry\Tracing\TraceId; use Sentry\Tracing\TransactionMetadata; use Sentry\UserDataBag; +use Sentry\Util\SentryUid; use Symfony\Bridge\PhpUnit\ClockMock; /** @@ -55,7 +58,10 @@ public function testSerialize(Event $event, string $expectedResult, bool $isOutp $result = $this->serializer->serialize($event); - if (EventType::transaction() !== $event->getType()) { + if ( + EventType::transaction() !== $event->getType() && + EventType::checkIn() !== $event->getType() + ) { $resultArray = $this->serializer->toArray($event); $this->assertJsonStringEqualsJsonString($result, json_encode($resultArray)); } @@ -538,5 +544,50 @@ public function serializeDataProvider(): iterable , true, ]; + + $checkinId = SentryUid::generate(); + $checkIn = new CheckIn( + 'my-monitor', + CheckInStatus::ok(), + $checkinId, + '1.0.0', + 'dev', + 10 + ); + + $event = Event::createCheckIn(new EventId('fc9442f5aef34234bb22b9a615e30ccd')); + $event->setCheckIn($checkIn); + + yield [ + $event, + <<setCheckIn($checkIn); + + yield [ + $event, + <<