17
17
use Illuminate \Queue \Events \JobProcessing ;
18
18
use Illuminate \Queue \Events \WorkerStopping ;
19
19
use Illuminate \Queue \QueueManager ;
20
+ use Laravel \Octane \Events as Octane ;
20
21
use Illuminate \Routing \Events \RouteMatched ;
21
22
use Illuminate \Routing \Route ;
22
23
use RuntimeException ;
@@ -32,13 +33,13 @@ class EventHandler
32
33
* @var array
33
34
*/
34
35
protected static $ eventHandlerMap = [
35
- 'router.matched ' => 'routerMatched ' , // Until Laravel 5.1
36
+ 'router.matched ' => 'routerMatched ' , // Until Laravel 5.1
36
37
'Illuminate\Routing\Events\RouteMatched ' => 'routeMatched ' , // Since Laravel 5.2
37
38
38
- 'illuminate.query ' => 'query ' , // Until Laravel 5.1
39
+ 'illuminate.query ' => 'query ' , // Until Laravel 5.1
39
40
'Illuminate\Database\Events\QueryExecuted ' => 'queryExecuted ' , // Since Laravel 5.2
40
41
41
- 'illuminate.log ' => 'log ' , // Until Laravel 5.3
42
+ 'illuminate.log ' => 'log ' , // Until Laravel 5.3
42
43
'Illuminate\Log\Events\MessageLogged ' => 'messageLogged ' , // Since Laravel 5.4
43
44
44
45
'Illuminate\Console\Events\CommandStarting ' => 'commandStarting ' , // Since Laravel 5.5
@@ -60,10 +61,29 @@ class EventHandler
60
61
* @var array
61
62
*/
62
63
protected static $ queueEventHandlerMap = [
63
- 'Illuminate\Queue\Events\JobProcessing ' => 'queueJobProcessing ' , // Since Laravel 5.2
64
- 'Illuminate\Queue\Events\JobProcessed ' => 'queueJobProcessed ' , // Since Laravel 5.2
64
+ 'Illuminate\Queue\Events\JobProcessing ' => 'queueJobProcessing ' , // Since Laravel 5.2
65
+ 'Illuminate\Queue\Events\JobProcessed ' => 'queueJobProcessed ' , // Since Laravel 5.2
65
66
'Illuminate\Queue\Events\JobExceptionOccurred ' => 'queueJobExceptionOccurred ' , // Since Laravel 5.2
66
- 'Illuminate\Queue\Events\WorkerStopping ' => 'queueWorkerStopping ' , // Since Laravel 5.2
67
+ 'Illuminate\Queue\Events\WorkerStopping ' => 'queueWorkerStopping ' , // Since Laravel 5.2
68
+ ];
69
+
70
+ /**
71
+ * Map Octane event handlers to events.
72
+ *
73
+ * @var array
74
+ */
75
+ protected static $ octaneEventHandlerMap = [
76
+ 'Laravel\Octane\Events\RequestReceived ' => 'octaneRequestReceived ' ,
77
+ 'Laravel\Octane\Events\RequestTerminated ' => 'octaneRequestTerminated ' ,
78
+
79
+ 'Laravel\Octane\Events\TaskReceived ' => 'octaneTaskReceived ' ,
80
+ 'Laravel\Octane\Events\TaskTerminated ' => 'octaneTaskTerminated ' ,
81
+
82
+ 'Laravel\Octane\Events\TickReceived ' => 'octaneTickReceived ' ,
83
+ 'Laravel\Octane\Events\TickTerminated ' => 'octaneTickTerminated ' ,
84
+
85
+ 'Laravel\Octane\Events\WorkerErrorOccurred ' => 'octaneWorkerErrorOccurred ' ,
86
+ 'Laravel\Octane\Events\WorkerStopping ' => 'octaneWorkerStopping ' ,
67
87
];
68
88
69
89
/**
@@ -108,13 +128,34 @@ class EventHandler
108
128
*/
109
129
private $ recordCommandInfo ;
110
130
131
+ /**
132
+ * Indicates if we should we add tick info to the breadcrumbs.
133
+ *
134
+ * @var bool
135
+ */
136
+ private $ recordOctaneTickInfo ;
137
+
138
+ /**
139
+ * Indicates if we should we add task info to the breadcrumbs.
140
+ *
141
+ * @var bool
142
+ */
143
+ private $ recordOctaneTaskInfo ;
144
+
111
145
/**
112
146
* Indicates if we pushed a scope for the queue.
113
147
*
114
148
* @var bool
115
149
*/
116
150
private $ pushedQueueScope = false ;
117
151
152
+ /**
153
+ * Indicates if we pushed a scope for Octane.
154
+ *
155
+ * @var bool
156
+ */
157
+ private $ pushedOctaneScope = false ;
158
+
118
159
/**
119
160
* EventHandler constructor.
120
161
*
@@ -125,11 +166,13 @@ public function __construct(Container $container, array $config)
125
166
{
126
167
$ this ->container = $ container ;
127
168
128
- $ this ->recordSqlQueries = ($ config ['breadcrumbs.sql_queries ' ] ?? $ config ['breadcrumbs ' ]['sql_queries ' ] ?? true ) === true ;
129
- $ this ->recordSqlBindings = ($ config ['breadcrumbs.sql_bindings ' ] ?? $ config ['breadcrumbs ' ]['sql_bindings ' ] ?? false ) === true ;
130
- $ this ->recordLaravelLogs = ($ config ['breadcrumbs.logs ' ] ?? $ config ['breadcrumbs ' ]['logs ' ] ?? true ) === true ;
131
- $ this ->recordQueueInfo = ($ config ['breadcrumbs.queue_info ' ] ?? $ config ['breadcrumbs ' ]['queue_info ' ] ?? true ) === true ;
132
- $ this ->recordCommandInfo = ($ config ['breadcrumbs.command_info ' ] ?? $ config ['breadcrumbs ' ]['command_info ' ] ?? true ) === true ;
169
+ $ this ->recordSqlQueries = ($ config ['breadcrumbs.sql_queries ' ] ?? $ config ['breadcrumbs ' ]['sql_queries ' ] ?? true ) === true ;
170
+ $ this ->recordSqlBindings = ($ config ['breadcrumbs.sql_bindings ' ] ?? $ config ['breadcrumbs ' ]['sql_bindings ' ] ?? false ) === true ;
171
+ $ this ->recordLaravelLogs = ($ config ['breadcrumbs.logs ' ] ?? $ config ['breadcrumbs ' ]['logs ' ] ?? true ) === true ;
172
+ $ this ->recordQueueInfo = ($ config ['breadcrumbs.queue_info ' ] ?? $ config ['breadcrumbs ' ]['queue_info ' ] ?? true ) === true ;
173
+ $ this ->recordCommandInfo = ($ config ['breadcrumbs.command_info ' ] ?? $ config ['breadcrumbs ' ]['command_info ' ] ?? true ) === true ;
174
+ $ this ->recordOctaneTickInfo = ($ config ['breadcrumbs.octane_tick_info ' ] ?? $ config ['breadcrumbs ' ]['octane_tick_info ' ] ?? true ) === true ;
175
+ $ this ->recordOctaneTaskInfo = ($ config ['breadcrumbs.octane_task_info ' ] ?? $ config ['breadcrumbs ' ]['octane_task_info ' ] ?? true ) === true ;
133
176
}
134
177
135
178
/**
@@ -166,6 +209,23 @@ public function subscribeAuthEvents(): void
166
209
}
167
210
}
168
211
212
+ /**
213
+ * Attach all queue event handlers.
214
+ */
215
+ public function subscribeOctaneEvents (): void
216
+ {
217
+ /** @var \Illuminate\Contracts\Events\Dispatcher $dispatcher */
218
+ try {
219
+ $ dispatcher = $ this ->container ->make (Dispatcher::class);
220
+
221
+ foreach (static ::$ octaneEventHandlerMap as $ eventName => $ handler ) {
222
+ $ dispatcher ->listen ($ eventName , [$ this , $ handler ]);
223
+ }
224
+ } catch (BindingResolutionException $ e ) {
225
+ // If we cannot resolve the event dispatcher we also cannot listen to events
226
+ }
227
+ }
228
+
169
229
/**
170
230
* Attach all queue event handlers.
171
231
*
@@ -174,8 +234,9 @@ public function subscribeAuthEvents(): void
174
234
public function subscribeQueueEvents (QueueManager $ queue ): void
175
235
{
176
236
$ queue ->looping (function () {
177
- $ this ->cleanupScopeForQueuedJob ();
178
- $ this ->afterQueuedJob ();
237
+ $ this ->cleanupScopeForTaskWithinLongRunningProcessWhen ($ this ->pushedQueueScope );
238
+
239
+ $ this ->pushedQueueScope = false ;
179
240
});
180
241
181
242
/** @var \Illuminate\Contracts\Events\Dispatcher $dispatcher */
@@ -351,33 +412,6 @@ private function addLogBreadcrumb(string $level, ?string $message, array $contex
351
412
));
352
413
}
353
414
354
- /**
355
- * Translates common log levels to Sentry breadcrumb levels.
356
- *
357
- * @param string $level Log level. Maybe any standard.
358
- *
359
- * @return string Breadcrumb level.
360
- */
361
- protected function logLevelToBreadcrumbLevel (string $ level ): string
362
- {
363
- switch (strtolower ($ level )) {
364
- case 'debug ' :
365
- return Breadcrumb::LEVEL_DEBUG ;
366
- case 'warning ' :
367
- return Breadcrumb::LEVEL_WARNING ;
368
- case 'error ' :
369
- return Breadcrumb::LEVEL_ERROR ;
370
- case 'critical ' :
371
- case 'alert ' :
372
- case 'emergency ' :
373
- return Breadcrumb::LEVEL_FATAL ;
374
- case 'info ' :
375
- case 'notice ' :
376
- default :
377
- return Breadcrumb::LEVEL_INFO ;
378
- }
379
- }
380
-
381
415
/**
382
416
* Since Laravel 5.3
383
417
*
@@ -416,16 +450,20 @@ protected function authenticatedHandler(Authenticated $event)
416
450
*/
417
451
protected function queueJobProcessingHandler (JobProcessing $ event )
418
452
{
419
- $ this ->prepareScopeForQueuedJob ();
453
+ $ this ->cleanupScopeForTaskWithinLongRunningProcessWhen ($ this ->pushedQueueScope );
454
+
455
+ $ this ->prepareScopeForTaskWithinLongRunningProcess ();
456
+
457
+ $ this ->pushedQueueScope = true ;
420
458
421
459
if (!$ this ->recordQueueInfo ) {
422
460
return ;
423
461
}
424
462
425
463
$ job = [
426
- 'job ' => $ event ->job ->getName (),
427
- 'queue ' => $ event ->job ->getQueue (),
428
- 'attempts ' => $ event ->job ->attempts (),
464
+ 'job ' => $ event ->job ->getName (),
465
+ 'queue ' => $ event ->job ->getQueue (),
466
+ 'attempts ' => $ event ->job ->attempts (),
429
467
'connection ' => $ event ->connectionName ,
430
468
];
431
469
@@ -450,7 +488,7 @@ protected function queueJobProcessingHandler(JobProcessing $event)
450
488
*/
451
489
protected function queueJobExceptionOccurredHandler (JobExceptionOccurred $ event )
452
490
{
453
- $ this ->afterQueuedJob ();
491
+ $ this ->afterTaskWithinLongRunningProcess ();
454
492
}
455
493
456
494
/**
@@ -460,7 +498,7 @@ protected function queueJobExceptionOccurredHandler(JobExceptionOccurred $event)
460
498
*/
461
499
protected function queueJobProcessedHandler (JobProcessed $ event )
462
500
{
463
- $ this ->afterQueuedJob ();
501
+ $ this ->afterTaskWithinLongRunningProcess ();
464
502
}
465
503
466
504
/**
@@ -531,34 +569,149 @@ protected function commandFinishedHandler(CommandFinished $event)
531
569
Integration::flushEvents ();
532
570
}
533
571
534
- private function afterQueuedJob (): void
572
+ protected function octaneRequestReceivedHandler (Octane \RequestReceived $ event ): void
573
+ {
574
+ $ this ->prepareScopeForOctane ();
575
+ }
576
+
577
+ protected function octaneRequestTerminatedHandler (Octane \RequestTerminated $ event ): void
578
+ {
579
+ $ this ->cleanupScopeForOctane ();
580
+ }
581
+
582
+ protected function octaneTaskReceivedHandler (Octane \TaskReceived $ event ): void
583
+ {
584
+ $ this ->prepareScopeForOctane ();
585
+
586
+ if (!$ this ->recordOctaneTaskInfo ) {
587
+ return ;
588
+ }
589
+
590
+ Integration::addBreadcrumb (new Breadcrumb (
591
+ Breadcrumb::LEVEL_INFO ,
592
+ Breadcrumb::TYPE_DEFAULT ,
593
+ 'octane.task ' ,
594
+ 'Processing Octane task '
595
+ ));
596
+ }
597
+
598
+ protected function octaneTaskTerminatedHandler (Octane \TaskTerminated $ event ): void
599
+ {
600
+ $ this ->cleanupScopeForOctane ();
601
+ }
602
+
603
+ protected function octaneTickReceivedHandler (Octane \TickReceived $ event ): void
604
+ {
605
+ $ this ->prepareScopeForOctane ();
606
+
607
+ if (!$ this ->recordOctaneTickInfo ) {
608
+ return ;
609
+ }
610
+
611
+ Integration::addBreadcrumb (new Breadcrumb (
612
+ Breadcrumb::LEVEL_INFO ,
613
+ Breadcrumb::TYPE_DEFAULT ,
614
+ 'octane.tick ' ,
615
+ 'Processing Octane tick '
616
+ ));
617
+ }
618
+
619
+ protected function octaneTickTerminatedHandler (Octane \TickTerminated $ event ): void
620
+ {
621
+ $ this ->cleanupScopeForOctane ();
622
+ }
623
+
624
+ protected function octaneWorkerErrorOccurredHandler (Octane \WorkerErrorOccurred $ event ): void
625
+ {
626
+ $ this ->afterTaskWithinLongRunningProcess ();
627
+ }
628
+
629
+ protected function octaneWorkerStoppingHandler (Octane \WorkerStopping $ event ): void
630
+ {
631
+ $ this ->afterTaskWithinLongRunningProcess ();
632
+ }
633
+
634
+ private function prepareScopeForOctane (): void
635
+ {
636
+ $ this ->cleanupScopeForOctane ();
637
+
638
+ $ this ->prepareScopeForTaskWithinLongRunningProcess ();
639
+
640
+ $ this ->pushedOctaneScope = true ;
641
+ }
642
+
643
+ private function cleanupScopeForOctane (): void
644
+ {
645
+ $ this ->cleanupScopeForTaskWithinLongRunningProcessWhen ($ this ->pushedOctaneScope );
646
+
647
+ $ this ->pushedOctaneScope = false ;
648
+ }
649
+
650
+ /**
651
+ * Translates common log levels to Sentry breadcrumb levels.
652
+ *
653
+ * @param string $level Log level. Maybe any standard.
654
+ *
655
+ * @return string Breadcrumb level.
656
+ */
657
+ private function logLevelToBreadcrumbLevel (string $ level ): string
658
+ {
659
+ switch (strtolower ($ level )) {
660
+ case 'debug ' :
661
+ return Breadcrumb::LEVEL_DEBUG ;
662
+ case 'warning ' :
663
+ return Breadcrumb::LEVEL_WARNING ;
664
+ case 'error ' :
665
+ return Breadcrumb::LEVEL_ERROR ;
666
+ case 'critical ' :
667
+ case 'alert ' :
668
+ case 'emergency ' :
669
+ return Breadcrumb::LEVEL_FATAL ;
670
+ case 'info ' :
671
+ case 'notice ' :
672
+ default :
673
+ return Breadcrumb::LEVEL_INFO ;
674
+ }
675
+ }
676
+
677
+ /**
678
+ * Should be called after a task within a long running process has ended so events can be flushed.
679
+ */
680
+ private function afterTaskWithinLongRunningProcess (): void
535
681
{
536
682
// Flush any and all events that were possibly generated by queue jobs
537
683
Integration::flushEvents ();
538
684
}
539
685
540
- private function prepareScopeForQueuedJob (): void
686
+ /**
687
+ * Should be called before starting a task within a long running process, this is done to prevent
688
+ * the task to have effect on the scope for the next task to run within the long running process.
689
+ */
690
+ private function prepareScopeForTaskWithinLongRunningProcess (): void
541
691
{
542
- $ this ->cleanupScopeForQueuedJob ();
543
-
544
692
SentrySdk::getCurrentHub ()->pushScope ();
545
693
546
- $ this ->pushedQueueScope = true ;
547
-
548
694
// When a job starts, we want to make sure the scope is cleared of breadcrumbs
549
695
SentrySdk::getCurrentHub ()->configureScope (static function (Scope $ scope ) {
550
696
$ scope ->clearBreadcrumbs ();
551
697
});
552
698
}
553
699
554
- private function cleanupScopeForQueuedJob (): void
700
+ /**
701
+ * Cleanup a previously prepared scope.
702
+ *
703
+ * @param bool $when Only cleanup the scope when this is true.
704
+ *
705
+ * @see prepareScopeForTaskWithinLongRunningProcess
706
+ */
707
+ private function cleanupScopeForTaskWithinLongRunningProcessWhen (bool $ when ): void
555
708
{
556
- if (!$ this -> pushedQueueScope ) {
709
+ if (!$ when ) {
557
710
return ;
558
711
}
559
712
560
- SentrySdk:: getCurrentHub ()-> popScope ();
713
+ $ this -> afterTaskWithinLongRunningProcess ();
561
714
562
- $ this -> pushedQueueScope = false ;
715
+ SentrySdk:: getCurrentHub ()-> popScope () ;
563
716
}
564
717
}
0 commit comments