raven-8.x-2.x-dev/src/Http/HttpClientMiddleware.php
src/Http/HttpClientMiddleware.php
<?php namespace Drupal\raven\Http; use Drupal\raven\EventSubscriber\RequestSubscriber; use GuzzleHttp\Exception\RequestException; use GuzzleHttp\Promise\Create; use GuzzleHttp\Psr7\Uri; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Sentry\Breadcrumb; use Sentry\SentrySdk; use Sentry\Tracing\SpanContext; use Sentry\Tracing\SpanStatus; /** * Instrument Guzzle HTTP requests. */ class HttpClientMiddleware { /** * {@inheritdoc} */ public function __construct(protected ?RequestSubscriber $requestSubscriber = NULL) { } /** * {@inheritdoc} */ public function __invoke(): callable { return function ($handler) { return function (RequestInterface $request, array $options) use ($handler) { // Build URI without username/password. $partialUri = Uri::fromParts([ 'scheme' => $request->getUri()->getScheme(), 'host' => $request->getUri()->getHost(), 'port' => $request->getUri()->getPort(), 'path' => $request->getUri()->getPath(), ]); $hub = SentrySdk::getCurrentHub(); $span = NULL; $parent = $hub->getSpan(); if ($parent && $parent->getSampled()) { $context = SpanContext::make() ->setOrigin('auto.http.client') ->setOp('http.client') ->setDescription($request->getMethod() . ' ' . (string) $partialUri) ->setData([ 'http.url' => (string) $partialUri, 'http.request.method' => $request->getMethod(), 'http.query' => $request->getUri()->getQuery(), 'http.fragment' => $request->getUri()->getFragment(), ]); $span = $parent->startChild($context); $hub->setSpan($span); } if ($client = $hub->getClient()) { $targets = $client->getOptions()->getTracePropagationTargets(); if ($targets === NULL || in_array($request->getUri()->getHost(), $targets)) { $request = $request ->withHeader('sentry-trace', \Sentry\getTraceparent()) ->withHeader('traceparent', \Sentry\getW3CTraceparent()); } if ($targets !== NULL && in_array($request->getUri()->getHost(), $targets) && $this->requestSubscriber) { $this->requestSubscriber->sanitizeBaggage(); $request = $request->withHeader('baggage', \Sentry\getBaggage()); } } $handlerPromiseCallback = static function ($responseOrException) use ($hub, $request, $span, $parent, $partialUri) { if ($span) { $span->finish(); $hub->setSpan($parent); } $response = NULL; if ($responseOrException instanceof ResponseInterface) { $response = $responseOrException; } elseif ($responseOrException instanceof RequestException) { $response = $responseOrException->getResponse(); } $breadcrumbData = [ 'http.url' => (string) $partialUri, 'http.request.method' => $request->getMethod(), 'http.request.body.size' => $request->getBody()->getSize(), ]; if ('' !== $request->getUri()->getQuery()) { $breadcrumbData['http.query'] = $request->getUri()->getQuery(); } if ('' !== $request->getUri()->getFragment()) { $breadcrumbData['http.fragment'] = $request->getUri()->getFragment(); } if ($response) { if ($span) { $span->setStatus(SpanStatus::createFromHttpStatusCode($response->getStatusCode())); } $breadcrumbData['http.response.status_code'] = $response->getStatusCode(); $breadcrumbData['http.response.body.size'] = $response->getBody()->getSize(); } elseif ($span) { $span->setStatus(SpanStatus::internalError()); } $hub->addBreadcrumb(new Breadcrumb(Breadcrumb::LEVEL_INFO, Breadcrumb::TYPE_HTTP, 'http', NULL, $breadcrumbData)); if ($responseOrException instanceof \Throwable) { return Create::rejectionFor($responseOrException); } return $responseOrException; }; return $handler($request, $options)->then($handlerPromiseCallback, $handlerPromiseCallback); }; }; } }