From 9b26cad08f2a3b03212d133398f8bc1b35ce3d93 Mon Sep 17 00:00:00 2001 From: Alex Bouma Date: Tue, 25 Jul 2023 19:47:40 +0200 Subject: [PATCH] Make it configurable if the performance traces continues after the response has been sent (#727) --- config/sentry.php | 4 ++ src/Sentry/Laravel/Tracing/Middleware.php | 44 ++++++++++++------- .../Laravel/Tracing/ServiceProvider.php | 11 ++++- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/config/sentry.php b/config/sentry.php index bbf98c83..2bf36dc2 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -71,6 +71,10 @@ // Indicates that requests without a matching route should be traced 'missing_routes' => false, + + // Indicates if the performance trace should continue after the response has been sent to the user until the application terminates + // This is required to capture any spans that are created after the response has been sent like queue jobs dispatched using `dispatch(...)->afterResponse()` for example + 'continue_after_response' => true, ], // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send-default-pii diff --git a/src/Sentry/Laravel/Tracing/Middleware.php b/src/Sentry/Laravel/Tracing/Middleware.php index 18e057fa..6341bfe2 100644 --- a/src/Sentry/Laravel/Tracing/Middleware.php +++ b/src/Sentry/Laravel/Tracing/Middleware.php @@ -45,6 +45,13 @@ class Middleware */ private $app; + /** + * Whether we should continue tracing after the response has been sent to the client. + * + * @var bool + */ + private $continueAfterResponse; + /** * Whether the terminating callback has been registered. * @@ -57,9 +64,10 @@ class Middleware * * @param LaravelApplication|LumenApplication $app */ - public function __construct($app) + public function __construct($app, bool $continueAfterResponse = true) { $this->app = $app; + $this->continueAfterResponse = $continueAfterResponse; } /** @@ -108,22 +116,26 @@ public function terminate(Request $request, $response): void $this->hydrateResponseData($response); } - // Ensure we do not register the terminating callback multiple times since there is no point in doing so - if ($this->registeredTerminatingCallback) { - return; - } - - // We need to finish the transaction after the response has been sent to the client - // so we register a terminating callback to do so, this allows us to also capture - // spans that are created during the termination of the application like queue - // dispatched using dispatch(...)->afterResponse(). This middleware is called - // before the terminating callbacks so we are 99.9% sure to be the last one - // to run except if another terminating callback is registered after ours. - $this->app->terminating(function () { + if ($this->continueAfterResponse) { + // Ensure we do not register the terminating callback multiple times since there is no point in doing so + if ($this->registeredTerminatingCallback) { + return; + } + + // We need to finish the transaction after the response has been sent to the client + // so we register a terminating callback to do so, this allows us to also capture + // spans that are created during the termination of the application like queue + // dispatched using dispatch(...)->afterResponse(). This middleware is called + // before the terminating callbacks so we are 99.9% sure to be the last one + // to run except if another terminating callback is registered after ours. + $this->app->terminating(function () { + $this->finishTransaction(); + }); + + $this->registeredTerminatingCallback = true; + } else { $this->finishTransaction(); - }); - - $this->registeredTerminatingCallback = true; + } } /** diff --git a/src/Sentry/Laravel/Tracing/ServiceProvider.php b/src/Sentry/Laravel/Tracing/ServiceProvider.php index 1845d1b3..e7ccc5f5 100644 --- a/src/Sentry/Laravel/Tracing/ServiceProvider.php +++ b/src/Sentry/Laravel/Tracing/ServiceProvider.php @@ -39,7 +39,7 @@ public function boot(): void }); } - $tracingConfig = $this->getUserConfig()['tracing'] ?? []; + $tracingConfig = $this->getTracingConfig(); $this->bindEvents($tracingConfig); @@ -61,7 +61,9 @@ public function boot(): void public function register(): void { $this->app->singleton(Middleware::class, function () { - return new Middleware($this->app); + $continueAfterResponse = ($this->getTracingConfig()['continue_after_response'] ?? true) === true; + + return new Middleware($this->app, $continueAfterResponse); }); $this->app->singleton(BacktraceHelper::class, function () { @@ -132,6 +134,11 @@ private function wrapViewEngine(Engine $realEngine): Engine return new ViewEngineDecorator($realEngine, $viewFactory); } + private function getTracingConfig(): array + { + return $this->getUserConfig()['tracing'] ?? []; + } + private function decorateRoutingDispatchers(): void { $this->app->extend(CallableDispatcher::class, static function (CallableDispatcher $dispatcher) {