diff --git a/composer.json b/composer.json index 60ef978..a80b561 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ }, "require-dev": { "cakephp/cakephp-codesniffer": "^5.0", - "phpunit/phpunit": "^10.5" + "phpunit/phpunit": "^10.5.5" }, "license": "MIT", "autoload": { diff --git a/src/Event/HttpEventListener.php b/src/Event/HttpEventListener.php new file mode 100644 index 0000000..b80ce52 --- /dev/null +++ b/src/Event/HttpEventListener.php @@ -0,0 +1,76 @@ + 'handleBeforeSend', + 'HttpClient.afterSend' => 'handleAfterSend', + ]; + } + + /** + * @param \Cake\Http\Client\ClientEvent $event + * @return void + */ + public function handlebeforeSend(ClientEvent $event): void + { + /** @var \Cake\Http\Client\Request $request */ + $request = $event->getRequest(); + $parentSpan = SentrySdk::getCurrentHub()->getSpan(); + + if ($parentSpan !== null) { + $span = SpanContext::make() + ->setOp('http.client'); + + $uri = $request->getUri(); + $fullUrl = sprintf('%s://%s%s/', $uri->getScheme(), $uri->getHost(), $uri->getPath()); + $span + ->setDescription(sprintf('%s %s', $request->getMethod(), $fullUrl)) + ->setData([ + 'url' => $fullUrl, + 'http.query' => $uri->getQuery(), + 'http.fragment' => $uri->getFragment(), + 'http.request.method' => $request->getMethod(), + 'http.request.body.size' => $request->getBody()->getSize(), + ]); + + $this->pushSpan($parentSpan->startChild($span)); + } + } + + /** + * @param \Cake\Http\Client\ClientEvent $event + * @return void + */ + public function handleAfterSend(ClientEvent $event): void + { + $response = $event->getResult(); + $span = $this->popSpan(); + + if ($span !== null) { + $span + ->setHttpStatus($response?->getStatusCode() ?? 0) + ->setData([ + 'http.response.body.size' => $response?->getBody()?->getSize(), + 'http.response.status_code' => $response?->getStatusCode() ?? 0, + ]) + ->finish(); + } + } +} diff --git a/src/Middleware/CakeSentryPerformanceMiddleware.php b/src/Middleware/CakeSentryPerformanceMiddleware.php index e2437d5..ce80fec 100644 --- a/src/Middleware/CakeSentryPerformanceMiddleware.php +++ b/src/Middleware/CakeSentryPerformanceMiddleware.php @@ -17,6 +17,7 @@ use Cake\Event\EventManager; use Cake\Http\Server; use CakeSentry\Database\Log\CakeSentryLog; +use CakeSentry\Event\HttpEventListener; use CakeSentry\EventListener; use CakeSentry\QuerySpanTrait; use Psr\Http\Message\ResponseInterface; @@ -77,6 +78,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $this->addQueryData(); $listener = new EventListener(); EventManager::instance()->on($listener); + EventManager::instance()->on(new HttpEventListener()); $response = $handler->handle($request); diff --git a/src/QuerySpanTrait.php b/src/QuerySpanTrait.php index 26963eb..80f5687 100644 --- a/src/QuerySpanTrait.php +++ b/src/QuerySpanTrait.php @@ -10,21 +10,12 @@ use Cake\Database\Schema\SqlserverSchemaDialect; use Cake\Datasource\ConnectionManager; use Sentry\SentrySdk; -use Sentry\Tracing\Span; use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; trait QuerySpanTrait { - /** - * @var array - */ - protected array $parentSpanStack = []; - - /** - * @var array - */ - protected array $currentSpanStack = []; + use SpanStackTrait; /** * @param \Cake\Database\Log\LoggedQuery $query @@ -81,30 +72,4 @@ public function addTransactionSpan(LoggedQuery $query, ?string $connectionName = $spanContext->setEndTimestamp($spanContext->getStartTimestamp() + $context['took'] / 1000); $parentSpan->startChild($spanContext); } - - /** - * @param \Sentry\Tracing\Span $span The span. - * @return void - */ - protected function pushSpan(Span $span): void - { - $this->parentSpanStack[] = SentrySdk::getCurrentHub()->getSpan(); - SentrySdk::getCurrentHub()->setSpan($span); - $this->currentSpanStack[] = $span; - } - - /** - * @return \Sentry\Tracing\Span|null - */ - protected function popSpan(): ?Span - { - if (count($this->currentSpanStack) === 0) { - return null; - } - - $parent = array_pop($this->parentSpanStack); - SentrySdk::getCurrentHub()->setSpan($parent); - - return array_pop($this->currentSpanStack); - } } diff --git a/src/SpanStackTrait.php b/src/SpanStackTrait.php new file mode 100644 index 0000000..f6b1bc7 --- /dev/null +++ b/src/SpanStackTrait.php @@ -0,0 +1,46 @@ +parentSpanStack[] = SentrySdk::getCurrentHub()->getSpan(); + SentrySdk::getCurrentHub()->setSpan($span); + $this->currentSpanStack[] = $span; + } + + /** + * @return \Sentry\Tracing\Span|null + */ + protected function popSpan(): ?Span + { + if (count($this->currentSpanStack) === 0) { + return null; + } + + $parent = array_pop($this->parentSpanStack); + SentrySdk::getCurrentHub()->setSpan($parent); + + return array_pop($this->currentSpanStack); + } +}