diff --git a/src/Logs/LogsAggregator.php b/src/Logs/LogsAggregator.php index 0fa66b7fc..99c0370c9 100644 --- a/src/Logs/LogsAggregator.php +++ b/src/Logs/LogsAggregator.php @@ -6,6 +6,7 @@ use Sentry\Attributes\Attribute; use Sentry\Client; +use Sentry\ClientInterface; use Sentry\Event; use Sentry\EventId; use Sentry\SentrySdk; @@ -159,20 +160,22 @@ public function add( $logs->push($log); if ($logFlushThreshold !== null && \count($logs) >= $logFlushThreshold) { - $this->flush($hub); + $this->flush($client); } } - public function flush(?HubInterface $hub = null): ?EventId + public function flush(?ClientInterface $client = null): ?EventId { - if ($this->logs === null || $this->logs->isEmpty()) { + $logs = $this->logs; + + if ($logs === null || $logs->isEmpty()) { return null; } - $hub = $hub ?? SentrySdk::getCurrentHub(); - $event = Event::createLogs()->setLogs($this->logs->drain()); + $client = $client ?? SentrySdk::getCurrentHub()->getClient(); + $event = Event::createLogs()->setLogs($logs->drain()); - return $hub->captureEvent($event); + return $client->captureEvent($event); } /** diff --git a/src/Metrics/MetricsAggregator.php b/src/Metrics/MetricsAggregator.php index a4a3aef3e..7fdae2394 100644 --- a/src/Metrics/MetricsAggregator.php +++ b/src/Metrics/MetricsAggregator.php @@ -5,6 +5,7 @@ namespace Sentry\Metrics; use Sentry\Client; +use Sentry\ClientInterface; use Sentry\Event; use Sentry\EventId; use Sentry\Metrics\Types\CounterMetric; @@ -124,20 +125,22 @@ public function add( $metrics->push($metric); if ($metricFlushThreshold !== null && \count($metrics) >= $metricFlushThreshold) { - $this->flush($hub); + $this->flush($client); } } - public function flush(?HubInterface $hub = null): ?EventId + public function flush(?ClientInterface $client = null): ?EventId { - if ($this->metrics === null || $this->metrics->isEmpty()) { + $metrics = $this->metrics; + + if ($metrics === null || $metrics->isEmpty()) { return null; } - $hub = $hub ?? SentrySdk::getCurrentHub(); - $event = Event::createMetrics()->setMetrics($this->metrics->drain()); + $client = $client ?? SentrySdk::getCurrentHub()->getClient(); + $event = Event::createMetrics()->setMetrics($metrics->drain()); - return $hub->captureEvent($event); + return $client->captureEvent($event); } /** diff --git a/src/State/RuntimeContextManager.php b/src/State/RuntimeContextManager.php index cec72ee48..db1a80a2e 100644 --- a/src/State/RuntimeContextManager.php +++ b/src/State/RuntimeContextManager.php @@ -161,12 +161,12 @@ private function removeContextById(string $runtimeContextId, ?int $timeout = nul private function flushRuntimeContextResources(RuntimeContext $runtimeContext, ?int $timeout, LoggerInterface $logger): void { - $hub = $runtimeContext->getHub(); + $client = $runtimeContext->getHub()->getClient(); // captureEvent can throw before transport send (for example from scope event processors // or before_send callbacks), so we isolate failures and continue flushing other resources. try { - $runtimeContext->getLogsAggregator()->flush($hub); + $runtimeContext->getLogsAggregator()->flush($client); } catch (\Throwable $exception) { $logger->error('Failed to flush logs while ending a runtime context.', [ 'exception' => $exception, @@ -176,7 +176,7 @@ private function flushRuntimeContextResources(RuntimeContext $runtimeContext, ?i // Keep metrics flush independent from logs flush so one bad callback does not block the rest. try { - $runtimeContext->getMetricsAggregator()->flush($hub); + $runtimeContext->getMetricsAggregator()->flush($client); } catch (\Throwable $exception) { $logger->error('Failed to flush trace metrics while ending a runtime context.', [ 'exception' => $exception, @@ -184,8 +184,6 @@ private function flushRuntimeContextResources(RuntimeContext $runtimeContext, ?i ]); } - $client = $hub->getClient(); - // Custom transports may throw from close(); endContext must stay best-effort and non-fatal. try { $client->flush($timeout); diff --git a/tests/Logs/LogsAggregatorTest.php b/tests/Logs/LogsAggregatorTest.php index 5278f5039..97320a6d1 100644 --- a/tests/Logs/LogsAggregatorTest.php +++ b/tests/Logs/LogsAggregatorTest.php @@ -7,8 +7,11 @@ use PHPUnit\Framework\TestCase; use Sentry\Client; use Sentry\ClientBuilder; +use Sentry\ClientInterface; +use Sentry\Event; use Sentry\Logs\LogLevel; use Sentry\Logs\LogsAggregator; +use Sentry\Options; use Sentry\SentrySdk; use Sentry\State\Hub; use Sentry\State\Scope; @@ -271,6 +274,39 @@ public function testFlushesImmediatelyWhenThresholdIsReached(): void $this->assertSame('Second message', StubTransport::$events[0]->getLogs()[1]->getBody()); } + public function testFlushCapturesLogsWithProvidedClient(): void + { + $client = $this->createMock(ClientInterface::class); + $client->method('getOptions') + ->willReturn(new Options([ + 'enable_logs' => true, + ])); + + $fallbackClient = $this->createMock(ClientInterface::class); + $fallbackClient->method('getOptions') + ->willReturn(new Options([ + 'enable_logs' => true, + ])); + $fallbackClient->expects($this->never()) + ->method('captureEvent'); + SentrySdk::setCurrentHub(new Hub($fallbackClient)); + + $aggregator = new LogsAggregator(); + $aggregator->add(LogLevel::info(), 'Test message'); + + $client->expects($this->once()) + ->method('captureEvent') + ->with( + $this->callback(function (Event $event): bool { + $this->assertCount(1, $event->getLogs()); + + return true; + }) + ); + + $aggregator->flush($client); + } + public function testDoesNotFlushImmediatelyWhenThresholdIsNull(): void { StubTransport::$events = []; diff --git a/tests/Metrics/TraceMetricsTest.php b/tests/Metrics/TraceMetricsTest.php index 1191e076e..bb5773699 100644 --- a/tests/Metrics/TraceMetricsTest.php +++ b/tests/Metrics/TraceMetricsTest.php @@ -6,12 +6,16 @@ use PHPUnit\Framework\TestCase; use Sentry\Client; +use Sentry\ClientInterface; +use Sentry\Event; use Sentry\Metrics\MetricsAggregator; 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\SentrySdk; +use Sentry\State\Hub; use Sentry\State\HubAdapter; use Sentry\State\Scope; @@ -110,6 +114,39 @@ public function testDoesNotFlushImmediatelyWhenMetricFlushThresholdIsNull(): voi $this->assertCount(2, StubTransport::$events[0]->getMetrics()); } + public function testFlushCapturesMetricsWithProvidedClient(): void + { + $client = $this->createMock(ClientInterface::class); + $client->method('getOptions') + ->willReturn(new Options([ + 'enable_metrics' => true, + ])); + + $fallbackClient = $this->createMock(ClientInterface::class); + $fallbackClient->method('getOptions') + ->willReturn(new Options([ + 'enable_metrics' => true, + ])); + $fallbackClient->expects($this->never()) + ->method('captureEvent'); + SentrySdk::setCurrentHub(new Hub($fallbackClient)); + + $aggregator = new MetricsAggregator(); + $aggregator->add(CounterMetric::TYPE, 'test-count', 2, ['foo' => 'bar'], null); + + $client->expects($this->once()) + ->method('captureEvent') + ->with( + $this->callback(function (Event $event): bool { + $this->assertCount(1, $event->getMetrics()); + + return true; + }) + ); + + $aggregator->flush($client); + } + public function testMetricsBufferFullWhenMetricFlushThresholdIsNull(): void { HubAdapter::getInstance()->bindClient(new Client(new Options([