diff --git a/src/Metrics/MetricsAggregator.php b/src/Metrics/MetricsAggregator.php index edd448772..5014c97fe 100644 --- a/src/Metrics/MetricsAggregator.php +++ b/src/Metrics/MetricsAggregator.php @@ -64,7 +64,7 @@ public function add( $type . $key . $unit . - implode('', $tags) . + serialize($tags) . $bucketTimestamp ); diff --git a/src/Serializer/EnvelopItems/TransactionItem.php b/src/Serializer/EnvelopItems/TransactionItem.php index 5296299be..acb0272c4 100644 --- a/src/Serializer/EnvelopItems/TransactionItem.php +++ b/src/Serializer/EnvelopItems/TransactionItem.php @@ -177,7 +177,16 @@ protected static function serializeSpan(Span $span): array } if (!empty($span->getMetricsSummary())) { - $result['metrics_summary'] = $span->getMetricsSummary(); + $formattedSummary = []; + $summary = $span->getMetricsSummary(); + + foreach ($summary as $mri => $metrics) { + foreach ($metrics as $metric) { + $formattedSummary[$mri][] = $metric; + } + } + + $result['_metrics_summary'] = $formattedSummary; } return $result; diff --git a/src/Tracing/Span.php b/src/Tracing/Span.php index f743d0aa9..c2c0f79ab 100644 --- a/src/Tracing/Span.php +++ b/src/Tracing/Span.php @@ -89,7 +89,7 @@ class Span protected $transaction; /** - * @var array + * @var array> */ protected $metricsSummary = []; @@ -492,7 +492,7 @@ public function detachSpanRecorder() } /** - * @return array + * @return array> */ public function getMetricsSummary(): array { @@ -511,17 +511,20 @@ public function setMetricsSummary( array $tags ): void { $mri = sprintf('%s:%s@%s', $type, $key, (string) $unit); - $bucketKey = $mri . implode('', $tags); + $bucketKey = $mri . serialize($tags); - if (\array_key_exists($bucketKey, $this->metricsSummary)) { + if ( + isset($this->metricsSummary[$mri]) + && \array_key_exists($bucketKey, $this->metricsSummary[$mri]) + ) { if ($type === SetType::TYPE) { $value = 1.0; } else { $value = (float) $value; } - $summary = $this->metricsSummary[$bucketKey]; - $this->metricsSummary[$bucketKey] = [ + $summary = $this->metricsSummary[$mri][$bucketKey]; + $this->metricsSummary[$mri][$bucketKey] = [ 'min' => min($summary['min'], $value), 'max' => max($summary['max'], $value), 'sum' => $summary['sum'] + $value, @@ -535,7 +538,7 @@ public function setMetricsSummary( $value = (float) $value; } - $this->metricsSummary[$bucketKey] = [ + $this->metricsSummary[$mri][$bucketKey] = [ 'min' => $value, 'max' => $value, 'sum' => $value, diff --git a/tests/Metrics/MetricsTest.php b/tests/Metrics/MetricsTest.php index 354030f1f..8dc7388a8 100644 --- a/tests/Metrics/MetricsTest.php +++ b/tests/Metrics/MetricsTest.php @@ -40,7 +40,7 @@ public function testIncrement(): void $client->expects($this->once()) ->method('captureEvent') ->with($this->callback(static function (Event $event) use ($self): bool { - $metric = $event->getMetrics()['92ed00fdaf9543ff4cace691f8a5166b']; + $metric = $event->getMetrics()['2794a118fd879e10a3a97836df803872']; $self->assertSame(CounterType::TYPE, $metric->getType()); $self->assertSame('foo', $metric->getKey()); @@ -102,7 +102,7 @@ public function testDistribution(): void $client->expects($this->once()) ->method('captureEvent') ->with($this->callback(static function (Event $event) use ($self): bool { - $metric = $event->getMetrics()['8a817dcdb12cfffc1fa8b459ad0c9d56']; + $metric = $event->getMetrics()['edb74f95b4572e82dc4600cfeea76181']; $self->assertSame(DistributionType::TYPE, $metric->getType()); $self->assertSame('foo', $metric->getKey()); @@ -162,30 +162,30 @@ public function testTiming(): void $self = $this; $client->expects($this->once()) - ->method('captureEvent') - ->with($this->callback(static function (Event $event) use ($self): bool { - $metric = $event->getMetrics()['8a817dcdb12cfffc1fa8b459ad0c9d56']; - - $self->assertSame(DistributionType::TYPE, $metric->getType()); - $self->assertSame('foo', $metric->getKey()); - $self->assertSame([1.0, 2.0], $metric->serialize()); - $self->assertSame(MetricsUnit::second(), $metric->getUnit()); - $self->assertSame( - [ - 'environment' => 'development', - 'foo' => 'bar', - 'release' => '1.0.0', - ], - $metric->getTags() - ); - $self->assertSame(1699412953, $metric->getTimestamp()); - - $codeLocation = $metric->getCodeLocation(); - - $self->assertSame('Sentry\Metrics\Metrics::timing', $codeLocation->getFunctionName()); - - return true; - })); + ->method('captureEvent') + ->with($this->callback(static function (Event $event) use ($self): bool { + $metric = $event->getMetrics()['edb74f95b4572e82dc4600cfeea76181']; + + $self->assertSame(DistributionType::TYPE, $metric->getType()); + $self->assertSame('foo', $metric->getKey()); + $self->assertSame([1.0, 2.0], $metric->serialize()); + $self->assertSame(MetricsUnit::second(), $metric->getUnit()); + $self->assertSame( + [ + 'environment' => 'development', + 'foo' => 'bar', + 'release' => '1.0.0', + ], + $metric->getTags() + ); + $self->assertSame(1699412953, $metric->getTimestamp()); + + $codeLocation = $metric->getCodeLocation(); + + $self->assertSame('Sentry\Metrics\Metrics::timing', $codeLocation->getFunctionName()); + + return true; + })); $hub = new Hub($client); SentrySdk::setCurrentHub($hub); @@ -238,7 +238,7 @@ public function testGauge(): void $client->expects($this->once()) ->method('captureEvent') ->with($this->callback(static function (Event $event) use ($self): bool { - $metric = $event->getMetrics()['d2a09273b9c61b66a0e6ee79c1babfed']; + $metric = $event->getMetrics()['f39c23c73897d4f006fd617f76664571']; $self->assertSame(GaugeType::TYPE, $metric->getType()); $self->assertSame('foo', $metric->getKey()); @@ -306,7 +306,7 @@ public function testSet(): void $client->expects($this->once()) ->method('captureEvent') ->with($this->callback(static function (Event $event) use ($self): bool { - $metric = $event->getMetrics()['c900a5750d0bc79016c29a7f0bdcd937']; + $metric = $event->getMetrics()['868b190d923bbd619570328d7ba3e4cd']; $self->assertSame(SetType::TYPE, $metric->getType()); $self->assertSame('foo', $metric->getKey()); diff --git a/tests/Serializer/PayloadSerializerTest.php b/tests/Serializer/PayloadSerializerTest.php index 19e00acc8..2b7f775ba 100644 --- a/tests/Serializer/PayloadSerializerTest.php +++ b/tests/Serializer/PayloadSerializerTest.php @@ -319,7 +319,6 @@ public static function serializeAsEnvelopeDataProvider(): iterable {"timestamp":1597790835,"platform":"php","sdk":{"name":"sentry.php","version":"$sdkVersion"},"spans":[],"transaction_info":{"source":"custom"}} TEXT , - false, ]; $event = Event::createEvent(new EventId('fc9442f5aef34234bb22b9a615e30ccd')); @@ -411,7 +410,6 @@ public static function serializeAsEnvelopeDataProvider(): iterable {"check_in_id":"$checkinId","monitor_slug":"my-monitor","status":"ok","duration":10,"release":"1.0.0","environment":"dev","monitor_config":{"schedule":{"type":"crontab","value":"0 0 * * *","unit":""},"checkin_margin":10,"max_runtime":12,"timezone":"Europe\/Amsterdam","failure_issue_threshold":5,"recovery_threshold":10},"contexts":{"trace":{"trace_id":"21160e9b836d479f81611368b2aa3d2c","span_id":"5dd538dc297544cc"}}} TEXT , - false, ]; $counter = new CounterType('counter', 1.0, MetricsUnit::second(), ['foo' => 'bar', 'baz' => 'qux'], 1597790835); @@ -441,7 +439,46 @@ public static function serializeAsEnvelopeDataProvider(): iterable no_tags@second:1|c|T1597790835 TEXT , - false, + ]; + + $span = new Span(); + $span->setSpanId(new SpanId('5dd538dc297544cc')); + $span->setTraceId(new TraceId('21160e9b836d479f81611368b2aa3d2c')); + $span->setMetricsSummary( + CounterType::TYPE, + 'counter', + 10, + MetricsUnit::custom('star'), + [ + 'repository' => 'client', + ] + ); + $span->setMetricsSummary( + CounterType::TYPE, + 'counter', + 50, + MetricsUnit::custom('star'), + [ + 'repository' => 'client', + ] + ); + + $event = Event::createTransaction(new EventId('fc9442f5aef34234bb22b9a615e30ccd')); + $event->setSpans([$span]); + $event->setTransaction('GET /'); + $event->setContext('trace', [ + 'trace_id' => '21160e9b836d479f81611368b2aa3d2c', + 'span_id' => '5dd538dc297544cc', + ]); + + yield [ + $event, + <<setMetricsSummary( + CounterType::TYPE, + 'counter', + 10, + MetricsUnit::custom('star'), + [ + 'repository' => 'client', + ] + ); + $span->setMetricsSummary( + CounterType::TYPE, + 'counter', + 50, + MetricsUnit::custom('star'), + [ + 'repository' => 'client', + ] + ); + $span->setMetricsSummary( + CounterType::TYPE, + 'counter', + 10, + MetricsUnit::custom('star'), + [ + 'repository' => 'server', + ] + ); + + $span->setMetricsSummary( + DistributionType::TYPE, + 'distribution', + 10.2, + MetricsUnit::millisecond(), + [] + ); + $span->setMetricsSummary( + DistributionType::TYPE, + 'distribution', + 5.7, + MetricsUnit::millisecond(), + [] + ); + + $span->setMetricsSummary( + GaugeType::TYPE, + 'gauge', + 10, + MetricsUnit::none(), + [] + ); + $span->setMetricsSummary( + GaugeType::TYPE, + 'gauge', + 20, + MetricsUnit::none(), + [] + ); + + $span->setMetricsSummary( + SetType::TYPE, + 'set', + 'jane@doe@example.com', + MetricsUnit::custom('user'), + [] + ); + $span->setMetricsSummary( + SetType::TYPE, + 'set', + 'jon@doe@example.com', + MetricsUnit::custom('user'), + [] + ); + + $this->assertSame([ + 'c:counter@star' => [ + 'c:counter@stara:1:{s:10:"repository";s:6:"client";}' => [ + 'min' => 10.0, + 'max' => 50.0, + 'sum' => 60.0, + 'count' => 2, + 'tags' => [ + 'repository' => 'client', + ], + ], + 'c:counter@stara:1:{s:10:"repository";s:6:"server";}' => [ + 'min' => 10.0, + 'max' => 10.0, + 'sum' => 10.0, + 'count' => 1, + 'tags' => [ + 'repository' => 'server', + ], + ], + ], + 'd:distribution@millisecond' => [ + 'd:distribution@milliseconda:0:{}' => [ + 'min' => 5.7, + 'max' => 10.2, + 'sum' => 15.899999999999999, + 'count' => 2, + 'tags' => [], + ], + ], + 'g:gauge@none' => [ + 'g:gauge@nonea:0:{}' => [ + 'min' => 10.0, + 'max' => 20.0, + 'sum' => 30.0, + 'count' => 2, + 'tags' => [], + ], + ], + 's:set@user' => [ + 's:set@usera:0:{}' => [ + 'min' => 0.0, + 'max' => 1.0, + 'sum' => 1.0, + 'count' => 2, + 'tags' => [], + ], + ], + ], $span->getMetricsSummary()); + } }