From 62bb5b70bc2c83d0767f13f5ee7cba8c0c83a137 Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Tue, 31 Oct 2023 04:51:16 +0100 Subject: [PATCH] Add DDM support --- src/Event.php | 28 ++++++++ src/EventType.php | 5 ++ src/Serializer/EnvelopItems/MetricsItem.php | 31 ++++++++ src/Serializer/PayloadSerializer.php | 4 ++ src/State/Hub.php | 78 +++++++++++++++++++++ src/State/HubInterface.php | 9 +++ src/functions.php | 27 +++++++ 7 files changed, 182 insertions(+) create mode 100644 src/Serializer/EnvelopItems/MetricsItem.php diff --git a/src/Event.php b/src/Event.php index b9fd06e27..83d5a4b1b 100644 --- a/src/Event.php +++ b/src/Event.php @@ -55,6 +55,11 @@ final class Event */ private $checkIn; + /** + * @var array|float|int|string>|null The check in data + */ + private $metric; + /** * @var string|null The name of the server (e.g. the host name) */ @@ -210,6 +215,11 @@ public static function createCheckIn(?EventId $eventId = null): self return new self($eventId, EventType::checkIn()); } + public static function createMetric(?EventId $eventId = null): self + { + return new self($eventId, EventType::metric()); + } + /** * Gets the ID of this event. */ @@ -354,6 +364,24 @@ public function setCheckIn(?CheckIn $checkIn): self return $this; } + /** + * @return array|float|int|string>|null + */ + public function getMetric(): ?array + { + return $this->metric; + } + + /** + * @param array|float|int|string> $metric + */ + public function setMetric(array $metric): self + { + $this->metric = $metric; + + return $this; + } + /** * Gets the name of the server. */ diff --git a/src/EventType.php b/src/EventType.php index beb04930f..7fdaaa183 100644 --- a/src/EventType.php +++ b/src/EventType.php @@ -42,6 +42,11 @@ public static function checkIn(): self return self::getInstance('check_in'); } + public static function metric(): self + { + return self::getInstance('metric_buckets'); + } + public function __toString(): string { return $this->value; diff --git a/src/Serializer/EnvelopItems/MetricsItem.php b/src/Serializer/EnvelopItems/MetricsItem.php new file mode 100644 index 000000000..8f6455646 --- /dev/null +++ b/src/Serializer/EnvelopItems/MetricsItem.php @@ -0,0 +1,31 @@ + (string) $event->getType(), + 'content_type' => 'application/json', + ]; + + $payload = []; + + $metric = $event->getMetric(); + if ($event->getMetric() !== null) { + $payload[] = $metric; + } + + return sprintf("%s\n%s", JSON::encode($header), JSON::encode($payload)); + } +} diff --git a/src/Serializer/PayloadSerializer.php b/src/Serializer/PayloadSerializer.php index ad1365b3a..589e79e57 100644 --- a/src/Serializer/PayloadSerializer.php +++ b/src/Serializer/PayloadSerializer.php @@ -9,6 +9,7 @@ use Sentry\Options; use Sentry\Serializer\EnvelopItems\CheckInItem; use Sentry\Serializer\EnvelopItems\EventItem; +use Sentry\Serializer\EnvelopItems\MetricsItem; use Sentry\Serializer\EnvelopItems\ProfileItem; use Sentry\Serializer\EnvelopItems\TransactionItem; use Sentry\Tracing\DynamicSamplingContext; @@ -77,6 +78,9 @@ public function serialize(Event $event): string case EventType::checkIn(): $items = CheckInItem::toEnvelopeItem($event); break; + case EventType::metric(): + $items = MetricsItem::toEnvelopeItem($event); + break; } return sprintf("%s\n%s", JSON::encode($envelopeHeader), $items); diff --git a/src/State/Hub.php b/src/State/Hub.php index 9ac3ff0e4..f4432cedf 100644 --- a/src/State/Hub.php +++ b/src/State/Hub.php @@ -319,6 +319,84 @@ public function getTransaction(): ?Transaction return $this->getScope()->getTransaction(); } + /** + * @param int|float $value + * @param string[] $tags + */ + public function metricsIncr(string $name, $value, array $tags): ?EventId + { + $client = $this->getClient(); + + if ($client === null) { + return null; + } + + $event = Event::createMetric(); + $metric = [ + 'timestamp' => time(), + 'width' => 0, + 'name' => 'c:custom/' . $name . '@none', + 'type' => 'c', + 'value' => $value, + 'tags' => $tags, + ]; + $event->setMetric($metric); + + return $this->captureEvent($event); + } + + /** + * @param int|float $value + * @param string[] $tags + */ + public function metricsDistribution(string $name, $value, array $tags, ?string $unit = null): ?EventId + { + $client = $this->getClient(); + + if ($client === null) { + return null; + } + + $event = Event::createMetric(); + $metric = [ + 'timestamp' => time(), + 'width' => 0, + 'name' => 'd:custom/' . $name . '@' . ($unit ?? 'none'), + 'type' => 'd', + 'value' => $value, + 'tags' => $tags, + ]; + $event->setMetric($metric); + + return $this->captureEvent($event); + } + + /** + * @param int|float $value + * @param string[] $tags + */ + public function metricsSet(string $name, $value, array $tags): ?EventId + { + $client = $this->getClient(); + + if ($client === null) { + return null; + } + + $event = Event::createMetric(); + $metric = [ + 'timestamp' => time(), + 'width' => 0, + 'name' => 's:custom/' . $name . '@none', + 'type' => 's', + 'value' => $value, + 'tags' => $tags, + ]; + $event->setMetric($metric); + + return $this->captureEvent($event); + } + /** * {@inheritdoc} */ diff --git a/src/State/HubInterface.php b/src/State/HubInterface.php index 44d9e70e3..0c70a1d97 100644 --- a/src/State/HubInterface.php +++ b/src/State/HubInterface.php @@ -17,6 +17,15 @@ use Sentry\Tracing\Transaction; use Sentry\Tracing\TransactionContext; +/** + * This interface represent the class which is responsible for maintaining a + * stack of pairs of clients and scopes. It is the main entry point to talk + * with the Sentry client. + * + * @method EventId|null metricsIncr(string $name, $value, array $tags) + * @method EventId|null metricsDistribution(string $name, $value, array $tags, ?string $unit = null) + * @method EventId|null metricsSet(string $name, $value, array $tags) + */ interface HubInterface { /** diff --git a/src/functions.php b/src/functions.php index 9dba70ab1..662ec6868 100644 --- a/src/functions.php +++ b/src/functions.php @@ -268,3 +268,30 @@ function continueTrace(string $sentryTrace, string $baggage): TransactionContext return TransactionContext::fromHeaders($sentryTrace, $baggage); } + +/** + * @param int|float $value + * @param string[] $tags + */ +function metricsIncr(string $key, $value, array $tags): ?EventId +{ + return SentrySdk::getCurrentHub()->metricsIncr($key, $value, $tags); +} + +/** + * @param int|float $value + * @param string[] $tags + */ +function metricsDistribution(string $key, $value, array $tags, ?string $unit = null): ?EventId +{ + return SentrySdk::getCurrentHub()->metricsDistribution($key, $value, $tags, $unit); +} + +/** + * @param int|float $value + * @param string[] $tags + */ +function metricsSet(string $key, $value, array $tags): ?EventId +{ + return SentrySdk::getCurrentHub()->metricsSet($key, $value, $tags); +}