From 6b7e6ac7536fdee52ba43af42c7b1dd8f87a4947 Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Sat, 25 Oct 2025 11:26:07 -0500 Subject: [PATCH 01/17] feat: Add Trace Metrics --- src/Event.php | 17 ++--- src/EventType.php | 5 +- src/Metrics/Metrics.php | 75 +++++++++++++++------ src/Metrics/MetricsAggregator.php | 69 +++++++++++++++++++ src/Metrics/MetricsUnit.php | 3 - src/Metrics/Types/AbstractType.php | 75 +++++++++++++++++++++ src/Metrics/Types/CounterType.php | 52 ++++++++++++++ src/Metrics/Types/DistributionType.php | 52 ++++++++++++++ src/Metrics/Types/GaugeType.php | 52 ++++++++++++++ src/Serializer/EnvelopItems/MetricsItem.php | 52 ++++++++++++++ src/Serializer/PayloadSerializer.php | 10 ++- src/functions.php | 2 +- 12 files changed, 424 insertions(+), 40 deletions(-) create mode 100644 src/Metrics/MetricsAggregator.php create mode 100644 src/Metrics/Types/AbstractType.php create mode 100644 src/Metrics/Types/CounterType.php create mode 100644 src/Metrics/Types/DistributionType.php create mode 100644 src/Metrics/Types/GaugeType.php create mode 100644 src/Serializer/EnvelopItems/MetricsItem.php diff --git a/src/Event.php b/src/Event.php index 5244f945c..1412e0de0 100644 --- a/src/Event.php +++ b/src/Event.php @@ -71,6 +71,11 @@ final class Event */ private $logs = []; + /** + * @var array + */ + private $metrics = []; + /** * @var string|null The name of the server (e.g. the host name) */ @@ -241,9 +246,6 @@ public static function createLogs(?EventId $eventId = null): self return new self($eventId, EventType::logs()); } - /** - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. - */ public static function createMetrics(?EventId $eventId = null): self { return new self($eventId, EventType::metrics()); @@ -445,19 +447,18 @@ public function setLogs(array $logs): self return $this; } - /** - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. - */ public function getMetrics(): array { - return []; + return $this->metrics; } /** - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. + * @param array $metrics */ public function setMetrics(array $metrics): self { + $this->metrics = $metrics; + return $this; } diff --git a/src/EventType.php b/src/EventType.php index 3c2d13fb3..db7f49311 100644 --- a/src/EventType.php +++ b/src/EventType.php @@ -47,12 +47,9 @@ public static function logs(): self return self::getInstance('log'); } - /** - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. - */ public static function metrics(): self { - return self::getInstance('metrics'); + return self::getInstance('trace_metric'); } /** diff --git a/src/Metrics/Metrics.php b/src/Metrics/Metrics.php index 6f0fa6764..1555a4ab6 100644 --- a/src/Metrics/Metrics.php +++ b/src/Metrics/Metrics.php @@ -5,6 +5,9 @@ namespace Sentry\Metrics; use Sentry\EventId; +use Sentry\Metrics\Types\CounterType; +use Sentry\Metrics\Types\DistributionType; +use Sentry\Metrics\Types\GaugeType; use Sentry\Tracing\SpanContext; use function Sentry\trace; @@ -16,6 +19,16 @@ class Metrics */ private static $instance; + /** + * @var MetricsAggregator + */ + private $aggregator; + + private function __construct() + { + $this->aggregator = new MetricsAggregator(); + } + public static function getInstance(): self { if (self::$instance === null) { @@ -40,34 +53,55 @@ public function increment( ): void { } - /** - * @param array $tags - * - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. - */ + public function count( + string $name, + float $value, + ?MetricsUnit $unit = null, + array $attributes = [], + ?float $timestamp = null + ): void { + $this->aggregator->add( + CounterType::TYPE, + $name, + $value, + $unit, + $attributes, + $timestamp + ); + } + public function distribution( - string $key, + string $name, float $value, ?MetricsUnit $unit = null, - array $tags = [], - ?int $timestamp = null, - int $stackLevel = 0 + array $attributes = [], + ?float $timestamp = null ): void { + $this->aggregator->add( + DistributionType::TYPE, + $name, + $value, + $unit, + $attributes, + $timestamp + ); } - /** - * @param array $tags - * - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. - */ public function gauge( - string $key, + string $name, float $value, ?MetricsUnit $unit = null, - array $tags = [], - ?int $timestamp = null, - int $stackLevel = 0 + array $attributes = [], + ?float $timestamp = null ): void { + $this->aggregator->add( + GaugeType::TYPE, + $name, + $value, + $unit, + $attributes, + $timestamp + ); } /** @@ -113,11 +147,8 @@ function () use ($callback) { ); } - /** - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. - */ public function flush(): ?EventId { - return null; + return $this->aggregator->flush(); } } diff --git a/src/Metrics/MetricsAggregator.php b/src/Metrics/MetricsAggregator.php new file mode 100644 index 000000000..6a5cb8390 --- /dev/null +++ b/src/Metrics/MetricsAggregator.php @@ -0,0 +1,69 @@ + + */ + private $metrics = []; + + private const METRIC_TYPES = [ + CounterType::TYPE => CounterType::class, + DistributionType::TYPE => DistributionType::class, + GaugeType::TYPE => GaugeType::class, + ]; + + /** + * @param int|float|string $value + */ + public function add( + string $type, + string $name, + $value, + ?MetricsUnit $unit, + array $attributes, + ?float $timestamp + ): void { + if ($timestamp === null) { + $timestamp = microtime(true); + } + if ($unit === null) { + $unit = MetricsUnit::none(); + } + + $metricTypeClass = self::METRIC_TYPES[$type]; + /** @var AbstractType $metric */ + /** @phpstan-ignore-next-line SetType accepts int|float|string, others only int|float */ + $metric = new $metricTypeClass($name, $value, $unit, $attributes, $timestamp); + $this->metrics[] = $metric; + } + + public function flush(): ?EventId + { + if ($this->metrics === []) { + return null; + } + + $hub = SentrySdk::getCurrentHub(); + $event = Event::createMetrics()->setMetrics($this->metrics); + + $this->metrics = []; + + return $hub->captureEvent($event); + } +} diff --git a/src/Metrics/MetricsUnit.php b/src/Metrics/MetricsUnit.php index e94951fe3..3e39d56fe 100644 --- a/src/Metrics/MetricsUnit.php +++ b/src/Metrics/MetricsUnit.php @@ -4,9 +4,6 @@ namespace Sentry\Metrics; -/** - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. - */ final class MetricsUnit implements \Stringable { /** diff --git a/src/Metrics/Types/AbstractType.php b/src/Metrics/Types/AbstractType.php new file mode 100644 index 000000000..9c28ca041 --- /dev/null +++ b/src/Metrics/Types/AbstractType.php @@ -0,0 +1,75 @@ + $attributes + */ + public function __construct(string $name, MetricsUnit $unit, array $attributes, float $timestamp) + { + $this->name = $name; + $this->unit = $unit; + $this->timestamp = $timestamp; + $this->attributes = new AttributeBag(); + + foreach ($attributes as $attribute) { + $this->attributes->set($attribute['name'], $attribute['value']); + } + } + + abstract public function setValue($value): void; + + abstract public function getType(): string; + + abstract public function getValue(); + + public function getName(): string + { + return $this->name; + } + + public function getUnit(): MetricsUnit + { + return $this->unit; + } + + public function getAttributes(): AttributeBag + { + return $this->attributes; + } + + public function getTimestamp(): float + { + return $this->timestamp; + } +} diff --git a/src/Metrics/Types/CounterType.php b/src/Metrics/Types/CounterType.php new file mode 100644 index 000000000..c0f93faef --- /dev/null +++ b/src/Metrics/Types/CounterType.php @@ -0,0 +1,52 @@ + $attributes + */ + public function __construct(string $name, $value, MetricsUnit $unit, array $attributes, float $timestamp) + { + parent::__construct($name, $unit, $attributes, $timestamp); + + $this->value = (float) $value; + } + + /** + * @param int|float $value + */ + public function setValue($value): void + { + $this->value = $value; + } + + public function getValue() + { + return $this->value; + } + + public function getType(): string + { + return self::TYPE; + } +} diff --git a/src/Metrics/Types/DistributionType.php b/src/Metrics/Types/DistributionType.php new file mode 100644 index 000000000..b3bceb6ad --- /dev/null +++ b/src/Metrics/Types/DistributionType.php @@ -0,0 +1,52 @@ + $attributes + */ + public function __construct(string $name, $value, MetricsUnit $unit, array $attributes, float $timestamp) + { + parent::__construct($name, $unit, $attributes, $timestamp); + + $this->value = (float) $value; + } + + /** + * @param int|float $value + */ + public function setValue($value): void + { + $this->value = $value; + } + + public function getValue() + { + return $this->value; + } + + public function getType(): string + { + return self::TYPE; + } +} diff --git a/src/Metrics/Types/GaugeType.php b/src/Metrics/Types/GaugeType.php new file mode 100644 index 000000000..0cb2eed3f --- /dev/null +++ b/src/Metrics/Types/GaugeType.php @@ -0,0 +1,52 @@ + $attributes + */ + public function __construct(string $name, $value, MetricsUnit $unit, array $attributes, float $timestamp) + { + parent::__construct($name, $unit, $attributes, $timestamp); + + $this->value = (float) $value; + } + + /** + * @param int|float $value + */ + public function setValue($value): void + { + $this->value = $value; + } + + public function getValue() + { + return $this->value; + } + + public function getType(): string + { + return self::TYPE; + } +} diff --git a/src/Serializer/EnvelopItems/MetricsItem.php b/src/Serializer/EnvelopItems/MetricsItem.php new file mode 100644 index 000000000..d8279edbb --- /dev/null +++ b/src/Serializer/EnvelopItems/MetricsItem.php @@ -0,0 +1,52 @@ +getMetrics(); + + $header = [ + 'type' => (string) EventType::metrics(), + 'item_count' => \count($metrics), + 'content_type' => 'application/vnd.sentry.items.trace-metric+json', + ]; + + return \sprintf( + "%s\n%s", + JSON::encode($header), + JSON::encode([ + 'items' => array_map(static function (AbstractType $metric): array { + return [ + 'timestamp' => $metric->getTimestamp(), + 'trace_id' => (string) SentrySdk::getCurrentHub()->getSpan()->getTraceId(), + 'name' => $metric->getName(), + 'value' => $metric->getValue(), + // 'unit' => (string) $metric->getUnit(), + 'type' => $metric->getType(), + 'attributes' => array_map(static function (Attribute $attribute): array { + return [ + 'type' => $attribute->getType(), + 'value' => $attribute->getValue(), + ]; + }, $metric->getAttributes()->all()), + ]; + }, $metrics), + ]) + ); + } +} diff --git a/src/Serializer/PayloadSerializer.php b/src/Serializer/PayloadSerializer.php index 4878cc767..bb8e78fcd 100644 --- a/src/Serializer/PayloadSerializer.php +++ b/src/Serializer/PayloadSerializer.php @@ -10,6 +10,7 @@ use Sentry\Serializer\EnvelopItems\CheckInItem; use Sentry\Serializer\EnvelopItems\EventItem; use Sentry\Serializer\EnvelopItems\LogsItem; +use Sentry\Serializer\EnvelopItems\MetricsItem; use Sentry\Serializer\EnvelopItems\ProfileItem; use Sentry\Serializer\EnvelopItems\TransactionItem; use Sentry\Tracing\DynamicSamplingContext; @@ -40,7 +41,7 @@ public function serialize(Event $event): string { // @see https://develop.sentry.dev/sdk/envelopes/#envelope-headers $envelopeHeader = [ - 'event_id' => (string) $event->getId(), + // 'event_id' => (string) $event->getId(), 'sent_at' => gmdate('Y-m-d\TH:i:s\Z'), 'dsn' => (string) $this->options->getDsn(), 'sdk' => $event->getSdkPayload(), @@ -51,7 +52,7 @@ public function serialize(Event $event): string $entries = $dynamicSamplingContext->getEntries(); if (!empty($entries)) { - $envelopeHeader['trace'] = $entries; + // $envelopeHeader['trace'] = $entries; } } @@ -73,8 +74,13 @@ public function serialize(Event $event): string case EventType::logs(): $items[] = LogsItem::toEnvelopeItem($event); break; + case EventType::metrics(): + $items[] = MetricsItem::toEnvelopeItem($event); + break; } + // dd(\sprintf("%s\n%s", JSON::encode($envelopeHeader), implode("\n", array_filter($items)))); + return \sprintf("%s\n%s", JSON::encode($envelopeHeader), implode("\n", array_filter($items))); } } diff --git a/src/functions.php b/src/functions.php index 23f6eb1e1..8972f6595 100644 --- a/src/functions.php +++ b/src/functions.php @@ -373,7 +373,7 @@ function logger(): Logs } /** - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. + * Get the Sentry Metrics client. */ function metrics(): Metrics { From 98a45f8892602d64281473a3dcc1344db4233fe1 Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Sat, 25 Oct 2025 16:16:15 -0500 Subject: [PATCH 02/17] Add trace and span ID --- src/Metrics/MetricsAggregator.php | 39 ++++++++++++++++++++- src/Metrics/Types/AbstractType.php | 38 +++++++++++++++++--- src/Metrics/Types/CounterType.php | 15 ++++++-- src/Metrics/Types/DistributionType.php | 15 ++++++-- src/Metrics/Types/GaugeType.php | 15 ++++++-- src/Serializer/EnvelopItems/MetricsItem.php | 3 +- 6 files changed, 110 insertions(+), 15 deletions(-) diff --git a/src/Metrics/MetricsAggregator.php b/src/Metrics/MetricsAggregator.php index 6a5cb8390..7910a2802 100644 --- a/src/Metrics/MetricsAggregator.php +++ b/src/Metrics/MetricsAggregator.php @@ -11,6 +11,7 @@ use Sentry\Metrics\Types\DistributionType; use Sentry\Metrics\Types\GaugeType; use Sentry\SentrySdk; +use Sentry\State\Scope; /** * @internal @@ -46,10 +47,46 @@ public function add( $unit = MetricsUnit::none(); } + $hub = SentrySdk::getCurrentHub(); + $client = $hub->getClient(); + + if ($client !== null) { + $options = $client->getOptions(); + + $defaultAttributes = [ + 'sentry.sdk.name' => $client->getSdkIdentifier(), + 'sentry.sdk.version' => $client->getSdkVersion(), + 'sentry.environment' => $options->getEnvironment() ?? Event::DEFAULT_ENVIRONMENT, + ]; + + $release = $options->getRelease(); + if ($release !== null) { + $defaultAttributes['sentry.release'] = $release; + } + + $attributes = array_merge($defaultAttributes, $attributes); + } + + $spanId = null; + $traceId = null; + + $span = $hub->getSpan(); + if ($span !== null) { + $spanId = $span->getSpanId(); + $traceId = $span->getTraceId(); + } else { + $hub->configureScope(function (Scope $scope) use (&$traceId, &$spanId) { + $propagationContext = $scope->getPropagationContext(); + $traceId = $propagationContext->getTraceId(); + $spanId = $propagationContext->getSpanId(); + }); + } + $metricTypeClass = self::METRIC_TYPES[$type]; /** @var AbstractType $metric */ /** @phpstan-ignore-next-line SetType accepts int|float|string, others only int|float */ - $metric = new $metricTypeClass($name, $value, $unit, $attributes, $timestamp); + $metric = new $metricTypeClass($name, $value, $unit, $traceId, $spanId, $attributes, $timestamp); + $this->metrics[] = $metric; } diff --git a/src/Metrics/Types/AbstractType.php b/src/Metrics/Types/AbstractType.php index 9c28ca041..02fac752a 100644 --- a/src/Metrics/Types/AbstractType.php +++ b/src/Metrics/Types/AbstractType.php @@ -6,6 +6,8 @@ use Sentry\Attributes\AttributeBag; use Sentry\Metrics\MetricsUnit; +use Sentry\Tracing\SpanId; +use Sentry\Tracing\TraceId; /** * @internal @@ -22,6 +24,16 @@ abstract class AbstractType */ private $unit; + /** + * @var TraceId + */ + private $traceId; + + /** + * @var SpanId + */ + private $spanId; + /** * @var float */ @@ -35,15 +47,23 @@ abstract class AbstractType /** * @param array $attributes */ - public function __construct(string $name, MetricsUnit $unit, array $attributes, float $timestamp) - { + public function __construct( + string $name, + MetricsUnit $unit, + TraceId $traceId, + SpanId $spanId, + array $attributes, + float $timestamp + ) { $this->name = $name; $this->unit = $unit; + $this->traceId = $traceId; + $this->spanId = $spanId; $this->timestamp = $timestamp; $this->attributes = new AttributeBag(); - foreach ($attributes as $attribute) { - $this->attributes->set($attribute['name'], $attribute['value']); + foreach ($attributes as $key => $value) { + $this->attributes->set($key, $value); } } @@ -63,6 +83,16 @@ public function getUnit(): MetricsUnit return $this->unit; } + public function getTraceId(): TraceId + { + return $this->traceId; + } + + public function getSpanId(): SpanId + { + return $this->spanId; + } + public function getAttributes(): AttributeBag { return $this->attributes; diff --git a/src/Metrics/Types/CounterType.php b/src/Metrics/Types/CounterType.php index c0f93faef..7dc0586d7 100644 --- a/src/Metrics/Types/CounterType.php +++ b/src/Metrics/Types/CounterType.php @@ -5,6 +5,8 @@ namespace Sentry\Metrics\Types; use Sentry\Metrics\MetricsUnit; +use Sentry\Tracing\SpanId; +use Sentry\Tracing\TraceId; /** * @internal @@ -25,9 +27,16 @@ final class CounterType extends AbstractType * @param int|float $value * @param array $attributes */ - public function __construct(string $name, $value, MetricsUnit $unit, array $attributes, float $timestamp) - { - parent::__construct($name, $unit, $attributes, $timestamp); + public function __construct( + string $name, + $value, + MetricsUnit $unit, + TraceId $traceId, + SpanId $spanId, + array $attributes, + float $timestamp + ) { + parent::__construct($name, $unit, $traceId, $spanId, $attributes, $timestamp); $this->value = (float) $value; } diff --git a/src/Metrics/Types/DistributionType.php b/src/Metrics/Types/DistributionType.php index b3bceb6ad..a2fdd449b 100644 --- a/src/Metrics/Types/DistributionType.php +++ b/src/Metrics/Types/DistributionType.php @@ -5,6 +5,8 @@ namespace Sentry\Metrics\Types; use Sentry\Metrics\MetricsUnit; +use Sentry\Tracing\SpanId; +use Sentry\Tracing\TraceId; /** * @internal @@ -25,9 +27,16 @@ final class DistributionType extends AbstractType * @param int|float $value * @param array $attributes */ - public function __construct(string $name, $value, MetricsUnit $unit, array $attributes, float $timestamp) - { - parent::__construct($name, $unit, $attributes, $timestamp); + public function __construct( + string $name, + $value, + MetricsUnit $unit, + TraceId $traceId, + SpanId $spanId, + array $attributes, + float $timestamp + ) { + parent::__construct($name, $unit, $traceId, $spanId, $attributes, $timestamp); $this->value = (float) $value; } diff --git a/src/Metrics/Types/GaugeType.php b/src/Metrics/Types/GaugeType.php index 0cb2eed3f..e2de04f4a 100644 --- a/src/Metrics/Types/GaugeType.php +++ b/src/Metrics/Types/GaugeType.php @@ -5,6 +5,8 @@ namespace Sentry\Metrics\Types; use Sentry\Metrics\MetricsUnit; +use Sentry\Tracing\SpanId; +use Sentry\Tracing\TraceId; /** * @internal @@ -25,9 +27,16 @@ final class GaugeType extends AbstractType * @param int|float $value * @param array $attributes */ - public function __construct(string $name, $value, MetricsUnit $unit, array $attributes, float $timestamp) - { - parent::__construct($name, $unit, $attributes, $timestamp); + public function __construct( + string $name, + $value, + MetricsUnit $unit, + TraceId $traceId, + SpanId $spanId, + array $attributes, + float $timestamp + ) { + parent::__construct($name, $unit, $traceId, $spanId, $attributes, $timestamp); $this->value = (float) $value; } diff --git a/src/Serializer/EnvelopItems/MetricsItem.php b/src/Serializer/EnvelopItems/MetricsItem.php index d8279edbb..ec36cfcf7 100644 --- a/src/Serializer/EnvelopItems/MetricsItem.php +++ b/src/Serializer/EnvelopItems/MetricsItem.php @@ -33,7 +33,8 @@ public static function toEnvelopeItem(Event $event): string 'items' => array_map(static function (AbstractType $metric): array { return [ 'timestamp' => $metric->getTimestamp(), - 'trace_id' => (string) SentrySdk::getCurrentHub()->getSpan()->getTraceId(), + 'trace_id' => (string) $metric->getTraceId(), + 'span_id' => (string) $metric->getSpanId(), 'name' => $metric->getName(), 'value' => $metric->getValue(), // 'unit' => (string) $metric->getUnit(), From 8aec319f4438d5090ea49bf70cf15932890c4a9b Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Mon, 10 Nov 2025 20:26:47 +0100 Subject: [PATCH 03/17] wip --- src/Metrics/Metrics.php | 24 ++++++++------------- src/Metrics/MetricsAggregator.php | 12 ++--------- src/Metrics/Types/AbstractType.php | 14 ++++++------ src/Metrics/Types/CounterType.php | 6 +++--- src/Metrics/Types/DistributionType.php | 6 +++--- src/Metrics/Types/GaugeType.php | 6 +++--- src/Serializer/EnvelopItems/MetricsItem.php | 3 +-- 7 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/Metrics/Metrics.php b/src/Metrics/Metrics.php index 1555a4ab6..ec45c19b5 100644 --- a/src/Metrics/Metrics.php +++ b/src/Metrics/Metrics.php @@ -41,7 +41,7 @@ public static function getInstance(): self /** * @param array $tags * - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. + * @deprecated Use Metrics::count() instead. To be removed in 5.x. */ public function increment( string $key, @@ -56,51 +56,45 @@ public function increment( public function count( string $name, float $value, - ?MetricsUnit $unit = null, array $attributes = [], - ?float $timestamp = null + ?MetricsUnit $unit = null ): void { $this->aggregator->add( CounterType::TYPE, $name, $value, - $unit, $attributes, - $timestamp + $unit ); } public function distribution( string $name, float $value, - ?MetricsUnit $unit = null, array $attributes = [], - ?float $timestamp = null + ?MetricsUnit $unit = null ): void { $this->aggregator->add( DistributionType::TYPE, $name, $value, - $unit, $attributes, - $timestamp + $unit ); } public function gauge( string $name, float $value, - ?MetricsUnit $unit = null, array $attributes = [], - ?float $timestamp = null + ?MetricsUnit $unit = null ): void { $this->aggregator->add( GaugeType::TYPE, $name, $value, - $unit, $attributes, - $timestamp + $unit ); } @@ -108,7 +102,7 @@ public function gauge( * @param int|string $value * @param array $tags * - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. + * @deprecated To be removed in 5.x. */ public function set( string $key, @@ -128,7 +122,7 @@ public function set( * * @return T * - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. + * @deprecated To be removed in 5.x. */ public function timing( string $key, diff --git a/src/Metrics/MetricsAggregator.php b/src/Metrics/MetricsAggregator.php index 7910a2802..2146d4e7d 100644 --- a/src/Metrics/MetricsAggregator.php +++ b/src/Metrics/MetricsAggregator.php @@ -36,17 +36,9 @@ public function add( string $type, string $name, $value, - ?MetricsUnit $unit, array $attributes, - ?float $timestamp + ?MetricsUnit $unit ): void { - if ($timestamp === null) { - $timestamp = microtime(true); - } - if ($unit === null) { - $unit = MetricsUnit::none(); - } - $hub = SentrySdk::getCurrentHub(); $client = $hub->getClient(); @@ -85,7 +77,7 @@ public function add( $metricTypeClass = self::METRIC_TYPES[$type]; /** @var AbstractType $metric */ /** @phpstan-ignore-next-line SetType accepts int|float|string, others only int|float */ - $metric = new $metricTypeClass($name, $value, $unit, $traceId, $spanId, $attributes, $timestamp); + $metric = new $metricTypeClass($name, $value, $traceId, $spanId, $attributes, microtime(true), $unit); $this->metrics[] = $metric; } diff --git a/src/Metrics/Types/AbstractType.php b/src/Metrics/Types/AbstractType.php index 02fac752a..8585b14e9 100644 --- a/src/Metrics/Types/AbstractType.php +++ b/src/Metrics/Types/AbstractType.php @@ -19,11 +19,6 @@ abstract class AbstractType */ private $name; - /** - * @var MetricsUnit - */ - private $unit; - /** * @var TraceId */ @@ -44,16 +39,21 @@ abstract class AbstractType */ private $attributes; + /** + * @var MetricsUnit|null + */ + private $unit; + /** * @param array $attributes */ public function __construct( string $name, - MetricsUnit $unit, TraceId $traceId, SpanId $spanId, + float $timestamp, array $attributes, - float $timestamp + ?MetricsUnit $unit, ) { $this->name = $name; $this->unit = $unit; diff --git a/src/Metrics/Types/CounterType.php b/src/Metrics/Types/CounterType.php index 7dc0586d7..1a3bfbf00 100644 --- a/src/Metrics/Types/CounterType.php +++ b/src/Metrics/Types/CounterType.php @@ -30,13 +30,13 @@ final class CounterType extends AbstractType public function __construct( string $name, $value, - MetricsUnit $unit, TraceId $traceId, SpanId $spanId, array $attributes, - float $timestamp + float $timestamp, + ?MetricsUnit $unit, ) { - parent::__construct($name, $unit, $traceId, $spanId, $attributes, $timestamp); + parent::__construct($name, $traceId, $spanId, $timestamp, $attributes, $unit); $this->value = (float) $value; } diff --git a/src/Metrics/Types/DistributionType.php b/src/Metrics/Types/DistributionType.php index a2fdd449b..3002edca3 100644 --- a/src/Metrics/Types/DistributionType.php +++ b/src/Metrics/Types/DistributionType.php @@ -30,13 +30,13 @@ final class DistributionType extends AbstractType public function __construct( string $name, $value, - MetricsUnit $unit, TraceId $traceId, SpanId $spanId, array $attributes, - float $timestamp + float $timestamp, + ?MetricsUnit $unit, ) { - parent::__construct($name, $unit, $traceId, $spanId, $attributes, $timestamp); + parent::__construct($name, $traceId, $spanId, $timestamp, $attributes, $unit); $this->value = (float) $value; } diff --git a/src/Metrics/Types/GaugeType.php b/src/Metrics/Types/GaugeType.php index e2de04f4a..4fc749075 100644 --- a/src/Metrics/Types/GaugeType.php +++ b/src/Metrics/Types/GaugeType.php @@ -30,13 +30,13 @@ final class GaugeType extends AbstractType public function __construct( string $name, $value, - MetricsUnit $unit, TraceId $traceId, SpanId $spanId, array $attributes, - float $timestamp + float $timestamp, + ?MetricsUnit $unit, ) { - parent::__construct($name, $unit, $traceId, $spanId, $attributes, $timestamp); + parent::__construct($name, $traceId, $spanId, $timestamp, $attributes, $unit); $this->value = (float) $value; } diff --git a/src/Serializer/EnvelopItems/MetricsItem.php b/src/Serializer/EnvelopItems/MetricsItem.php index ec36cfcf7..978828011 100644 --- a/src/Serializer/EnvelopItems/MetricsItem.php +++ b/src/Serializer/EnvelopItems/MetricsItem.php @@ -8,7 +8,6 @@ use Sentry\Event; use Sentry\EventType; use Sentry\Metrics\Types\AbstractType; -use Sentry\SentrySdk; use Sentry\Util\JSON; /** @@ -37,7 +36,7 @@ public static function toEnvelopeItem(Event $event): string 'span_id' => (string) $metric->getSpanId(), 'name' => $metric->getName(), 'value' => $metric->getValue(), - // 'unit' => (string) $metric->getUnit(), + 'unit' => $metric->getUnit() ? (string) $metric->getUnit() : null, 'type' => $metric->getType(), 'attributes' => array_map(static function (Attribute $attribute): array { return [ From 7ec9ec703cf4c8778dd02b19a847a6ccdb8fd977 Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Tue, 18 Nov 2025 18:37:32 +0100 Subject: [PATCH 04/17] introduce ring buffer, add tests --- src/Event.php | 8 +- src/EventType.php | 10 + src/Metrics/Metrics.php | 9 + src/Metrics/MetricsAggregator.php | 31 ++- src/Metrics/MetricsUnit.php | 1 + src/Metrics/Types/AbstractType.php | 4 +- src/Metrics/Types/CounterType.php | 2 +- src/Metrics/Types/GaugeType.php | 2 +- src/Serializer/PayloadSerializer.php | 10 +- src/Util/RingBuffer.php | 215 +++++++++++++++++++++ tests/Metrics/MetricsTest.php | 175 +++++++++-------- tests/Serializer/PayloadSerializerTest.php | 46 +++++ tests/Util/RingBufferTest.php | 146 ++++++++++++++ 13 files changed, 561 insertions(+), 98 deletions(-) create mode 100644 src/Util/RingBuffer.php create mode 100644 tests/Util/RingBufferTest.php diff --git a/src/Event.php b/src/Event.php index 1412e0de0..c8ebc1b14 100644 --- a/src/Event.php +++ b/src/Event.php @@ -7,6 +7,7 @@ use Sentry\Context\OsContext; use Sentry\Context\RuntimeContext; use Sentry\Logs\Log; +use Sentry\Metrics\Types\AbstractType; use Sentry\Profiling\Profile; use Sentry\Tracing\Span; @@ -72,7 +73,7 @@ final class Event private $logs = []; /** - * @var array + * @var array */ private $metrics = []; @@ -447,13 +448,16 @@ public function setLogs(array $logs): self return $this; } + /** + * @return AbstractType[] + */ public function getMetrics(): array { return $this->metrics; } /** - * @param array $metrics + * @param AbstractType[] $metrics */ public function setMetrics(array $metrics): self { diff --git a/src/EventType.php b/src/EventType.php index db7f49311..ccdcd1418 100644 --- a/src/EventType.php +++ b/src/EventType.php @@ -68,6 +68,16 @@ public static function cases(): array ]; } + public function requiresEventId(): bool + { + switch ($this) { + case self::metrics(): + return false; + default: + return true; + } + } + public function __toString(): string { return $this->value; diff --git a/src/Metrics/Metrics.php b/src/Metrics/Metrics.php index ec45c19b5..858033cf9 100644 --- a/src/Metrics/Metrics.php +++ b/src/Metrics/Metrics.php @@ -53,6 +53,9 @@ public function increment( ): void { } + /** + * @param array $attributes + */ public function count( string $name, float $value, @@ -68,6 +71,9 @@ public function count( ); } + /** + * @param array $attributes + */ public function distribution( string $name, float $value, @@ -83,6 +89,9 @@ public function distribution( ); } + /** + * @param array $attributes + */ public function gauge( string $name, float $value, diff --git a/src/Metrics/MetricsAggregator.php b/src/Metrics/MetricsAggregator.php index 2146d4e7d..5eb65fd34 100644 --- a/src/Metrics/MetricsAggregator.php +++ b/src/Metrics/MetricsAggregator.php @@ -4,6 +4,7 @@ namespace Sentry\Metrics; +use Sentry\Client; use Sentry\Event; use Sentry\EventId; use Sentry\Metrics\Types\AbstractType; @@ -12,6 +13,7 @@ use Sentry\Metrics\Types\GaugeType; use Sentry\SentrySdk; use Sentry\State\Scope; +use Sentry\Util\RingBuffer; /** * @internal @@ -19,9 +21,19 @@ final class MetricsAggregator { /** - * @var array + * @var int */ - private $metrics = []; + public const METRICS_BUFFER_SIZE = 1000; + + /** + * @var RingBuffer + */ + private $metrics; + + public function __construct() + { + $this->metrics = new RingBuffer(self::METRICS_BUFFER_SIZE); + } private const METRIC_TYPES = [ CounterType::TYPE => CounterType::class, @@ -30,7 +42,8 @@ final class MetricsAggregator ]; /** - * @param int|float|string $value + * @param int|float|string $value + * @param array $attributes */ public function add( string $type, @@ -42,7 +55,7 @@ public function add( $hub = SentrySdk::getCurrentHub(); $client = $hub->getClient(); - if ($client !== null) { + if ($client instanceof Client) { $options = $client->getOptions(); $defaultAttributes = [ @@ -56,7 +69,7 @@ public function add( $defaultAttributes['sentry.release'] = $release; } - $attributes = array_merge($defaultAttributes, $attributes); + $attributes += $defaultAttributes; } $spanId = null; @@ -79,19 +92,17 @@ public function add( /** @phpstan-ignore-next-line SetType accepts int|float|string, others only int|float */ $metric = new $metricTypeClass($name, $value, $traceId, $spanId, $attributes, microtime(true), $unit); - $this->metrics[] = $metric; + $this->metrics->push($metric); } public function flush(): ?EventId { - if ($this->metrics === []) { + if ($this->metrics->isEmpty()) { return null; } $hub = SentrySdk::getCurrentHub(); - $event = Event::createMetrics()->setMetrics($this->metrics); - - $this->metrics = []; + $event = Event::createMetrics()->setMetrics($this->metrics->drain()); return $hub->captureEvent($event); } diff --git a/src/Metrics/MetricsUnit.php b/src/Metrics/MetricsUnit.php index 3e39d56fe..e04c68ff9 100644 --- a/src/Metrics/MetricsUnit.php +++ b/src/Metrics/MetricsUnit.php @@ -141,6 +141,7 @@ public static function percent(): self return self::getInstance('percent'); } + // none and custom is removed public static function none(): self { return self::getInstance('none'); diff --git a/src/Metrics/Types/AbstractType.php b/src/Metrics/Types/AbstractType.php index 8585b14e9..04741fec5 100644 --- a/src/Metrics/Types/AbstractType.php +++ b/src/Metrics/Types/AbstractType.php @@ -53,7 +53,7 @@ public function __construct( SpanId $spanId, float $timestamp, array $attributes, - ?MetricsUnit $unit, + ?MetricsUnit $unit ) { $this->name = $name; $this->unit = $unit; @@ -78,7 +78,7 @@ public function getName(): string return $this->name; } - public function getUnit(): MetricsUnit + public function getUnit(): ?MetricsUnit { return $this->unit; } diff --git a/src/Metrics/Types/CounterType.php b/src/Metrics/Types/CounterType.php index 1a3bfbf00..b34e6629b 100644 --- a/src/Metrics/Types/CounterType.php +++ b/src/Metrics/Types/CounterType.php @@ -34,7 +34,7 @@ public function __construct( SpanId $spanId, array $attributes, float $timestamp, - ?MetricsUnit $unit, + ?MetricsUnit $unit ) { parent::__construct($name, $traceId, $spanId, $timestamp, $attributes, $unit); diff --git a/src/Metrics/Types/GaugeType.php b/src/Metrics/Types/GaugeType.php index 4fc749075..ff8f4bd1a 100644 --- a/src/Metrics/Types/GaugeType.php +++ b/src/Metrics/Types/GaugeType.php @@ -34,7 +34,7 @@ public function __construct( SpanId $spanId, array $attributes, float $timestamp, - ?MetricsUnit $unit, + ?MetricsUnit $unit ) { parent::__construct($name, $traceId, $spanId, $timestamp, $attributes, $unit); diff --git a/src/Serializer/PayloadSerializer.php b/src/Serializer/PayloadSerializer.php index bb8e78fcd..c9f5c1c19 100644 --- a/src/Serializer/PayloadSerializer.php +++ b/src/Serializer/PayloadSerializer.php @@ -41,21 +41,25 @@ public function serialize(Event $event): string { // @see https://develop.sentry.dev/sdk/envelopes/#envelope-headers $envelopeHeader = [ - // 'event_id' => (string) $event->getId(), 'sent_at' => gmdate('Y-m-d\TH:i:s\Z'), 'dsn' => (string) $this->options->getDsn(), 'sdk' => $event->getSdkPayload(), ]; + if ($event->getType()->requiresEventId()) { + $envelopeHeader = ['event_id' => (string) $event->getId()] + $envelopeHeader; + } + $dynamicSamplingContext = $event->getSdkMetadata('dynamic_sampling_context'); if ($dynamicSamplingContext instanceof DynamicSamplingContext) { $entries = $dynamicSamplingContext->getEntries(); if (!empty($entries)) { - // $envelopeHeader['trace'] = $entries; + $envelopeHeader['trace'] = $entries; } } + $items = []; switch ($event->getType()) { @@ -79,8 +83,6 @@ public function serialize(Event $event): string break; } - // dd(\sprintf("%s\n%s", JSON::encode($envelopeHeader), implode("\n", array_filter($items)))); - return \sprintf("%s\n%s", JSON::encode($envelopeHeader), implode("\n", array_filter($items))); } } diff --git a/src/Util/RingBuffer.php b/src/Util/RingBuffer.php new file mode 100644 index 000000000..7852f53db --- /dev/null +++ b/src/Util/RingBuffer.php @@ -0,0 +1,215 @@ + + */ + private $buffer; + + /** + * @var int + */ + private $capacity; + + /** + * Points at the first element in the buffer. + * + * @var int + */ + private $head = 0; + + /** + * Points at the index where the next insertion will happen. + * If the buffer is not full, this will point to an empty array index. + * When full, it will point to the position where the oldest element is. + * + * @var int + */ + private $tail = 0; + + /** + * @var int + */ + private $count = 0; + + /** + * Creates a new buffer with a fixed capacity. + */ + public function __construct(int $capacity) + { + if ($capacity <= 0) { + throw new \RuntimeException('RingBuffer capacity must be greater than 0'); + } + $this->capacity = $capacity; + $this->buffer = new \SplFixedArray($capacity); + } + + /** + * Returns how many elements can be stored in the buffer before it starts overwriting + * old elements. + */ + public function capacity(): int + { + return $this->capacity; + } + + /** + * The current number of stored elements. + */ + public function count(): int + { + return $this->count; + } + + /** + * Whether the buffer contains any element or not. + */ + public function isEmpty(): bool + { + return $this->count === 0; + } + + /** + * Whether the buffer is at capacity and will start to overwrite old elements on push. + */ + public function isFull(): bool + { + return $this->count === $this->capacity; + } + + /** + * Adds a new element to the back of the buffer. If the buffer is at capacity, it will + * overwrite the oldest element. + * + * Insertion order is still maintained. + * + * @param T $value + */ + public function push($value): void + { + $this->buffer[$this->tail] = $value; + + $this->tail = ($this->tail + 1) % $this->capacity; + + if ($this->isFull()) { + $this->head = ($this->head + 1) % $this->capacity; + } else { + ++$this->count; + } + } + + /** + * Returns and removes the first element in the buffer. + * If the buffer is empty, it will return null instead. + * + * @return T|null + */ + public function shift() + { + if ($this->isEmpty()) { + return null; + } + $value = $this->buffer[$this->head]; + + $this->buffer[$this->head] = null; + + $this->head = ($this->head + 1) % $this->capacity; + --$this->count; + + return $value; + } + + /** + * Returns the last element in the buffer without removing it. + * If the buffer is empty, it will return null instead. + * + * @return T|null + */ + public function peekBack() + { + if ($this->isEmpty()) { + return null; + } + $idx = ($this->tail - 1 + $this->capacity) % $this->capacity; + + return $this->buffer[$idx]; + } + + /** + * Returns the first element in the buffer without removing it. + * If the buffer is empty, it will return null instead. + * + * @return T|null + */ + public function peekFront() + { + if ($this->isEmpty()) { + return null; + } + + return $this->buffer[$this->head]; + } + + /** + * Resets the count and removes all elements from the buffer. + */ + public function clear(): void + { + for ($i = 0; $i < $this->count; ++$i) { + $this->buffer[($this->head + $i) % $this->capacity] = null; + } + $this->count = 0; + $this->head = 0; + $this->tail = 0; + } + + /** + * Returns the content of the buffer as array. The resulting array will have the size of `count` + * and not `capacity`. + * + * @return array + */ + public function toArray(): array + { + $result = []; + for ($i = 0; $i < $this->count; ++$i) { + $value = $this->buffer[($this->head + $i) % $this->capacity]; + /** @var T $value */ + $result[] = $value; + } + + return $result; + } + + /** + * Returns the content of the buffer and clears all elements that it contains in the process. + * + * @return array + */ + public function drain(): array + { + $result = $this->toArray(); + $this->clear(); + + return $result; + } +} diff --git a/tests/Metrics/MetricsTest.php b/tests/Metrics/MetricsTest.php index 1e33a53d5..5ccf174b6 100644 --- a/tests/Metrics/MetricsTest.php +++ b/tests/Metrics/MetricsTest.php @@ -5,14 +5,23 @@ namespace Sentry\Tests; use PHPUnit\Framework\TestCase; +use Sentry\Client; use Sentry\ClientInterface; use Sentry\Event; +use Sentry\Metrics\MetricsAggregator; use Sentry\Metrics\MetricsUnit; +use Sentry\Metrics\Types\CounterType; +use Sentry\Metrics\Types\DistributionType; +use Sentry\Metrics\Types\GaugeType; use Sentry\Options; use Sentry\SentrySdk; use Sentry\State\Hub; +use Sentry\State\HubAdapter; use Sentry\Tracing\SpanContext; use Sentry\Tracing\TransactionContext; +use Sentry\Transport\Result; +use Sentry\Transport\ResultStatus; +use Sentry\Transport\TransportInterface; use Sentry\Util\ClockMock; use function Sentry\metrics; @@ -58,45 +67,6 @@ public function testIncrement(): void metrics()->flush(); } - public function testDistribution(): void - { - ClockMock::withClockMock(1699412953); - - /** @var ClientInterface&MockObject $client */ - $client = $this->createMock(ClientInterface::class); - $client->expects($this->any()) - ->method('getOptions') - ->willReturn(new Options([ - 'release' => '1.0.0', - 'environment' => 'development', - 'attach_metric_code_locations' => true, - ])); - - $self = $this; - - $client->expects($this->never()) - ->method('captureEvent'); - - $hub = new Hub($client); - SentrySdk::setCurrentHub($hub); - - metrics()->distribution( - 'foo', - 1, - MetricsUnit::second(), - ['foo' => 'bar'] - ); - - metrics()->distribution( - 'foo', - 2, - MetricsUnit::second(), - ['foo' => 'bar'] - ); - - metrics()->flush(); - } - public function testTiming(): void { ClockMock::withClockMock(1699412953); @@ -148,45 +118,6 @@ static function () { metrics()->flush(); } - public function testGauge(): void - { - ClockMock::withClockMock(1699412953); - - /** @var ClientInterface&MockObject $client */ - $client = $this->createMock(ClientInterface::class); - $client->expects($this->any()) - ->method('getOptions') - ->willReturn(new Options([ - 'release' => '1.0.0', - 'environment' => 'development', - 'attach_metric_code_locations' => true, - ])); - - $self = $this; - - $client->expects($this->never()) - ->method('captureEvent'); - - $hub = new Hub($client); - SentrySdk::setCurrentHub($hub); - - metrics()->gauge( - 'foo', - 1, - MetricsUnit::second(), - ['foo' => 'bar'] - ); - - metrics()->gauge( - 'foo', - 2, - MetricsUnit::second(), - ['foo' => 'bar'] - ); - - metrics()->flush(); - } - public function testSet(): void { ClockMock::withClockMock(1699412953); @@ -303,4 +234,92 @@ public function testMetricsSummary(): void $span->finish(); $transaction->finish(); } + + // ======= Metrics V2 ========= + + protected function setUp(): void + { + HubAdapter::getInstance()->bindClient(new Client(new Options(), new StubTransport())); + StubTransport::$events = []; + } + + public function testCounterMetrics(): void + { + metrics()->count('test-count', 2, ['foo' => 'bar']); + metrics()->count('test-count', 2, ['foo' => 'bar']); + metrics()->flush(); + + $this->assertCount(1, StubTransport::$events); + $event = StubTransport::$events[0]; + $this->assertCount(2, $event->getMetrics()); + $metrics = $event->getMetrics(); + $metric = $metrics[0]; + $this->assertEquals('test-count', $metric->getName()); + $this->assertEquals(CounterType::TYPE, $metric->getType()); + $this->assertEquals(2, $metric->getValue()); + $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); + } + + public function testGaugeMetrics(): void + { + metrics()->gauge('test-gauge', 10, ['foo' => 'bar']); + metrics()->flush(); + + $this->assertCount(1, StubTransport::$events); + $event = StubTransport::$events[0]; + $this->assertCount(1, $event->getMetrics()); + $metrics = $event->getMetrics(); + $metric = $metrics[0]; + $this->assertEquals('test-gauge', $metric->getName()); + $this->assertEquals(GaugeType::TYPE, $metric->getType()); + $this->assertEquals(10, $metric->getValue()); + $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); + } + + public function testDistributionMetrics(): void + { + metrics()->distribution('test-distribution', 10, ['foo' => 'bar']); + metrics()->flush(); + $this->assertCount(1, StubTransport::$events); + $event = StubTransport::$events[0]; + $this->assertCount(1, $event->getMetrics()); + $metrics = $event->getMetrics(); + $metric = $metrics[0]; + $this->assertEquals('test-distribution', $metric->getName()); + $this->assertEquals(DistributionType::TYPE, $metric->getType()); + $this->assertEquals(10, $metric->getValue()); + $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); + } + + public function testMetricsBufferFull(): void + { + for ($i = 0; $i < MetricsAggregator::METRICS_BUFFER_SIZE + 100; ++$i) { + metrics()->count('test', 1, ['foo' => 'bar']); + } + metrics()->flush(); + $this->assertCount(1, StubTransport::$events); + $event = StubTransport::$events[0]; + $metrics = $event->getMetrics(); + $this->assertCount(MetricsAggregator::METRICS_BUFFER_SIZE, $metrics); + } +} + +class StubTransport implements TransportInterface +{ + /** + * @var Event[] + */ + public static $events = []; + + public function send(Event $event): Result + { + self::$events[] = $event; + + return new Result(ResultStatus::success()); + } + + public function close(?int $timeout = null): Result + { + return new Result(ResultStatus::success()); + } } diff --git a/tests/Serializer/PayloadSerializerTest.php b/tests/Serializer/PayloadSerializerTest.php index 1855bf487..82c74a351 100644 --- a/tests/Serializer/PayloadSerializerTest.php +++ b/tests/Serializer/PayloadSerializerTest.php @@ -18,6 +18,10 @@ use Sentry\Frame; use Sentry\Logs\Log; use Sentry\Logs\LogLevel; +use Sentry\Metrics\MetricsUnit; +use Sentry\Metrics\Types\CounterType; +use Sentry\Metrics\Types\DistributionType; +use Sentry\Metrics\Types\GaugeType; use Sentry\MonitorConfig; use Sentry\MonitorSchedule; use Sentry\Options; @@ -426,5 +430,47 @@ public static function serializeAsEnvelopeDataProvider(): iterable TEXT , ]; + + $event = Event::createMetrics(new EventId('fc9442f5aef34234bb22b9a615e30ccd')); + $event->setMetrics([ + new CounterType('test-counter', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], 1597790835.0, MetricsUnit::bit()), + ]); + + yield [ + $event, + <<setMetrics([ + new GaugeType('test-gauge', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], ClockMock::microtime(true), MetricsUnit::second()), + ]); + + yield [ + $event, + <<setMetrics([ + new DistributionType('test-distribution', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], ClockMock::microtime(true), MetricsUnit::day()), + ]); + + yield [ + $event, + <<push('foo'); + $buffer->push('bar'); + + $result = $buffer->toArray(); + $this->assertSame(2, $buffer->count()); + $this->assertEquals(['foo', 'bar'], $result); + } + + public function testPeekBack(): void + { + $buffer = new RingBuffer(5); + $buffer->push('foo'); + $buffer->push('bar'); + + $this->assertSame(2, $buffer->count()); + $this->assertSame('bar', $buffer->peekBack()); + } + + public function testPeekBackEmpty(): void + { + $buffer = new RingBuffer(5); + + $this->assertEmpty($buffer); + $this->assertNull($buffer->peekBack()); + } + + public function testPeekFront(): void + { + $buffer = new RingBuffer(5); + $buffer->push('foo'); + $buffer->push('bar'); + + $this->assertSame(2, $buffer->count()); + $this->assertSame('foo', $buffer->peekFront()); + } + + public function testPeekFrontEmpty(): void + { + $buffer = new RingBuffer(5); + + $this->assertEmpty($buffer); + $this->assertNull($buffer->peekFront()); + } + + public function testFixedCapacity(): void + { + $buffer = new RingBuffer(2); + $buffer->push('foo'); + $buffer->push('bar'); + $buffer->push('baz'); + + $this->assertSame(2, $buffer->count()); + $this->assertEquals(['bar', 'baz'], $buffer->toArray()); + } + + public function testClear(): void + { + $buffer = new RingBuffer(5); + $buffer->push('foo'); + $buffer->push('bar'); + + $this->assertSame(2, $buffer->count()); + $buffer->clear(); + $this->assertTrue($buffer->isEmpty()); + } + + public function testDrain(): void + { + $buffer = new RingBuffer(5); + $buffer->push('foo'); + $buffer->push('bar'); + + $this->assertSame(2, $buffer->count()); + $result = $buffer->drain(); + $this->assertTrue($buffer->isEmpty()); + $this->assertEquals(['foo', 'bar'], $result); + } + + public function testShift(): void + { + $buffer = new RingBuffer(5); + $buffer->push('foo'); + $buffer->push('bar'); + + $this->assertEquals('foo', $buffer->shift()); + $this->assertCount(1, $buffer); + } + + public function testShiftAndPush(): void + { + $buffer = new RingBuffer(5); + $buffer->push('foo'); + $buffer->push('bar'); + + $buffer->shift(); + + $buffer->push('baz'); + + $this->assertCount(2, $buffer); + $this->assertEquals(['bar', 'baz'], $buffer->toArray()); + } + + public function testCapacityOne(): void + { + $buffer = new RingBuffer(1); + $buffer->push('foo'); + $buffer->push('bar'); + + $this->assertCount(1, $buffer); + $this->assertSame('bar', $buffer->shift()); + } + + public function testInvalidCapacity(): void + { + $this->expectException(\RuntimeException::class); + $buffer = new RingBuffer(-1); + } + + public function testIsEmpty(): void + { + $buffer = new RingBuffer(5); + $this->assertTrue($buffer->isEmpty()); + } + + public function testIsFull(): void + { + $buffer = new RingBuffer(2); + $buffer->push('foo'); + $buffer->push('bar'); + $this->assertTrue($buffer->isFull()); + } +} From 35babbbdf1b65d9f600413b47ddc44cc33dfbd72 Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Wed, 19 Nov 2025 11:06:18 +0100 Subject: [PATCH 05/17] cs --- src/Serializer/PayloadSerializer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Serializer/PayloadSerializer.php b/src/Serializer/PayloadSerializer.php index c9f5c1c19..3a2cfc926 100644 --- a/src/Serializer/PayloadSerializer.php +++ b/src/Serializer/PayloadSerializer.php @@ -59,7 +59,6 @@ public function serialize(Event $event): string } } - $items = []; switch ($event->getType()) { From 1aa4f55bed7e82a1d83e1d5640f4ff50d187b4b9 Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Wed, 19 Nov 2025 11:09:06 +0100 Subject: [PATCH 06/17] rename MetricsUnit -> Unit --- src/Event.php | 2 +- src/Metrics/Metrics.php | 26 +++++++++++----------- src/Metrics/MetricsAggregator.php | 2 +- src/Metrics/Types/AbstractType.php | 8 +++---- src/Metrics/Types/CounterType.php | 4 ++-- src/Metrics/Types/DistributionType.php | 14 ++++++------ src/Metrics/Types/GaugeType.php | 4 ++-- src/Metrics/{MetricsUnit.php => Unit.php} | 2 +- src/Tracing/Span.php | 8 +++---- tests/Metrics/MetricsTest.php | 18 +++++++-------- tests/Serializer/PayloadSerializerTest.php | 8 +++---- 11 files changed, 48 insertions(+), 48 deletions(-) rename src/Metrics/{MetricsUnit.php => Unit.php} (98%) diff --git a/src/Event.php b/src/Event.php index c8ebc1b14..4b1c039b4 100644 --- a/src/Event.php +++ b/src/Event.php @@ -73,7 +73,7 @@ final class Event private $logs = []; /** - * @var array + * @var AbstractType[] */ private $metrics = []; diff --git a/src/Metrics/Metrics.php b/src/Metrics/Metrics.php index 858033cf9..e39f6e8fe 100644 --- a/src/Metrics/Metrics.php +++ b/src/Metrics/Metrics.php @@ -45,11 +45,11 @@ public static function getInstance(): self */ public function increment( string $key, - float $value, - ?MetricsUnit $unit = null, - array $tags = [], - ?int $timestamp = null, - int $stackLevel = 0 + float $value, + ?Unit $unit = null, + array $tags = [], + ?int $timestamp = null, + int $stackLevel = 0 ): void { } @@ -60,7 +60,7 @@ public function count( string $name, float $value, array $attributes = [], - ?MetricsUnit $unit = null + ?Unit $unit = null ): void { $this->aggregator->add( CounterType::TYPE, @@ -78,7 +78,7 @@ public function distribution( string $name, float $value, array $attributes = [], - ?MetricsUnit $unit = null + ?Unit $unit = null ): void { $this->aggregator->add( DistributionType::TYPE, @@ -96,7 +96,7 @@ public function gauge( string $name, float $value, array $attributes = [], - ?MetricsUnit $unit = null + ?Unit $unit = null ): void { $this->aggregator->add( GaugeType::TYPE, @@ -115,11 +115,11 @@ public function gauge( */ public function set( string $key, - $value, - ?MetricsUnit $unit = null, - array $tags = [], - ?int $timestamp = null, - int $stackLevel = 0 + $value, + ?Unit $unit = null, + array $tags = [], + ?int $timestamp = null, + int $stackLevel = 0 ): void { } diff --git a/src/Metrics/MetricsAggregator.php b/src/Metrics/MetricsAggregator.php index 5eb65fd34..f32b222e2 100644 --- a/src/Metrics/MetricsAggregator.php +++ b/src/Metrics/MetricsAggregator.php @@ -50,7 +50,7 @@ public function add( string $name, $value, array $attributes, - ?MetricsUnit $unit + ?Unit $unit ): void { $hub = SentrySdk::getCurrentHub(); $client = $hub->getClient(); diff --git a/src/Metrics/Types/AbstractType.php b/src/Metrics/Types/AbstractType.php index 04741fec5..9fc6bae19 100644 --- a/src/Metrics/Types/AbstractType.php +++ b/src/Metrics/Types/AbstractType.php @@ -5,7 +5,7 @@ namespace Sentry\Metrics\Types; use Sentry\Attributes\AttributeBag; -use Sentry\Metrics\MetricsUnit; +use Sentry\Metrics\Unit; use Sentry\Tracing\SpanId; use Sentry\Tracing\TraceId; @@ -40,7 +40,7 @@ abstract class AbstractType private $attributes; /** - * @var MetricsUnit|null + * @var Unit|null */ private $unit; @@ -53,7 +53,7 @@ public function __construct( SpanId $spanId, float $timestamp, array $attributes, - ?MetricsUnit $unit + ?Unit $unit ) { $this->name = $name; $this->unit = $unit; @@ -78,7 +78,7 @@ public function getName(): string return $this->name; } - public function getUnit(): ?MetricsUnit + public function getUnit(): ?Unit { return $this->unit; } diff --git a/src/Metrics/Types/CounterType.php b/src/Metrics/Types/CounterType.php index b34e6629b..3f3cc4a5c 100644 --- a/src/Metrics/Types/CounterType.php +++ b/src/Metrics/Types/CounterType.php @@ -4,7 +4,7 @@ namespace Sentry\Metrics\Types; -use Sentry\Metrics\MetricsUnit; +use Sentry\Metrics\Unit; use Sentry\Tracing\SpanId; use Sentry\Tracing\TraceId; @@ -34,7 +34,7 @@ public function __construct( SpanId $spanId, array $attributes, float $timestamp, - ?MetricsUnit $unit + ?Unit $unit ) { parent::__construct($name, $traceId, $spanId, $timestamp, $attributes, $unit); diff --git a/src/Metrics/Types/DistributionType.php b/src/Metrics/Types/DistributionType.php index 3002edca3..8ebe203e5 100644 --- a/src/Metrics/Types/DistributionType.php +++ b/src/Metrics/Types/DistributionType.php @@ -4,7 +4,7 @@ namespace Sentry\Metrics\Types; -use Sentry\Metrics\MetricsUnit; +use Sentry\Metrics\Unit; use Sentry\Tracing\SpanId; use Sentry\Tracing\TraceId; @@ -28,13 +28,13 @@ final class DistributionType extends AbstractType * @param array $attributes */ public function __construct( - string $name, - $value, + string $name, + $value, TraceId $traceId, - SpanId $spanId, - array $attributes, - float $timestamp, - ?MetricsUnit $unit, + SpanId $spanId, + array $attributes, + float $timestamp, + ?Unit $unit, ) { parent::__construct($name, $traceId, $spanId, $timestamp, $attributes, $unit); diff --git a/src/Metrics/Types/GaugeType.php b/src/Metrics/Types/GaugeType.php index ff8f4bd1a..2249f7579 100644 --- a/src/Metrics/Types/GaugeType.php +++ b/src/Metrics/Types/GaugeType.php @@ -4,7 +4,7 @@ namespace Sentry\Metrics\Types; -use Sentry\Metrics\MetricsUnit; +use Sentry\Metrics\Unit; use Sentry\Tracing\SpanId; use Sentry\Tracing\TraceId; @@ -34,7 +34,7 @@ public function __construct( SpanId $spanId, array $attributes, float $timestamp, - ?MetricsUnit $unit + ?Unit $unit ) { parent::__construct($name, $traceId, $spanId, $timestamp, $attributes, $unit); diff --git a/src/Metrics/MetricsUnit.php b/src/Metrics/Unit.php similarity index 98% rename from src/Metrics/MetricsUnit.php rename to src/Metrics/Unit.php index e04c68ff9..50637656c 100644 --- a/src/Metrics/MetricsUnit.php +++ b/src/Metrics/Unit.php @@ -4,7 +4,7 @@ namespace Sentry\Metrics; -final class MetricsUnit implements \Stringable +final class Unit implements \Stringable { /** * @var string The value of the enum instance diff --git a/src/Tracing/Span.php b/src/Tracing/Span.php index e55c4c948..8d1942fe1 100644 --- a/src/Tracing/Span.php +++ b/src/Tracing/Span.php @@ -5,7 +5,7 @@ namespace Sentry\Tracing; use Sentry\EventId; -use Sentry\Metrics\MetricsUnit; +use Sentry\Metrics\Unit; use Sentry\SentrySdk; use Sentry\State\Scope; @@ -547,9 +547,9 @@ public function getMetricsSummary(): array public function setMetricsSummary( string $type, string $key, - $value, - MetricsUnit $unit, - array $tags + $value, + Unit $unit, + array $tags ): void { } diff --git a/tests/Metrics/MetricsTest.php b/tests/Metrics/MetricsTest.php index 5ccf174b6..1e1399a40 100644 --- a/tests/Metrics/MetricsTest.php +++ b/tests/Metrics/MetricsTest.php @@ -9,7 +9,7 @@ use Sentry\ClientInterface; use Sentry\Event; use Sentry\Metrics\MetricsAggregator; -use Sentry\Metrics\MetricsUnit; +use Sentry\Metrics\Unit; use Sentry\Metrics\Types\CounterType; use Sentry\Metrics\Types\DistributionType; use Sentry\Metrics\Types\GaugeType; @@ -53,14 +53,14 @@ public function testIncrement(): void metrics()->increment( 'foo', 1, - MetricsUnit::second(), + Unit::second(), ['foo' => 'bar'] ); metrics()->increment( 'foo', 2, - MetricsUnit::second(), + Unit::second(), ['foo' => 'bar'] ); @@ -143,21 +143,21 @@ public function testSet(): void metrics()->set( 'foo', 1, - MetricsUnit::second(), + Unit::second(), ['foo' => 'bar'] ); metrics()->set( 'foo', 1, - MetricsUnit::second(), + Unit::second(), ['foo' => 'bar'] ); metrics()->set( 'foo', 'foo', - MetricsUnit::second(), + Unit::second(), ['foo' => 'bar'] ); @@ -208,7 +208,7 @@ public function testMetricsSummary(): void metrics()->increment( 'foo', 1, - MetricsUnit::second(), + Unit::second(), ['foo' => 'bar'] ); @@ -220,14 +220,14 @@ public function testMetricsSummary(): void metrics()->increment( 'foo', 1, - MetricsUnit::second(), + Unit::second(), ['foo' => 'bar'] ); metrics()->increment( 'foo', 1, - MetricsUnit::second(), + Unit::second(), ['foo' => 'bar'] ); diff --git a/tests/Serializer/PayloadSerializerTest.php b/tests/Serializer/PayloadSerializerTest.php index 82c74a351..a9ed325b8 100644 --- a/tests/Serializer/PayloadSerializerTest.php +++ b/tests/Serializer/PayloadSerializerTest.php @@ -18,7 +18,7 @@ use Sentry\Frame; use Sentry\Logs\Log; use Sentry\Logs\LogLevel; -use Sentry\Metrics\MetricsUnit; +use Sentry\Metrics\Unit; use Sentry\Metrics\Types\CounterType; use Sentry\Metrics\Types\DistributionType; use Sentry\Metrics\Types\GaugeType; @@ -433,7 +433,7 @@ public static function serializeAsEnvelopeDataProvider(): iterable $event = Event::createMetrics(new EventId('fc9442f5aef34234bb22b9a615e30ccd')); $event->setMetrics([ - new CounterType('test-counter', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], 1597790835.0, MetricsUnit::bit()), + new CounterType('test-counter', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], 1597790835.0, Unit::bit()), ]); yield [ @@ -447,7 +447,7 @@ public static function serializeAsEnvelopeDataProvider(): iterable $event = Event::createMetrics(new EventId('fc9442f5aef34234bb22b9a615e30ccd')); $event->setMetrics([ - new GaugeType('test-gauge', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], ClockMock::microtime(true), MetricsUnit::second()), + new GaugeType('test-gauge', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], ClockMock::microtime(true), Unit::second()), ]); yield [ @@ -461,7 +461,7 @@ public static function serializeAsEnvelopeDataProvider(): iterable $event = Event::createMetrics(new EventId('fc9442f5aef34234bb22b9a615e30ccd')); $event->setMetrics([ - new DistributionType('test-distribution', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], ClockMock::microtime(true), MetricsUnit::day()), + new DistributionType('test-distribution', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], ClockMock::microtime(true), Unit::day()), ]); yield [ From a3ac803b9073f2a5e858bf481201ef03fdf18881 Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Wed, 19 Nov 2025 11:15:36 +0100 Subject: [PATCH 07/17] cs --- src/Metrics/Metrics.php | 20 ++++++++++---------- src/Metrics/Types/DistributionType.php | 12 ++++++------ src/Tracing/Span.php | 6 +++--- tests/Metrics/MetricsTest.php | 2 +- tests/Serializer/PayloadSerializerTest.php | 2 +- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Metrics/Metrics.php b/src/Metrics/Metrics.php index e39f6e8fe..a4c14d0d9 100644 --- a/src/Metrics/Metrics.php +++ b/src/Metrics/Metrics.php @@ -45,11 +45,11 @@ public static function getInstance(): self */ public function increment( string $key, - float $value, - ?Unit $unit = null, - array $tags = [], - ?int $timestamp = null, - int $stackLevel = 0 + float $value, + ?Unit $unit = null, + array $tags = [], + ?int $timestamp = null, + int $stackLevel = 0 ): void { } @@ -115,11 +115,11 @@ public function gauge( */ public function set( string $key, - $value, - ?Unit $unit = null, - array $tags = [], - ?int $timestamp = null, - int $stackLevel = 0 + $value, + ?Unit $unit = null, + array $tags = [], + ?int $timestamp = null, + int $stackLevel = 0 ): void { } diff --git a/src/Metrics/Types/DistributionType.php b/src/Metrics/Types/DistributionType.php index 8ebe203e5..0ffdb589a 100644 --- a/src/Metrics/Types/DistributionType.php +++ b/src/Metrics/Types/DistributionType.php @@ -28,13 +28,13 @@ final class DistributionType extends AbstractType * @param array $attributes */ public function __construct( - string $name, - $value, + string $name, + $value, TraceId $traceId, - SpanId $spanId, - array $attributes, - float $timestamp, - ?Unit $unit, + SpanId $spanId, + array $attributes, + float $timestamp, + ?Unit $unit, ) { parent::__construct($name, $traceId, $spanId, $timestamp, $attributes, $unit); diff --git a/src/Tracing/Span.php b/src/Tracing/Span.php index 8d1942fe1..0810f6906 100644 --- a/src/Tracing/Span.php +++ b/src/Tracing/Span.php @@ -547,9 +547,9 @@ public function getMetricsSummary(): array public function setMetricsSummary( string $type, string $key, - $value, - Unit $unit, - array $tags + $value, + Unit $unit, + array $tags ): void { } diff --git a/tests/Metrics/MetricsTest.php b/tests/Metrics/MetricsTest.php index 1e1399a40..c741bb95f 100644 --- a/tests/Metrics/MetricsTest.php +++ b/tests/Metrics/MetricsTest.php @@ -9,10 +9,10 @@ use Sentry\ClientInterface; use Sentry\Event; use Sentry\Metrics\MetricsAggregator; -use Sentry\Metrics\Unit; use Sentry\Metrics\Types\CounterType; use Sentry\Metrics\Types\DistributionType; use Sentry\Metrics\Types\GaugeType; +use Sentry\Metrics\Unit; use Sentry\Options; use Sentry\SentrySdk; use Sentry\State\Hub; diff --git a/tests/Serializer/PayloadSerializerTest.php b/tests/Serializer/PayloadSerializerTest.php index a9ed325b8..c4287cd67 100644 --- a/tests/Serializer/PayloadSerializerTest.php +++ b/tests/Serializer/PayloadSerializerTest.php @@ -18,10 +18,10 @@ use Sentry\Frame; use Sentry\Logs\Log; use Sentry\Logs\LogLevel; -use Sentry\Metrics\Unit; use Sentry\Metrics\Types\CounterType; use Sentry\Metrics\Types\DistributionType; use Sentry\Metrics\Types\GaugeType; +use Sentry\Metrics\Unit; use Sentry\MonitorConfig; use Sentry\MonitorSchedule; use Sentry\Options; From b7c6f9e28436ecbacc142d24363aa1627d7378d7 Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Wed, 19 Nov 2025 11:23:03 +0100 Subject: [PATCH 08/17] lints --- phpstan-baseline.neon | 10 ---------- src/Metrics/Types/AbstractType.php | 8 +++++++- src/Metrics/Types/CounterType.php | 7 +++++-- src/Metrics/Types/DistributionType.php | 7 +++++-- src/Metrics/Types/GaugeType.php | 7 +++++-- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3ff509ab0..e4ce16ef5 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -25,21 +25,11 @@ parameters: count: 1 path: src/Dsn.php - - - message: "#^Method Sentry\\\\Event\\:\\:getMetrics\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/Event.php - - message: "#^Method Sentry\\\\Event\\:\\:getMetricsSummary\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 path: src/Event.php - - - message: "#^Method Sentry\\\\Event\\:\\:setMetrics\\(\\) has parameter \\$metrics with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Event.php - - message: "#^Method Sentry\\\\Event\\:\\:setMetricsSummary\\(\\) has parameter \\$metricsSummary with no value type specified in iterable type array\\.$#" count: 1 diff --git a/src/Metrics/Types/AbstractType.php b/src/Metrics/Types/AbstractType.php index 9fc6bae19..7e95a5046 100644 --- a/src/Metrics/Types/AbstractType.php +++ b/src/Metrics/Types/AbstractType.php @@ -45,7 +45,7 @@ abstract class AbstractType private $unit; /** - * @param array $attributes + * @param array $attributes */ public function __construct( string $name, @@ -67,10 +67,16 @@ public function __construct( } } + /** + * @param int|float|string $value + */ abstract public function setValue($value): void; abstract public function getType(): string; + /** + * @return int|float|string + */ abstract public function getValue(); public function getName(): string diff --git a/src/Metrics/Types/CounterType.php b/src/Metrics/Types/CounterType.php index 3f3cc4a5c..77391d811 100644 --- a/src/Metrics/Types/CounterType.php +++ b/src/Metrics/Types/CounterType.php @@ -24,8 +24,8 @@ final class CounterType extends AbstractType private $value; /** - * @param int|float $value - * @param array $attributes + * @param int|float $value + * @param array $attributes */ public function __construct( string $name, @@ -49,6 +49,9 @@ public function setValue($value): void $this->value = $value; } + /** + * @return int|float + */ public function getValue() { return $this->value; diff --git a/src/Metrics/Types/DistributionType.php b/src/Metrics/Types/DistributionType.php index 0ffdb589a..a41a978ed 100644 --- a/src/Metrics/Types/DistributionType.php +++ b/src/Metrics/Types/DistributionType.php @@ -24,8 +24,8 @@ final class DistributionType extends AbstractType private $value; /** - * @param int|float $value - * @param array $attributes + * @param int|float $value + * @param array $attributes */ public function __construct( string $name, @@ -49,6 +49,9 @@ public function setValue($value): void $this->value = $value; } + /** + * @return int|float + */ public function getValue() { return $this->value; diff --git a/src/Metrics/Types/GaugeType.php b/src/Metrics/Types/GaugeType.php index 2249f7579..3f1e1fcf1 100644 --- a/src/Metrics/Types/GaugeType.php +++ b/src/Metrics/Types/GaugeType.php @@ -24,8 +24,8 @@ final class GaugeType extends AbstractType private $value; /** - * @param int|float $value - * @param array $attributes + * @param int|float $value + * @param array $attributes */ public function __construct( string $name, @@ -49,6 +49,9 @@ public function setValue($value): void $this->value = $value; } + /** + * @return int|float + */ public function getValue() { return $this->value; From 82e101f67ceba587bc5d1437e5285acbaf9ed825 Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Wed, 19 Nov 2025 11:24:36 +0100 Subject: [PATCH 09/17] fix --- src/Metrics/Types/DistributionType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Metrics/Types/DistributionType.php b/src/Metrics/Types/DistributionType.php index a41a978ed..79cd8d625 100644 --- a/src/Metrics/Types/DistributionType.php +++ b/src/Metrics/Types/DistributionType.php @@ -34,7 +34,7 @@ public function __construct( SpanId $spanId, array $attributes, float $timestamp, - ?Unit $unit, + ?Unit $unit ) { parent::__construct($name, $traceId, $spanId, $timestamp, $attributes, $unit); From 080e9b15801906eb2271ed26b3734ea791bc9210 Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Wed, 19 Nov 2025 11:35:11 +0100 Subject: [PATCH 10/17] psalm --- src/Metrics/Types/AbstractType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Metrics/Types/AbstractType.php b/src/Metrics/Types/AbstractType.php index 7e95a5046..9e637e48a 100644 --- a/src/Metrics/Types/AbstractType.php +++ b/src/Metrics/Types/AbstractType.php @@ -68,7 +68,7 @@ public function __construct( } /** - * @param int|float|string $value + * @param int|float $value */ abstract public function setValue($value): void; From 30db6b2b3dd5727c18b08b67dc8c3b6f9882f145 Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Thu, 20 Nov 2025 15:22:20 +0100 Subject: [PATCH 11/17] Apply suggestion from @Litarnus --- src/Metrics/Types/AbstractType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Metrics/Types/AbstractType.php b/src/Metrics/Types/AbstractType.php index 9e637e48a..e0be457b8 100644 --- a/src/Metrics/Types/AbstractType.php +++ b/src/Metrics/Types/AbstractType.php @@ -75,7 +75,7 @@ abstract public function setValue($value): void; abstract public function getType(): string; /** - * @return int|float|string + * @return int|float */ abstract public function getValue(); From 42a7fae40a8b1984e2210d6785da89723a7852ac Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Mon, 24 Nov 2025 15:43:01 +0100 Subject: [PATCH 12/17] add TraceMetrics, revert Metrics to old state to remain BC --- src/Metrics/Metrics.php | 87 ++++-------- src/Metrics/TraceMetrics.php | 99 ++++++++++++++ src/functions.php | 8 +- tests/Metrics/MetricsTest.php | 205 +++++++++++++---------------- tests/Metrics/TraceMetricsTest.php | 85 ++++++++++++ tests/StubTransport.php | 31 +++++ 6 files changed, 344 insertions(+), 171 deletions(-) create mode 100644 src/Metrics/TraceMetrics.php create mode 100644 tests/Metrics/TraceMetricsTest.php create mode 100644 tests/StubTransport.php diff --git a/src/Metrics/Metrics.php b/src/Metrics/Metrics.php index a4c14d0d9..20a825d41 100644 --- a/src/Metrics/Metrics.php +++ b/src/Metrics/Metrics.php @@ -5,13 +5,15 @@ namespace Sentry\Metrics; use Sentry\EventId; -use Sentry\Metrics\Types\CounterType; -use Sentry\Metrics\Types\DistributionType; -use Sentry\Metrics\Types\GaugeType; use Sentry\Tracing\SpanContext; use function Sentry\trace; +class_alias(Unit::class, '\Sentry\Metrics\MetricsUnit'); + +/** + * @deprecated use TraceMetrics instead + */ class Metrics { /** @@ -19,16 +21,6 @@ class Metrics */ private static $instance; - /** - * @var MetricsAggregator - */ - private $aggregator; - - private function __construct() - { - $this->aggregator = new MetricsAggregator(); - } - public static function getInstance(): self { if (self::$instance === null) { @@ -41,7 +33,7 @@ public static function getInstance(): self /** * @param array $tags * - * @deprecated Use Metrics::count() instead. To be removed in 5.x. + * @deprecated Use TraceMetrics::count() instead. To be removed in 5.x. */ public function increment( string $key, @@ -54,69 +46,45 @@ public function increment( } /** - * @param array $attributes - */ - public function count( - string $name, - float $value, - array $attributes = [], - ?Unit $unit = null - ): void { - $this->aggregator->add( - CounterType::TYPE, - $name, - $value, - $attributes, - $unit - ); - } - - /** - * @param array $attributes + * @param array $tags + * + * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. */ public function distribution( - string $name, + string $key, float $value, - array $attributes = [], - ?Unit $unit = null + ?Unit $unit = null, + array $tags = [], + ?int $timestamp = null, + int $stackLevel = 0 ): void { - $this->aggregator->add( - DistributionType::TYPE, - $name, - $value, - $attributes, - $unit - ); } /** - * @param array $attributes + * @param array $tags + * + * @deprecated Use TraceMetrics::gauge() instead. To be removed in 5.x. */ public function gauge( - string $name, + string $key, float $value, - array $attributes = [], - ?Unit $unit = null + ?Unit $unit = null, + array $tags = [], + ?int $timestamp = null, + int $stackLevel = 0 ): void { - $this->aggregator->add( - GaugeType::TYPE, - $name, - $value, - $attributes, - $unit - ); } /** * @param int|string $value * @param array $tags * - * @deprecated To be removed in 5.x. + * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. */ public function set( string $key, $value, - ?Unit $unit = null, + ?MetricsUnit $unit = null, array $tags = [], ?int $timestamp = null, int $stackLevel = 0 @@ -131,7 +99,7 @@ public function set( * * @return T * - * @deprecated To be removed in 5.x. + * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. */ public function timing( string $key, @@ -150,8 +118,11 @@ function () use ($callback) { ); } + /** + * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. + */ public function flush(): ?EventId { - return $this->aggregator->flush(); + return null; } } diff --git a/src/Metrics/TraceMetrics.php b/src/Metrics/TraceMetrics.php new file mode 100644 index 000000000..d21609ff1 --- /dev/null +++ b/src/Metrics/TraceMetrics.php @@ -0,0 +1,99 @@ +aggregator = new MetricsAggregator(); + } + + public static function getInstance(): self + { + if (self::$instance === null) { + self::$instance = new TraceMetrics(); + } + + return self::$instance; + } + + /** + * @param int|float $value + * @param array $attributes + */ + public function count( + string $name, + $value, + array $attributes = [], + ?Unit $unit = null + ): void { + $this->aggregator->add( + CounterType::TYPE, + $name, + $value, + $attributes, + $unit + ); + } + + /** + * @param int|float $value + * @param array $attributes + */ + public function distribution( + string $name, + $value, + array $attributes = [], + ?Unit $unit = null + ): void { + $this->aggregator->add( + DistributionType::TYPE, + $name, + $value, + $attributes, + $unit + ); + } + + /** + * @param int|float $value + * @param array $attributes + */ + public function gauge( + string $name, + $value, + array $attributes = [], + ?Unit $unit = null + ): void { + $this->aggregator->add( + GaugeType::TYPE, + $name, + $value, + $attributes, + $unit + ); + } + + public function flush(): ?EventId + { + return $this->aggregator->flush(); + } +} diff --git a/src/functions.php b/src/functions.php index 84f275a23..af967c8f9 100644 --- a/src/functions.php +++ b/src/functions.php @@ -9,6 +9,7 @@ use Sentry\Integration\IntegrationInterface; use Sentry\Logs\Logs; use Sentry\Metrics\Metrics; +use Sentry\Metrics\TraceMetrics; use Sentry\State\Scope; use Sentry\Tracing\PropagationContext; use Sentry\Tracing\SpanContext; @@ -373,13 +374,18 @@ function logger(): Logs } /** - * Get the Sentry Metrics client. + * @deprecated use `trace_metrics` instead */ function metrics(): Metrics { return Metrics::getInstance(); } +function trace_metrics(): TraceMetrics +{ + return TraceMetrics::getInstance(); +} + /** * Adds a feature flag evaluation to the current scope. * When invoked repeatedly for the same name, the most recent value is used. diff --git a/tests/Metrics/MetricsTest.php b/tests/Metrics/MetricsTest.php index c741bb95f..3de480657 100644 --- a/tests/Metrics/MetricsTest.php +++ b/tests/Metrics/MetricsTest.php @@ -5,23 +5,14 @@ namespace Sentry\Tests; use PHPUnit\Framework\TestCase; -use Sentry\Client; use Sentry\ClientInterface; use Sentry\Event; -use Sentry\Metrics\MetricsAggregator; -use Sentry\Metrics\Types\CounterType; -use Sentry\Metrics\Types\DistributionType; -use Sentry\Metrics\Types\GaugeType; -use Sentry\Metrics\Unit; +use Sentry\Metrics\MetricsUnit; use Sentry\Options; use Sentry\SentrySdk; use Sentry\State\Hub; -use Sentry\State\HubAdapter; use Sentry\Tracing\SpanContext; use Sentry\Tracing\TransactionContext; -use Sentry\Transport\Result; -use Sentry\Transport\ResultStatus; -use Sentry\Transport\TransportInterface; use Sentry\Util\ClockMock; use function Sentry\metrics; @@ -53,14 +44,53 @@ public function testIncrement(): void metrics()->increment( 'foo', 1, - Unit::second(), + MetricsUnit::second(), ['foo' => 'bar'] ); metrics()->increment( 'foo', 2, - Unit::second(), + MetricsUnit::second(), + ['foo' => 'bar'] + ); + + metrics()->flush(); + } + + public function testDistribution(): void + { + ClockMock::withClockMock(1699412953); + + /** @var ClientInterface&MockObject $client */ + $client = $this->createMock(ClientInterface::class); + $client->expects($this->any()) + ->method('getOptions') + ->willReturn(new Options([ + 'release' => '1.0.0', + 'environment' => 'development', + 'attach_metric_code_locations' => true, + ])); + + $self = $this; + + $client->expects($this->never()) + ->method('captureEvent'); + + $hub = new Hub($client); + SentrySdk::setCurrentHub($hub); + + metrics()->distribution( + 'foo', + 1, + MetricsUnit::second(), + ['foo' => 'bar'] + ); + + metrics()->distribution( + 'foo', + 2, + MetricsUnit::second(), ['foo' => 'bar'] ); @@ -74,12 +104,12 @@ public function testTiming(): void /** @var ClientInterface&MockObject $client */ $client = $this->createMock(ClientInterface::class); $client->expects($this->any()) - ->method('getOptions') - ->willReturn(new Options([ - 'release' => '1.0.0', - 'environment' => 'development', - 'attach_metric_code_locations' => true, - ])); + ->method('getOptions') + ->willReturn(new Options([ + 'release' => '1.0.0', + 'environment' => 'development', + 'attach_metric_code_locations' => true, + ])); $self = $this; @@ -118,6 +148,45 @@ static function () { metrics()->flush(); } + public function testGauge(): void + { + ClockMock::withClockMock(1699412953); + + /** @var ClientInterface&MockObject $client */ + $client = $this->createMock(ClientInterface::class); + $client->expects($this->any()) + ->method('getOptions') + ->willReturn(new Options([ + 'release' => '1.0.0', + 'environment' => 'development', + 'attach_metric_code_locations' => true, + ])); + + $self = $this; + + $client->expects($this->never()) + ->method('captureEvent'); + + $hub = new Hub($client); + SentrySdk::setCurrentHub($hub); + + metrics()->gauge( + 'foo', + 1, + MetricsUnit::second(), + ['foo' => 'bar'] + ); + + metrics()->gauge( + 'foo', + 2, + MetricsUnit::second(), + ['foo' => 'bar'] + ); + + metrics()->flush(); + } + public function testSet(): void { ClockMock::withClockMock(1699412953); @@ -143,21 +212,21 @@ public function testSet(): void metrics()->set( 'foo', 1, - Unit::second(), + MetricsUnit::second(), ['foo' => 'bar'] ); metrics()->set( 'foo', 1, - Unit::second(), + MetricsUnit::second(), ['foo' => 'bar'] ); metrics()->set( 'foo', 'foo', - Unit::second(), + MetricsUnit::second(), ['foo' => 'bar'] ); @@ -208,7 +277,7 @@ public function testMetricsSummary(): void metrics()->increment( 'foo', 1, - Unit::second(), + MetricsUnit::second(), ['foo' => 'bar'] ); @@ -220,106 +289,18 @@ public function testMetricsSummary(): void metrics()->increment( 'foo', 1, - Unit::second(), + MetricsUnit::second(), ['foo' => 'bar'] ); metrics()->increment( 'foo', 1, - Unit::second(), + MetricsUnit::second(), ['foo' => 'bar'] ); $span->finish(); $transaction->finish(); } - - // ======= Metrics V2 ========= - - protected function setUp(): void - { - HubAdapter::getInstance()->bindClient(new Client(new Options(), new StubTransport())); - StubTransport::$events = []; - } - - public function testCounterMetrics(): void - { - metrics()->count('test-count', 2, ['foo' => 'bar']); - metrics()->count('test-count', 2, ['foo' => 'bar']); - metrics()->flush(); - - $this->assertCount(1, StubTransport::$events); - $event = StubTransport::$events[0]; - $this->assertCount(2, $event->getMetrics()); - $metrics = $event->getMetrics(); - $metric = $metrics[0]; - $this->assertEquals('test-count', $metric->getName()); - $this->assertEquals(CounterType::TYPE, $metric->getType()); - $this->assertEquals(2, $metric->getValue()); - $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); - } - - public function testGaugeMetrics(): void - { - metrics()->gauge('test-gauge', 10, ['foo' => 'bar']); - metrics()->flush(); - - $this->assertCount(1, StubTransport::$events); - $event = StubTransport::$events[0]; - $this->assertCount(1, $event->getMetrics()); - $metrics = $event->getMetrics(); - $metric = $metrics[0]; - $this->assertEquals('test-gauge', $metric->getName()); - $this->assertEquals(GaugeType::TYPE, $metric->getType()); - $this->assertEquals(10, $metric->getValue()); - $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); - } - - public function testDistributionMetrics(): void - { - metrics()->distribution('test-distribution', 10, ['foo' => 'bar']); - metrics()->flush(); - $this->assertCount(1, StubTransport::$events); - $event = StubTransport::$events[0]; - $this->assertCount(1, $event->getMetrics()); - $metrics = $event->getMetrics(); - $metric = $metrics[0]; - $this->assertEquals('test-distribution', $metric->getName()); - $this->assertEquals(DistributionType::TYPE, $metric->getType()); - $this->assertEquals(10, $metric->getValue()); - $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); - } - - public function testMetricsBufferFull(): void - { - for ($i = 0; $i < MetricsAggregator::METRICS_BUFFER_SIZE + 100; ++$i) { - metrics()->count('test', 1, ['foo' => 'bar']); - } - metrics()->flush(); - $this->assertCount(1, StubTransport::$events); - $event = StubTransport::$events[0]; - $metrics = $event->getMetrics(); - $this->assertCount(MetricsAggregator::METRICS_BUFFER_SIZE, $metrics); - } -} - -class StubTransport implements TransportInterface -{ - /** - * @var Event[] - */ - public static $events = []; - - public function send(Event $event): Result - { - self::$events[] = $event; - - return new Result(ResultStatus::success()); - } - - public function close(?int $timeout = null): Result - { - return new Result(ResultStatus::success()); - } } diff --git a/tests/Metrics/TraceMetricsTest.php b/tests/Metrics/TraceMetricsTest.php new file mode 100644 index 000000000..ab86559d2 --- /dev/null +++ b/tests/Metrics/TraceMetricsTest.php @@ -0,0 +1,85 @@ +bindClient(new Client(new Options(), new StubTransport())); + StubTransport::$events = []; + } + + public function testCounterMetrics(): void + { + trace_metrics()->count('test-count', 2, ['foo' => 'bar']); + trace_metrics()->count('test-count', 2, ['foo' => 'bar']); + trace_metrics()->flush(); + + $this->assertCount(1, StubTransport::$events); + $event = StubTransport::$events[0]; + $this->assertCount(2, $event->getMetrics()); + $metrics = $event->getMetrics(); + $metric = $metrics[0]; + $this->assertEquals('test-count', $metric->getName()); + $this->assertEquals(CounterType::TYPE, $metric->getType()); + $this->assertEquals(2, $metric->getValue()); + $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); + } + + public function testGaugeMetrics(): void + { + trace_metrics()->gauge('test-gauge', 10, ['foo' => 'bar']); + trace_metrics()->flush(); + + $this->assertCount(1, StubTransport::$events); + $event = StubTransport::$events[0]; + $this->assertCount(1, $event->getMetrics()); + $metrics = $event->getMetrics(); + $metric = $metrics[0]; + $this->assertEquals('test-gauge', $metric->getName()); + $this->assertEquals(GaugeType::TYPE, $metric->getType()); + $this->assertEquals(10, $metric->getValue()); + $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); + } + + public function testDistributionMetrics(): void + { + trace_metrics()->distribution('test-distribution', 10, ['foo' => 'bar']); + trace_metrics()->flush(); + $this->assertCount(1, StubTransport::$events); + $event = StubTransport::$events[0]; + $this->assertCount(1, $event->getMetrics()); + $metrics = $event->getMetrics(); + $metric = $metrics[0]; + $this->assertEquals('test-distribution', $metric->getName()); + $this->assertEquals(DistributionType::TYPE, $metric->getType()); + $this->assertEquals(10, $metric->getValue()); + $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); + } + + public function testMetricsBufferFull(): void + { + for ($i = 0; $i < MetricsAggregator::METRICS_BUFFER_SIZE + 100; ++$i) { + trace_metrics()->count('test', 1, ['foo' => 'bar']); + } + trace_metrics()->flush(); + $this->assertCount(1, StubTransport::$events); + $event = StubTransport::$events[0]; + $metrics = $event->getMetrics(); + $this->assertCount(MetricsAggregator::METRICS_BUFFER_SIZE, $metrics); + } +} diff --git a/tests/StubTransport.php b/tests/StubTransport.php new file mode 100644 index 000000000..7be1db638 --- /dev/null +++ b/tests/StubTransport.php @@ -0,0 +1,31 @@ + Date: Mon, 24 Nov 2025 15:44:42 +0100 Subject: [PATCH 13/17] lint --- src/Metrics/Metrics.php | 2 +- tests/StubTransport.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Metrics/Metrics.php b/src/Metrics/Metrics.php index 20a825d41..5cb6daa4b 100644 --- a/src/Metrics/Metrics.php +++ b/src/Metrics/Metrics.php @@ -84,7 +84,7 @@ public function gauge( public function set( string $key, $value, - ?MetricsUnit $unit = null, + ?Unit $unit = null, array $tags = [], ?int $timestamp = null, int $stackLevel = 0 diff --git a/tests/StubTransport.php b/tests/StubTransport.php index 7be1db638..185c5b6d5 100644 --- a/tests/StubTransport.php +++ b/tests/StubTransport.php @@ -1,5 +1,7 @@ Date: Mon, 24 Nov 2025 17:19:14 +0100 Subject: [PATCH 14/17] add enable_metrics and before_send_metric --- src/Metrics/Metrics.php | 2 +- src/Metrics/MetricsAggregator.php | 16 +++++++- src/Options.php | 62 ++++++++++++++++++++++++++++++ tests/Metrics/TraceMetricsTest.php | 36 ++++++++++++++++- tests/StubTransport.php | 14 +++++++ 5 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/Metrics/Metrics.php b/src/Metrics/Metrics.php index 5cb6daa4b..89fcd114f 100644 --- a/src/Metrics/Metrics.php +++ b/src/Metrics/Metrics.php @@ -48,7 +48,7 @@ public function increment( /** * @param array $tags * - * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. + * @deprecated Use TraceMetrics::distribution() instead. Metrics API is a no-op and will be removed in 5.x. */ public function distribution( string $key, diff --git a/src/Metrics/MetricsAggregator.php b/src/Metrics/MetricsAggregator.php index f32b222e2..652293957 100644 --- a/src/Metrics/MetricsAggregator.php +++ b/src/Metrics/MetricsAggregator.php @@ -42,7 +42,7 @@ public function __construct() ]; /** - * @param int|float|string $value + * @param int|float $value * @param array $attributes */ public function add( @@ -58,6 +58,10 @@ public function add( if ($client instanceof Client) { $options = $client->getOptions(); + if ($options->getEnableMetrics() === false) { + return; + } + $defaultAttributes = [ 'sentry.sdk.name' => $client->getSdkIdentifier(), 'sentry.sdk.version' => $client->getSdkVersion(), @@ -89,9 +93,17 @@ public function add( $metricTypeClass = self::METRIC_TYPES[$type]; /** @var AbstractType $metric */ - /** @phpstan-ignore-next-line SetType accepts int|float|string, others only int|float */ + /** @phpstan-ignore-next-line */ $metric = new $metricTypeClass($name, $value, $traceId, $spanId, $attributes, microtime(true), $unit); + if ($client !== null) { + $beforeSendMetric = $client->getOptions()->getBeforeSendMetricCallback(); + $metric = $beforeSendMetric($metric); + if ($metric === null) { + return; + } + } + $this->metrics->push($metric); } diff --git a/src/Options.php b/src/Options.php index 84ead7836..9f7568d1b 100644 --- a/src/Options.php +++ b/src/Options.php @@ -10,6 +10,7 @@ use Sentry\Integration\ErrorListenerIntegration; use Sentry\Integration\IntegrationInterface; use Sentry\Logs\Log; +use Sentry\Metrics\Types\AbstractType; use Sentry\Transport\TransportInterface; use Symfony\Component\OptionsResolver\Options as SymfonyOptions; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -177,6 +178,31 @@ public function getEnableLogs(): bool return $this->options['enable_logs'] ?? false; } + /** + * Sets if metrics should be enabled or not. + */ + public function setEnableMetrics(bool $enableTracing): self + { + $options = array_merge($this->options, ['enable_metrics' => $enableTracing]); + + $this->options = $this->resolver->resolve($options); + + return $this; + } + + /** + * Returns whether metrics are enabled or not. + */ + public function getEnableMetrics(): bool + { + /** + * @var bool $enableMetrics + */ + $enableMetrics = $this->options['enable_metrics'] ?? true; + + return $enableMetrics; + } + /** * Sets the sampling factor to apply to transactions. A value of 0 will deny * sending any transactions, and a value of 1 will send 100% of transactions. @@ -676,6 +702,35 @@ public function getBeforeSendMetricsCallback(): callable return $this->options['before_send_metrics']; } + /** + * Gets a callback that will be invoked before a metric is added. + * Returning `null` means that the metric will be discarded. + */ + public function getBeforeSendMetricCallback(): callable + { + /** + * @var callable $callback + */ + $callback = $this->options['before_send_metric']; + + return $callback; + } + + /** + * Sets a new callback that is invoked before metrics are sent. + * Returning `null` means that the metric will be discarded. + * + * @return $this + */ + public function setBeforeSendMetricCallback(callable $callback): self + { + $options = array_merge($this->options, ['before_send_metric' => $callback]); + + $this->options = $this->resolver->resolve($options); + + return $this; + } + /** * Sets a callable to be called to decide whether metrics should * be send or not. @@ -1220,6 +1275,7 @@ private function configureOptions(OptionsResolver $resolver): void 'sample_rate' => 1, 'enable_tracing' => null, 'enable_logs' => false, + 'enable_metrics' => true, 'traces_sample_rate' => null, 'traces_sampler' => null, 'profiles_sample_rate' => null, @@ -1256,10 +1312,14 @@ private function configureOptions(OptionsResolver $resolver): void }, /** * @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x. + * Use `before_send_metric` instead. */ 'before_send_metrics' => static function (Event $metrics): ?Event { return null; }, + 'before_send_metric' => static function (AbstractType $metric): AbstractType { + return $metric; + }, 'trace_propagation_targets' => null, 'strict_trace_propagation' => false, 'tags' => [], @@ -1290,6 +1350,7 @@ private function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('sample_rate', ['int', 'float']); $resolver->setAllowedTypes('enable_tracing', ['null', 'bool']); $resolver->setAllowedTypes('enable_logs', 'bool'); + $resolver->setAllowedTypes('enable_metrics', 'bool'); $resolver->setAllowedTypes('traces_sample_rate', ['null', 'int', 'float']); $resolver->setAllowedTypes('traces_sampler', ['null', 'callable']); $resolver->setAllowedTypes('profiles_sample_rate', ['null', 'int', 'float']); @@ -1309,6 +1370,7 @@ private function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('before_send', ['callable']); $resolver->setAllowedTypes('before_send_transaction', ['callable']); $resolver->setAllowedTypes('before_send_log', 'callable'); + $resolver->setAllowedTypes('before_send_metric', ['callable']); $resolver->setAllowedTypes('ignore_exceptions', 'string[]'); $resolver->setAllowedTypes('ignore_transactions', 'string[]'); $resolver->setAllowedTypes('trace_propagation_targets', ['null', 'string[]']); diff --git a/tests/Metrics/TraceMetricsTest.php b/tests/Metrics/TraceMetricsTest.php index ab86559d2..5811999fe 100644 --- a/tests/Metrics/TraceMetricsTest.php +++ b/tests/Metrics/TraceMetricsTest.php @@ -7,6 +7,7 @@ use PHPUnit\Framework\TestCase; use Sentry\Client; use Sentry\Metrics\MetricsAggregator; +use Sentry\Metrics\Types\AbstractType; use Sentry\Metrics\Types\CounterType; use Sentry\Metrics\Types\DistributionType; use Sentry\Metrics\Types\GaugeType; @@ -19,7 +20,7 @@ final class TraceMetricsTest extends TestCase { protected function setUp(): void { - HubAdapter::getInstance()->bindClient(new Client(new Options(), new StubTransport())); + HubAdapter::getInstance()->bindClient(new Client(new Options(), StubTransport::getInstance())); StubTransport::$events = []; } @@ -82,4 +83,37 @@ public function testMetricsBufferFull(): void $metrics = $event->getMetrics(); $this->assertCount(MetricsAggregator::METRICS_BUFFER_SIZE, $metrics); } + + public function testEnableMetrics(): void + { + HubAdapter::getInstance()->bindClient(new Client(new Options([ + 'enable_metrics' => false, + ]), StubTransport::getInstance())); + + trace_metrics()->count('test-count', 2, ['foo' => 'bar']); + trace_metrics()->flush(); + + $this->assertEmpty(StubTransport::$events); + } + + public function testBeforeSendMetricAltersContent() + { + HubAdapter::getInstance()->bindClient(new Client(new Options([ + 'before_send_metric' => static function (AbstractType $metric) { + $metric->setValue(99999); + + return $metric; + }, + ]), StubTransport::getInstance())); + + trace_metrics()->count('test-count', 2, ['foo' => 'bar']); + trace_metrics()->flush(); + + $this->assertCount(1, StubTransport::$events); + $event = StubTransport::$events[0]; + + $this->assertCount(1, $event->getMetrics()); + $metric = $event->getMetrics()[0]; + $this->assertEquals(99999, $metric->getValue()); + } } diff --git a/tests/StubTransport.php b/tests/StubTransport.php index 185c5b6d5..8a427622d 100644 --- a/tests/StubTransport.php +++ b/tests/StubTransport.php @@ -19,6 +19,20 @@ class StubTransport implements TransportInterface */ public static $events = []; + /** + * @var self + */ + private static $instance; + + public static function getInstance(): self + { + if (self::$instance === null) { + self::$instance = new self(); + } + + return self::$instance; + } + public function send(Event $event): Result { self::$events[] = $event; From bba56677d15e30f325470bc426206b54f0b74f68 Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Tue, 25 Nov 2025 17:10:29 +0100 Subject: [PATCH 15/17] deprecate units --- src/Metrics/Unit.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Metrics/Unit.php b/src/Metrics/Unit.php index 50637656c..d11fa86c0 100644 --- a/src/Metrics/Unit.php +++ b/src/Metrics/Unit.php @@ -141,12 +141,17 @@ public static function percent(): self return self::getInstance('percent'); } - // none and custom is removed + /** + * @deprecated `none` is not supported and will be removed in 5.x + */ public static function none(): self { return self::getInstance('none'); } + /** + * @deprecated custom unit types are currently not supported. Will be removed in 5.x + */ public static function custom(string $unit): self { return new self($unit); From ab49ab64548b0683fc713632b41dc693ceb5240a Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Thu, 27 Nov 2025 14:57:15 +0100 Subject: [PATCH 16/17] PR feedback --- src/Event.php | 8 ++-- src/EventType.php | 1 + src/Metrics/Metrics.php | 1 + src/Metrics/MetricsAggregator.php | 36 +++++++++++++----- src/Metrics/TraceMetrics.php | 13 ++++--- .../{CounterType.php => CounterMetric.php} | 4 +- ...ibutionType.php => DistributionMetric.php} | 4 +- .../Types/{GaugeType.php => GaugeMetric.php} | 4 +- .../Types/{AbstractType.php => Metric.php} | 4 +- src/Options.php | 4 +- src/Serializer/EnvelopItems/MetricsItem.php | 4 +- src/Serializer/PayloadSerializer.php | 2 +- src/Tracing/Span.php | 2 +- src/{Metrics => }/Unit.php | 2 +- tests/Metrics/TraceMetricsTest.php | 16 ++++---- tests/Serializer/PayloadSerializerTest.php | 38 +++++++++---------- 16 files changed, 82 insertions(+), 61 deletions(-) rename src/Metrics/Types/{CounterType.php => CounterMetric.php} (93%) rename src/Metrics/Types/{DistributionType.php => DistributionMetric.php} (93%) rename src/Metrics/Types/{GaugeType.php => GaugeMetric.php} (94%) rename src/Metrics/Types/{AbstractType.php => Metric.php} (97%) rename src/{Metrics => }/Unit.php (99%) diff --git a/src/Event.php b/src/Event.php index 4b1c039b4..e2d2a8c0f 100644 --- a/src/Event.php +++ b/src/Event.php @@ -7,7 +7,7 @@ use Sentry\Context\OsContext; use Sentry\Context\RuntimeContext; use Sentry\Logs\Log; -use Sentry\Metrics\Types\AbstractType; +use Sentry\Metrics\Types\Metric; use Sentry\Profiling\Profile; use Sentry\Tracing\Span; @@ -73,7 +73,7 @@ final class Event private $logs = []; /** - * @var AbstractType[] + * @var Metric[] */ private $metrics = []; @@ -449,7 +449,7 @@ public function setLogs(array $logs): self } /** - * @return AbstractType[] + * @return Metric[] */ public function getMetrics(): array { @@ -457,7 +457,7 @@ public function getMetrics(): array } /** - * @param AbstractType[] $metrics + * @param Metric[] $metrics */ public function setMetrics(array $metrics): self { diff --git a/src/EventType.php b/src/EventType.php index ccdcd1418..679f96633 100644 --- a/src/EventType.php +++ b/src/EventType.php @@ -72,6 +72,7 @@ public function requiresEventId(): bool { switch ($this) { case self::metrics(): + case self::logs(): return false; default: return true; diff --git a/src/Metrics/Metrics.php b/src/Metrics/Metrics.php index 89fcd114f..21fc15607 100644 --- a/src/Metrics/Metrics.php +++ b/src/Metrics/Metrics.php @@ -7,6 +7,7 @@ use Sentry\EventId; use Sentry\Tracing\SpanContext; +use Sentry\Unit; use function Sentry\trace; class_alias(Unit::class, '\Sentry\Metrics\MetricsUnit'); diff --git a/src/Metrics/MetricsAggregator.php b/src/Metrics/MetricsAggregator.php index 652293957..ce81f59e8 100644 --- a/src/Metrics/MetricsAggregator.php +++ b/src/Metrics/MetricsAggregator.php @@ -7,10 +7,10 @@ use Sentry\Client; use Sentry\Event; use Sentry\EventId; -use Sentry\Metrics\Types\AbstractType; -use Sentry\Metrics\Types\CounterType; -use Sentry\Metrics\Types\DistributionType; -use Sentry\Metrics\Types\GaugeType; +use Sentry\Metrics\Types\CounterMetric; +use Sentry\Metrics\Types\DistributionMetric; +use Sentry\Metrics\Types\GaugeMetric; +use Sentry\Metrics\Types\Metric; use Sentry\SentrySdk; use Sentry\State\Scope; use Sentry\Util\RingBuffer; @@ -26,7 +26,7 @@ final class MetricsAggregator public const METRICS_BUFFER_SIZE = 1000; /** - * @var RingBuffer + * @var RingBuffer */ private $metrics; @@ -36,9 +36,9 @@ public function __construct() } private const METRIC_TYPES = [ - CounterType::TYPE => CounterType::class, - DistributionType::TYPE => DistributionType::class, - GaugeType::TYPE => GaugeType::class, + CounterMetric::TYPE => CounterMetric::class, + DistributionMetric::TYPE => DistributionMetric::class, + GaugeMetric::TYPE => GaugeMetric::class, ]; /** @@ -66,8 +66,26 @@ public function add( 'sentry.sdk.name' => $client->getSdkIdentifier(), 'sentry.sdk.version' => $client->getSdkVersion(), 'sentry.environment' => $options->getEnvironment() ?? Event::DEFAULT_ENVIRONMENT, + 'server.address' => $options->getServerName(), ]; + if ($options->shouldSendDefaultPii()) { + $hub->configureScope(function (Scope $scope) use (&$defaultAttributes) { + $user = $scope->getUser(); + if ($user !== null) { + if ($user->getId() !== null) { + $defaultAttributes['user.id'] = $user->getId(); + } + if ($user->getEmail() !== null) { + $defaultAttributes['user.email'] = $user->getEmail(); + } + if ($user->getUsername() !== null) { + $defaultAttributes['user.name'] = $user->getUsername(); + } + } + }); + } + $release = $options->getRelease(); if ($release !== null) { $defaultAttributes['sentry.release'] = $release; @@ -92,7 +110,7 @@ public function add( } $metricTypeClass = self::METRIC_TYPES[$type]; - /** @var AbstractType $metric */ + /** @var Metric $metric */ /** @phpstan-ignore-next-line */ $metric = new $metricTypeClass($name, $value, $traceId, $spanId, $attributes, microtime(true), $unit); diff --git a/src/Metrics/TraceMetrics.php b/src/Metrics/TraceMetrics.php index d21609ff1..a3ef4a0a0 100644 --- a/src/Metrics/TraceMetrics.php +++ b/src/Metrics/TraceMetrics.php @@ -5,9 +5,10 @@ namespace Sentry\Metrics; use Sentry\EventId; -use Sentry\Metrics\Types\CounterType; -use Sentry\Metrics\Types\DistributionType; -use Sentry\Metrics\Types\GaugeType; +use Sentry\Metrics\Types\CounterMetric; +use Sentry\Metrics\Types\DistributionMetric; +use Sentry\Metrics\Types\GaugeMetric; +use Sentry\Unit; class TraceMetrics { @@ -46,7 +47,7 @@ public function count( ?Unit $unit = null ): void { $this->aggregator->add( - CounterType::TYPE, + CounterMetric::TYPE, $name, $value, $attributes, @@ -65,7 +66,7 @@ public function distribution( ?Unit $unit = null ): void { $this->aggregator->add( - DistributionType::TYPE, + DistributionMetric::TYPE, $name, $value, $attributes, @@ -84,7 +85,7 @@ public function gauge( ?Unit $unit = null ): void { $this->aggregator->add( - GaugeType::TYPE, + GaugeMetric::TYPE, $name, $value, $attributes, diff --git a/src/Metrics/Types/CounterType.php b/src/Metrics/Types/CounterMetric.php similarity index 93% rename from src/Metrics/Types/CounterType.php rename to src/Metrics/Types/CounterMetric.php index 77391d811..a309e176d 100644 --- a/src/Metrics/Types/CounterType.php +++ b/src/Metrics/Types/CounterMetric.php @@ -4,14 +4,14 @@ namespace Sentry\Metrics\Types; -use Sentry\Metrics\Unit; use Sentry\Tracing\SpanId; use Sentry\Tracing\TraceId; +use Sentry\Unit; /** * @internal */ -final class CounterType extends AbstractType +final class CounterMetric extends Metric { /** * @var string diff --git a/src/Metrics/Types/DistributionType.php b/src/Metrics/Types/DistributionMetric.php similarity index 93% rename from src/Metrics/Types/DistributionType.php rename to src/Metrics/Types/DistributionMetric.php index 79cd8d625..14e39c01d 100644 --- a/src/Metrics/Types/DistributionType.php +++ b/src/Metrics/Types/DistributionMetric.php @@ -4,14 +4,14 @@ namespace Sentry\Metrics\Types; -use Sentry\Metrics\Unit; +use Sentry\Unit; use Sentry\Tracing\SpanId; use Sentry\Tracing\TraceId; /** * @internal */ -final class DistributionType extends AbstractType +final class DistributionMetric extends Metric { /** * @var string diff --git a/src/Metrics/Types/GaugeType.php b/src/Metrics/Types/GaugeMetric.php similarity index 94% rename from src/Metrics/Types/GaugeType.php rename to src/Metrics/Types/GaugeMetric.php index 3f1e1fcf1..2b58745be 100644 --- a/src/Metrics/Types/GaugeType.php +++ b/src/Metrics/Types/GaugeMetric.php @@ -4,14 +4,14 @@ namespace Sentry\Metrics\Types; -use Sentry\Metrics\Unit; use Sentry\Tracing\SpanId; use Sentry\Tracing\TraceId; +use Sentry\Unit; /** * @internal */ -final class GaugeType extends AbstractType +final class GaugeMetric extends Metric { /** * @var string diff --git a/src/Metrics/Types/AbstractType.php b/src/Metrics/Types/Metric.php similarity index 97% rename from src/Metrics/Types/AbstractType.php rename to src/Metrics/Types/Metric.php index e0be457b8..999acbed9 100644 --- a/src/Metrics/Types/AbstractType.php +++ b/src/Metrics/Types/Metric.php @@ -5,14 +5,14 @@ namespace Sentry\Metrics\Types; use Sentry\Attributes\AttributeBag; -use Sentry\Metrics\Unit; use Sentry\Tracing\SpanId; use Sentry\Tracing\TraceId; +use Sentry\Unit; /** * @internal */ -abstract class AbstractType +abstract class Metric { /** * @var string diff --git a/src/Options.php b/src/Options.php index 9f7568d1b..8e1ee2279 100644 --- a/src/Options.php +++ b/src/Options.php @@ -10,7 +10,7 @@ use Sentry\Integration\ErrorListenerIntegration; use Sentry\Integration\IntegrationInterface; use Sentry\Logs\Log; -use Sentry\Metrics\Types\AbstractType; +use Sentry\Metrics\Types\Metric; use Sentry\Transport\TransportInterface; use Symfony\Component\OptionsResolver\Options as SymfonyOptions; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -1317,7 +1317,7 @@ private function configureOptions(OptionsResolver $resolver): void 'before_send_metrics' => static function (Event $metrics): ?Event { return null; }, - 'before_send_metric' => static function (AbstractType $metric): AbstractType { + 'before_send_metric' => static function (Metric $metric): Metric { return $metric; }, 'trace_propagation_targets' => null, diff --git a/src/Serializer/EnvelopItems/MetricsItem.php b/src/Serializer/EnvelopItems/MetricsItem.php index 978828011..1a2b41092 100644 --- a/src/Serializer/EnvelopItems/MetricsItem.php +++ b/src/Serializer/EnvelopItems/MetricsItem.php @@ -7,7 +7,7 @@ use Sentry\Attributes\Attribute; use Sentry\Event; use Sentry\EventType; -use Sentry\Metrics\Types\AbstractType; +use Sentry\Metrics\Types\Metric; use Sentry\Util\JSON; /** @@ -29,7 +29,7 @@ public static function toEnvelopeItem(Event $event): string "%s\n%s", JSON::encode($header), JSON::encode([ - 'items' => array_map(static function (AbstractType $metric): array { + 'items' => array_map(static function (Metric $metric): array { return [ 'timestamp' => $metric->getTimestamp(), 'trace_id' => (string) $metric->getTraceId(), diff --git a/src/Serializer/PayloadSerializer.php b/src/Serializer/PayloadSerializer.php index 3a2cfc926..45de0f29f 100644 --- a/src/Serializer/PayloadSerializer.php +++ b/src/Serializer/PayloadSerializer.php @@ -47,7 +47,7 @@ public function serialize(Event $event): string ]; if ($event->getType()->requiresEventId()) { - $envelopeHeader = ['event_id' => (string) $event->getId()] + $envelopeHeader; + $envelopeHeader['event_id'] = (string) $event->getId(); } $dynamicSamplingContext = $event->getSdkMetadata('dynamic_sampling_context'); diff --git a/src/Tracing/Span.php b/src/Tracing/Span.php index 0810f6906..cbec6b15a 100644 --- a/src/Tracing/Span.php +++ b/src/Tracing/Span.php @@ -5,7 +5,7 @@ namespace Sentry\Tracing; use Sentry\EventId; -use Sentry\Metrics\Unit; +use Sentry\Unit; use Sentry\SentrySdk; use Sentry\State\Scope; diff --git a/src/Metrics/Unit.php b/src/Unit.php similarity index 99% rename from src/Metrics/Unit.php rename to src/Unit.php index d11fa86c0..5a83ab720 100644 --- a/src/Metrics/Unit.php +++ b/src/Unit.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Sentry\Metrics; +namespace Sentry; final class Unit implements \Stringable { diff --git a/tests/Metrics/TraceMetricsTest.php b/tests/Metrics/TraceMetricsTest.php index 5811999fe..13fea3081 100644 --- a/tests/Metrics/TraceMetricsTest.php +++ b/tests/Metrics/TraceMetricsTest.php @@ -7,10 +7,10 @@ use PHPUnit\Framework\TestCase; use Sentry\Client; use Sentry\Metrics\MetricsAggregator; -use Sentry\Metrics\Types\AbstractType; -use Sentry\Metrics\Types\CounterType; -use Sentry\Metrics\Types\DistributionType; -use Sentry\Metrics\Types\GaugeType; +use Sentry\Metrics\Types\Metric; +use Sentry\Metrics\Types\CounterMetric; +use Sentry\Metrics\Types\DistributionMetric; +use Sentry\Metrics\Types\GaugeMetric; use Sentry\Options; use Sentry\State\HubAdapter; @@ -36,7 +36,7 @@ public function testCounterMetrics(): void $metrics = $event->getMetrics(); $metric = $metrics[0]; $this->assertEquals('test-count', $metric->getName()); - $this->assertEquals(CounterType::TYPE, $metric->getType()); + $this->assertEquals(CounterMetric::TYPE, $metric->getType()); $this->assertEquals(2, $metric->getValue()); $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); } @@ -52,7 +52,7 @@ public function testGaugeMetrics(): void $metrics = $event->getMetrics(); $metric = $metrics[0]; $this->assertEquals('test-gauge', $metric->getName()); - $this->assertEquals(GaugeType::TYPE, $metric->getType()); + $this->assertEquals(GaugeMetric::TYPE, $metric->getType()); $this->assertEquals(10, $metric->getValue()); $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); } @@ -67,7 +67,7 @@ public function testDistributionMetrics(): void $metrics = $event->getMetrics(); $metric = $metrics[0]; $this->assertEquals('test-distribution', $metric->getName()); - $this->assertEquals(DistributionType::TYPE, $metric->getType()); + $this->assertEquals(DistributionMetric::TYPE, $metric->getType()); $this->assertEquals(10, $metric->getValue()); $this->assertArrayHasKey('foo', $metric->getAttributes()->toSimpleArray()); } @@ -99,7 +99,7 @@ public function testEnableMetrics(): void public function testBeforeSendMetricAltersContent() { HubAdapter::getInstance()->bindClient(new Client(new Options([ - 'before_send_metric' => static function (AbstractType $metric) { + 'before_send_metric' => static function (Metric $metric) { $metric->setValue(99999); return $metric; diff --git a/tests/Serializer/PayloadSerializerTest.php b/tests/Serializer/PayloadSerializerTest.php index c4287cd67..3d3cc4c75 100644 --- a/tests/Serializer/PayloadSerializerTest.php +++ b/tests/Serializer/PayloadSerializerTest.php @@ -18,10 +18,9 @@ use Sentry\Frame; use Sentry\Logs\Log; use Sentry\Logs\LogLevel; -use Sentry\Metrics\Types\CounterType; -use Sentry\Metrics\Types\DistributionType; -use Sentry\Metrics\Types\GaugeType; -use Sentry\Metrics\Unit; +use Sentry\Metrics\Types\CounterMetric; +use Sentry\Metrics\Types\DistributionMetric; +use Sentry\Metrics\Types\GaugeMetric; use Sentry\MonitorConfig; use Sentry\MonitorSchedule; use Sentry\Options; @@ -35,6 +34,7 @@ use Sentry\Tracing\SpanStatus; use Sentry\Tracing\TraceId; use Sentry\Tracing\TransactionMetadata; +use Sentry\Unit; use Sentry\UserDataBag; use Sentry\Util\ClockMock; use Sentry\Util\SentryUid; @@ -69,7 +69,7 @@ public static function serializeAsEnvelopeDataProvider(): iterable yield [ Event::createEvent(new EventId('fc9442f5aef34234bb22b9a615e30ccd')), <<\/","server_name":"foo.example.com","release":"721e41770371db95eee98ca2707686226b993eda","environment":"production","fingerprint":["myrpc","POST","\/foo.bar"],"modules":{"my.module.name":"1.0"},"extra":{"my_key":1,"some_other_value":"foo bar"},"tags":{"ios_version":"4.0","context":"production"},"user":{"id":"unique_id","username":"my_user","email":"foo@example.com","ip_address":"127.0.0.1","segment":"my_segment"},"contexts":{"os":{"name":"Linux","version":"4.19.104-microsoft-standard","build":"#1 SMP Wed Feb 19 06:37:35 UTC 2020","kernel_version":"Linux 7944782cd697 4.19.104-microsoft-standard #1 SMP Wed Feb 19 06:37:35 UTC 2020 x86_64"},"runtime":{"name":"php","sapi":"cli","version":"7.4.3"},"electron":{"type":"runtime","name":"Electron","version":"4.0"}},"breadcrumbs":{"values":[{"type":"user","category":"log","level":"info","timestamp":1597790835},{"type":"navigation","category":"log","level":"info","timestamp":1597790835,"data":{"from":"\/login","to":"\/dashboard"}},{"type":"default","category":"log","level":"info","timestamp":1597790835,"data":{"0":"foo","1":"bar"}}]},"request":{"method":"POST","url":"http:\/\/absolute.uri\/foo","query_string":"query=foobar&page=2","data":{"foo":"bar"},"cookies":{"PHPSESSID":"298zf09hf012fh2"},"headers":{"content-type":"text\/html"},"env":{"REMOTE_ADDR":"127.0.0.1"}},"exception":{"values":[{"type":"Exception","value":"chained exception","stacktrace":{"frames":[{"filename":"file\/name.py","lineno":3,"in_app":true},{"filename":"file\/name.py","lineno":3,"in_app":false,"abs_path":"absolute\/file\/name.py","function":"myfunction","raw_function":"raw_function_name","pre_context":["def foo():"," my_var = 'foo'"],"context_line":" raise ValueError()","post_context":["","def main():"],"vars":{"my_var":"value"}}]},"mechanism":{"type":"generic","handled":true,"data":{"code":123}}},{"type":"Exception","value":"initial exception"}]}} TEXT @@ -187,7 +187,7 @@ public static function serializeAsEnvelopeDataProvider(): iterable yield [ $event, <<setMetrics([ - new CounterType('test-counter', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], 1597790835.0, Unit::bit()), + new CounterMetric('test-counter', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], 1597790835.0, Unit::bit()), ]); yield [ @@ -447,7 +447,7 @@ public static function serializeAsEnvelopeDataProvider(): iterable $event = Event::createMetrics(new EventId('fc9442f5aef34234bb22b9a615e30ccd')); $event->setMetrics([ - new GaugeType('test-gauge', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], ClockMock::microtime(true), Unit::second()), + new GaugeMetric('test-gauge', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], ClockMock::microtime(true), Unit::second()), ]); yield [ @@ -461,7 +461,7 @@ public static function serializeAsEnvelopeDataProvider(): iterable $event = Event::createMetrics(new EventId('fc9442f5aef34234bb22b9a615e30ccd')); $event->setMetrics([ - new DistributionType('test-distribution', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], ClockMock::microtime(true), Unit::day()), + new DistributionMetric('test-distribution', 5, new TraceId('21160e9b836d479f81611368b2aa3d2c'), new SpanId('d051f34163cd45fb'), ['foo' => 'bar'], ClockMock::microtime(true), Unit::day()), ]); yield [ From 4ada6226b18eec087a4d934f9a2e5f38c97bae1b Mon Sep 17 00:00:00 2001 From: Martin Linzmayer Date: Thu, 27 Nov 2025 15:04:23 +0100 Subject: [PATCH 17/17] CS + lint --- src/Metrics/Metrics.php | 2 +- src/Metrics/MetricsAggregator.php | 1 + src/Metrics/Types/DistributionMetric.php | 2 +- src/Tracing/Span.php | 2 +- tests/Metrics/TraceMetricsTest.php | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Metrics/Metrics.php b/src/Metrics/Metrics.php index 21fc15607..936538e19 100644 --- a/src/Metrics/Metrics.php +++ b/src/Metrics/Metrics.php @@ -6,8 +6,8 @@ use Sentry\EventId; use Sentry\Tracing\SpanContext; - use Sentry\Unit; + use function Sentry\trace; class_alias(Unit::class, '\Sentry\Metrics\MetricsUnit'); diff --git a/src/Metrics/MetricsAggregator.php b/src/Metrics/MetricsAggregator.php index ce81f59e8..fa0dfd5be 100644 --- a/src/Metrics/MetricsAggregator.php +++ b/src/Metrics/MetricsAggregator.php @@ -13,6 +13,7 @@ use Sentry\Metrics\Types\Metric; use Sentry\SentrySdk; use Sentry\State\Scope; +use Sentry\Unit; use Sentry\Util\RingBuffer; /** diff --git a/src/Metrics/Types/DistributionMetric.php b/src/Metrics/Types/DistributionMetric.php index 14e39c01d..bfbc85ce9 100644 --- a/src/Metrics/Types/DistributionMetric.php +++ b/src/Metrics/Types/DistributionMetric.php @@ -4,9 +4,9 @@ namespace Sentry\Metrics\Types; -use Sentry\Unit; use Sentry\Tracing\SpanId; use Sentry\Tracing\TraceId; +use Sentry\Unit; /** * @internal diff --git a/src/Tracing/Span.php b/src/Tracing/Span.php index cbec6b15a..09fe62a20 100644 --- a/src/Tracing/Span.php +++ b/src/Tracing/Span.php @@ -5,9 +5,9 @@ namespace Sentry\Tracing; use Sentry\EventId; -use Sentry\Unit; use Sentry\SentrySdk; use Sentry\State\Scope; +use Sentry\Unit; /** * This class stores all the information about a span. diff --git a/tests/Metrics/TraceMetricsTest.php b/tests/Metrics/TraceMetricsTest.php index 13fea3081..39ebf0705 100644 --- a/tests/Metrics/TraceMetricsTest.php +++ b/tests/Metrics/TraceMetricsTest.php @@ -7,10 +7,10 @@ use PHPUnit\Framework\TestCase; use Sentry\Client; use Sentry\Metrics\MetricsAggregator; -use Sentry\Metrics\Types\Metric; use Sentry\Metrics\Types\CounterMetric; use Sentry\Metrics\Types\DistributionMetric; use Sentry\Metrics\Types\GaugeMetric; +use Sentry\Metrics\Types\Metric; use Sentry\Options; use Sentry\State\HubAdapter;