77use Illuminate \Contracts \Container \Container ;
88use Illuminate \Contracts \Events \Dispatcher ;
99use Illuminate \Database \Events as DatabaseEvents ;
10+ use Illuminate \Http \Client \Events as HttpClientEvents ;
1011use Illuminate \Queue \Events as QueueEvents ;
1112use Illuminate \Queue \Queue ;
1213use Illuminate \Queue \QueueManager ;
14+ use Illuminate \Routing \Events as RoutingEvents ;
1315use RuntimeException ;
1416use Sentry \Laravel \Integration ;
1517use Sentry \SentrySdk ;
@@ -30,7 +32,11 @@ class EventHandler
3032 * @var array
3133 */
3234 protected static $ eventHandlerMap = [
35+ RoutingEvents \RouteMatched::class => 'routeMatched ' ,
3336 DatabaseEvents \QueryExecuted::class => 'queryExecuted ' ,
37+ HttpClientEvents \RequestSending::class => 'httpClientRequestSending ' ,
38+ HttpClientEvents \ResponseReceived::class => 'httpClientResponseReceived ' ,
39+ HttpClientEvents \ConnectionFailed::class => 'httpClientConnectionFailed ' ,
3440 ];
3541
3642 /**
@@ -93,6 +99,20 @@ class EventHandler
9399 */
94100 private $ currentQueueJobSpan ;
95101
102+ /**
103+ * Holds a reference to the parent http client request span.
104+ *
105+ * @var \Sentry\Tracing\Span|null
106+ */
107+ private $ parentHttpClientRequestSpan ;
108+
109+ /**
110+ * Holds a reference to the current http client request span.
111+ *
112+ * @var \Sentry\Tracing\Span|null
113+ */
114+ private $ currentHttpClientRequestSpan ;
115+
96116 /**
97117 * The backtrace helper.
98118 *
@@ -122,6 +142,7 @@ public function __construct(Container $container, BacktraceHelper $backtraceHelp
122142 /**
123143 * Attach all event handlers.
124144 *
145+ * @uses self::routeMatchedHandler()
125146 * @uses self::queryExecutedHandler()
126147 */
127148 public function subscribe (): void
@@ -202,6 +223,20 @@ public function __call(string $method, array $arguments)
202223 }
203224 }
204225
226+ protected function routeMatchedHandler (RoutingEvents \RouteMatched $ match ): void
227+ {
228+ $ transaction = Integration::currentTransaction ();
229+
230+ if ($ transaction === null ) {
231+ return ;
232+ }
233+
234+ [$ transactionName , $ transactionSource ] = Integration::extractNameAndSourceForRoute ($ match ->route );
235+
236+ $ transaction ->setName ($ transactionName );
237+ $ transaction ->getMetadata ()->setSource ($ transactionSource );
238+ }
239+
205240 protected function queryExecutedHandler (DatabaseEvents \QueryExecuted $ query ): void
206241 {
207242 if (!$ this ->traceSqlQueries ) {
@@ -250,6 +285,56 @@ private function resolveQueryOriginFromBacktrace(): ?string
250285 return "{$ filePath }: {$ firstAppFrame ->getLine ()}" ;
251286 }
252287
288+ protected function httpClientRequestSendingHandler (HttpClientEvents \RequestSending $ event ): void
289+ {
290+ $ parentSpan = Integration::currentTracingSpan ();
291+
292+ if ($ parentSpan === null ) {
293+ return ;
294+ }
295+
296+ $ context = new SpanContext ;
297+
298+ $ context ->setOp ('http.client ' );
299+ $ context ->setDescription ($ event ->request ->method () . ' ' . $ event ->request ->url ());
300+ $ context ->setStartTimestamp (microtime (true ));
301+
302+ $ this ->currentHttpClientRequestSpan = $ parentSpan ->startChild ($ context );
303+
304+ $ this ->parentHttpClientRequestSpan = $ parentSpan ;
305+
306+ SentrySdk::getCurrentHub ()->setSpan ($ this ->currentHttpClientRequestSpan );
307+ }
308+
309+ protected function httpClientResponseReceivedHandler (HttpClientEvents \ResponseReceived $ event ): void
310+ {
311+ if ($ this ->currentHttpClientRequestSpan !== null ) {
312+ $ this ->currentHttpClientRequestSpan ->setHttpStatus ($ event ->response ->status ());
313+ $ this ->afterHttpClientRequest ();
314+ }
315+ }
316+
317+ protected function httpClientConnectionFailedHandler (HttpClientEvents \ConnectionFailed $ event ): void
318+ {
319+ if ($ this ->currentHttpClientRequestSpan !== null ) {
320+ $ this ->currentHttpClientRequestSpan ->setStatus (SpanStatus::internalError ());
321+ $ this ->afterHttpClientRequest ();
322+ }
323+ }
324+
325+ private function afterHttpClientRequest (): void
326+ {
327+ if ($ this ->currentHttpClientRequestSpan === null ) {
328+ return ;
329+ }
330+
331+ $ this ->currentHttpClientRequestSpan ->finish ();
332+ $ this ->currentHttpClientRequestSpan = null ;
333+
334+ SentrySdk::getCurrentHub ()->setSpan ($ this ->parentHttpClientRequestSpan );
335+ $ this ->parentHttpClientRequestSpan = null ;
336+ }
337+
253338 protected function queueJobProcessingHandler (QueueEvents \JobProcessing $ event ): void
254339 {
255340 $ parentSpan = Integration::currentTracingSpan ();
@@ -278,24 +363,18 @@ protected function queueJobProcessingHandler(QueueEvents\JobProcessing $event):
278363 $ context = new SpanContext ;
279364 }
280365
366+ $ resolvedJobName = $ event ->job ->resolveName ();
367+
281368 $ job = [
282369 'job ' => $ event ->job ->getName (),
283370 'queue ' => $ event ->job ->getQueue (),
371+ 'resolved ' => $ event ->job ->resolveName (),
284372 'attempts ' => $ event ->job ->attempts (),
285373 'connection ' => $ event ->connectionName ,
286374 ];
287375
288- // Resolve name exists only from Laravel 5.3+
289- $ resolvedJobName = method_exists ($ event ->job , 'resolveName ' )
290- ? $ event ->job ->resolveName ()
291- : null ;
292-
293- if ($ resolvedJobName !== null ) {
294- $ job ['resolved ' ] = $ resolvedJobName ;
295- }
296-
297376 if ($ context instanceof TransactionContext) {
298- $ context ->setName ($ resolvedJobName ?? $ event -> job -> getName () );
377+ $ context ->setName ($ resolvedJobName );
299378 $ context ->setSource (TransactionSource::task ());
300379 }
301380
0 commit comments