Skip to content

Commit

Permalink
feat: Add support for Cron Monitoring (#1467)
Browse files Browse the repository at this point in the history
  • Loading branch information
cleptric authored Mar 14, 2023
1 parent 94e1a8e commit 192e88e
Show file tree
Hide file tree
Showing 8 changed files with 344 additions and 3 deletions.
117 changes: 117 additions & 0 deletions src/CheckIn.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

declare(strict_types=1);

namespace Sentry;

use Sentry\Util\SentryUid;

final class CheckIn
{
/**
* @var string The check-in ID
*/
private $id;

/**
* @var string The monitor slug
*/
private $monitorSlug;

/**
* @var \Sentry\CheckInStatus The status of the check-in
*/
private $status;

/**
* @var string|null The release
*/
private $release;

/**
* @var string|null The environment
*/
private $environment;

/**
* @var int|null The duration of the check in seconds
*/
private $duration;

public function __construct(
string $monitorSlug,
CheckInStatus $status,
string $id = null,
?string $release = null,
?string $environment = null,
?int $duration = null
) {
$this->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;
}
}
55 changes: 55 additions & 0 deletions src/CheckInStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Sentry;

/**
* This enum represents all the possible status of a check in.
*/
final class CheckInStatus implements \Stringable
{
/**
* @var string The value of the enum instance
*/
private $value;

/**
* @var array<string, self> 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];
}
}
20 changes: 20 additions & 0 deletions src/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
*/
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/EventType.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
33 changes: 32 additions & 1 deletion src/Serializer/PayloadSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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<string, mixed>
*/
Expand Down Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion src/Transport/HttpTransport.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Expand Down
59 changes: 59 additions & 0 deletions tests/CheckInTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace Sentry\Tests;

use PHPUnit\Framework\TestCase;
use Sentry\CheckIn;
use Sentry\CheckInStatus;
use Sentry\Util\SentryUid;

final class CheckInTest extends TestCase
{
public function testConstructor(): void
{
$checkInId = SentryUid::generate();
$checkIn = new CheckIn(
'my-monitor',
CheckInStatus::ok(),
$checkInId,
'1.0.0',
'dev',
10
);

$this->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],
];
}
}
Loading

0 comments on commit 192e88e

Please sign in to comment.