diff --git a/src/Sentry/Laravel/Tracing/Routing/TracingCallableDispatcherTracing.php b/src/Sentry/Laravel/Tracing/Routing/TracingCallableDispatcherTracing.php new file mode 100644 index 00000000..7ccb1062 --- /dev/null +++ b/src/Sentry/Laravel/Tracing/Routing/TracingCallableDispatcherTracing.php @@ -0,0 +1,24 @@ +dispatcher = $dispatcher; + } + + public function dispatch(Route $route, $callable) + { + return $this->wrapRouteDispatch(function () use ($route, $callable) { + return $this->dispatcher->dispatch($route, $callable); + }, $route); + } +} diff --git a/src/Sentry/Laravel/Tracing/Routing/TracingControllerDispatcherTracing.php b/src/Sentry/Laravel/Tracing/Routing/TracingControllerDispatcherTracing.php new file mode 100644 index 00000000..1cedda2c --- /dev/null +++ b/src/Sentry/Laravel/Tracing/Routing/TracingControllerDispatcherTracing.php @@ -0,0 +1,29 @@ +dispatcher = $dispatcher; + } + + public function dispatch(Route $route, $controller, $method) + { + return $this->wrapRouteDispatch(function () use ($route, $controller, $method) { + return $this->dispatcher->dispatch($route, $controller, $method); + }, $route); + } + + public function getMiddleware($controller, $method) + { + return $this->dispatcher->getMiddleware($controller, $method); + } +} diff --git a/src/Sentry/Laravel/Tracing/Routing/TracingRoutingDispatcher.php b/src/Sentry/Laravel/Tracing/Routing/TracingRoutingDispatcher.php new file mode 100644 index 00000000..98212973 --- /dev/null +++ b/src/Sentry/Laravel/Tracing/Routing/TracingRoutingDispatcher.php @@ -0,0 +1,36 @@ +getSpan(); + + // When there is no active transaction we can skip doing anything and just immediately return the callable + if ($parentSpan === null) { + return $dispatch(); + } + + $context = new SpanContext; + $context->setOp('http.route'); + $context->setDescription($route->getActionName()); + + $span = $parentSpan->startChild($context); + + SentrySdk::getCurrentHub()->setSpan($span); + + try { + return $dispatch(); + } finally { + $span->finish(); + + SentrySdk::getCurrentHub()->setSpan($parentSpan); + } + } +} diff --git a/src/Sentry/Laravel/Tracing/ServiceProvider.php b/src/Sentry/Laravel/Tracing/ServiceProvider.php index 1071b8fb..cd56d2d4 100644 --- a/src/Sentry/Laravel/Tracing/ServiceProvider.php +++ b/src/Sentry/Laravel/Tracing/ServiceProvider.php @@ -8,10 +8,14 @@ use Illuminate\Contracts\View\Engine; use Illuminate\Contracts\View\View; use Illuminate\Foundation\Http\Kernel as HttpKernel; +use Illuminate\Routing\Contracts\CallableDispatcher; +use Illuminate\Routing\Contracts\ControllerDispatcher; use Illuminate\View\Engines\EngineResolver; use Illuminate\View\Factory as ViewFactory; use InvalidArgumentException; use Sentry\Laravel\BaseServiceProvider; +use Sentry\Laravel\Tracing\Routing\TracingCallableDispatcherTracing; +use Sentry\Laravel\Tracing\Routing\TracingControllerDispatcherTracing; use Sentry\Serializer\RepresentationSerializer; class ServiceProvider extends BaseServiceProvider @@ -29,6 +33,8 @@ public function boot(): void $this->bindViewEngine($tracingConfig); + $this->decorateRoutingDispatchers(); + if ($this->app->bound(HttpKernelInterface::class)) { /** @var \Illuminate\Foundation\Http\Kernel $httpKernel */ $httpKernel = $this->app->make(HttpKernelInterface::class); @@ -119,4 +125,15 @@ private function wrapViewEngine(Engine $realEngine): Engine return new ViewEngineDecorator($realEngine, $viewFactory); } + + private function decorateRoutingDispatchers(): void + { + $this->app->extend(CallableDispatcher::class, static function (CallableDispatcher $dispatcher) { + return new TracingCallableDispatcherTracing($dispatcher); + }); + + $this->app->extend(ControllerDispatcher::class, static function (ControllerDispatcher $dispatcher) { + return new TracingControllerDispatcherTracing($dispatcher); + }); + } }