2
2
3
3
namespace Sentry \Laravel \Tracing \Integrations ;
4
4
5
+ use GraphQL \Language \AST \DocumentNode ;
5
6
use GraphQL \Language \AST \OperationDefinitionNode ;
6
- use Illuminate \Contracts \Events \Dispatcher ;
7
+ use Illuminate \Contracts \Events \Dispatcher as EventDispatcher ;
7
8
use Nuwave \Lighthouse \Events \EndExecution ;
8
9
use Nuwave \Lighthouse \Events \EndRequest ;
9
10
use Nuwave \Lighthouse \Events \StartExecution ;
12
13
use Sentry \SentrySdk ;
13
14
use Sentry \Tracing \SpanContext ;
14
15
15
- class LighthouseIntegration
16
+ class LighthouseIntegration implements IntegrationInterface
16
17
{
17
- /** @var array<int, < string|null , \GraphQL\Language\AST\OperationDefinitionNode> > $operations */
18
+ /** @var array<int, array{? string, \GraphQL\Language\AST\OperationDefinitionNode} > $operations */
18
19
private $ operations ;
19
20
20
21
/** @var \Sentry\Tracing\Span|null $previousSpan */
@@ -26,16 +27,12 @@ class LighthouseIntegration
26
27
/** @var \Sentry\Tracing\Span|null $operationSpan */
27
28
private $ operationSpan ;
28
29
29
- public function __construct (Dispatcher $ evenDispatcher )
30
+ public function __construct (EventDispatcher $ eventDispatcher )
30
31
{
31
- if (!class_exists (StartRequest::class)) {
32
- return ;
33
- }
34
-
35
- $ evenDispatcher ->listen (StartRequest::class, [$ this , 'handleStartRequest ' ]);
36
- $ evenDispatcher ->listen (StartExecution::class, [$ this , 'handleStartExecution ' ]);
37
- $ evenDispatcher ->listen (EndExecution::class, [$ this , 'handleEndExecution ' ]);
38
- $ evenDispatcher ->listen (EndRequest::class, [$ this , 'handleEndRequest ' ]);
32
+ $ eventDispatcher ->listen (StartRequest::class, [$ this , 'handleStartRequest ' ]);
33
+ $ eventDispatcher ->listen (StartExecution::class, [$ this , 'handleStartExecution ' ]);
34
+ $ eventDispatcher ->listen (EndExecution::class, [$ this , 'handleEndExecution ' ]);
35
+ $ eventDispatcher ->listen (EndRequest::class, [$ this , 'handleEndRequest ' ]);
39
36
}
40
37
41
38
public function handleStartRequest (StartRequest $ startRequest ): void
@@ -46,12 +43,12 @@ public function handleStartRequest(StartRequest $startRequest): void
46
43
return ;
47
44
}
48
45
49
- $ this ->operations = [];
50
-
51
46
$ context = new SpanContext ;
52
47
$ context ->setOp ('graphql.request ' );
53
48
54
- $ this ->requestSpan = $ this ->previousSpan ->startChild ($ context );
49
+ $ this ->operations = [];
50
+ $ this ->requestSpan = $ this ->previousSpan ->startChild ($ context );
51
+ $ this ->operationSpan = null ;
55
52
56
53
SentrySdk::getCurrentHub ()->setSpan ($ this ->requestSpan );
57
54
}
@@ -62,14 +59,18 @@ public function handleStartExecution(StartExecution $startExecution): void
62
59
return ;
63
60
}
64
61
62
+ if (!$ startExecution ->query instanceof DocumentNode) {
63
+ return ;
64
+ }
65
+
65
66
/** @var \GraphQL\Language\AST\OperationDefinitionNode|null $operationDefinition */
66
67
$ operationDefinition = $ startExecution ->query ->definitions [0 ] ?? null ;
67
68
68
- if ($ operationDefinition === null ) {
69
+ if (! $ operationDefinition instanceof OperationDefinitionNode ) {
69
70
return ;
70
71
}
71
72
72
- $ this ->operations [] = [$ startExecution ->operationName , $ operationDefinition ];
73
+ $ this ->operations [] = [$ startExecution ->operationName ?? null , $ operationDefinition ];
73
74
74
75
$ context = new SpanContext ;
75
76
$ context ->setOp (
@@ -116,6 +117,12 @@ public function handleEndRequest(EndRequest $endRequest): void
116
117
117
118
private function updateTransaction (): void
118
119
{
120
+ $ transaction = SentrySdk::getCurrentHub ()->getTransaction ();
121
+
122
+ if ($ transaction === null ) {
123
+ return ;
124
+ }
125
+
119
126
$ groupedOperations = [];
120
127
121
128
foreach ($ this ->operations as [$ operationName , $ operation ]) {
@@ -143,10 +150,12 @@ private function updateTransaction(): void
143
150
144
151
$ transactionName = 'lighthouse? ' . implode ('& ' , $ groupedOperations );
145
152
146
- Integration::setTransaction ($ transactionName );
147
- SentrySdk::getCurrentHub ()->getTransaction ()->setName ($ transactionName );
153
+ $ transaction ->setName ($ transactionName );
148
154
}
149
155
156
+ /**
157
+ * @return array<int, string>
158
+ */
150
159
private function extractOperationNames (OperationDefinitionNode $ operation ): array
151
160
{
152
161
if ($ operation ->name !== null ) {
@@ -157,9 +166,9 @@ private function extractOperationNames(OperationDefinitionNode $operation): arra
157
166
158
167
/** @var \GraphQL\Language\AST\FieldNode $selection */
159
168
foreach ($ operation ->selectionSet ->selections as $ selection ) {
160
- $ selectionSet [] = $ selection -> alias === null
161
- ? $ selection -> name -> value
162
- : $ selection ->alias ->value ;
169
+ // Not respecting aliases because they are only relevant for clients
170
+ // and the tracing we extract here is targeted at server developers.
171
+ $ selectionSet [] = $ selection ->name ->value ;
163
172
}
164
173
165
174
sort ($ selectionSet , SORT_STRING );
@@ -169,6 +178,10 @@ private function extractOperationNames(OperationDefinitionNode $operation): arra
169
178
170
179
public static function supported (): bool
171
180
{
172
- return class_exists (StartRequest::class);
181
+ if (!class_exists (StartRequest::class) || !class_exists (StartExecution::class)) {
182
+ return false ;
183
+ }
184
+
185
+ return property_exists (StartExecution::class, 'query ' );
173
186
}
174
187
}
0 commit comments