@geekmidas/telescope 9.0.2 → 10.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +14 -4
  2. package/dist/{http-D5kn3_Mt.d.mts → http-BiNtg85L.d.mts} +3 -3
  3. package/dist/{http-D5kn3_Mt.d.mts.map → http-BiNtg85L.d.mts.map} +1 -1
  4. package/dist/instrumentation/http.d.mts +1 -1
  5. package/dist/instrumentation/index.cjs +2 -2
  6. package/dist/instrumentation/index.d.cts +2 -2
  7. package/dist/instrumentation/index.d.mts +3 -3
  8. package/dist/instrumentation/index.mjs +2 -2
  9. package/dist/instrumentation/middleware.cjs +1 -1
  10. package/dist/instrumentation/middleware.d.cts +1 -1
  11. package/dist/instrumentation/middleware.d.mts +1 -1
  12. package/dist/instrumentation/middleware.mjs +1 -1
  13. package/dist/instrumentation/otel.cjs +1 -1
  14. package/dist/instrumentation/otel.d.cts +1 -1
  15. package/dist/instrumentation/otel.d.mts +1 -1
  16. package/dist/instrumentation/otel.mjs +1 -1
  17. package/dist/logger/console.d.cts.map +1 -1
  18. package/dist/logger/pino.d.mts +2 -2
  19. package/dist/{middleware-DqPQpcup.cjs → middleware-Bcq6XXGG.cjs} +2 -2
  20. package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
  21. package/dist/{middleware-4-GrQlOT.mjs → middleware-D1XEHvyy.mjs} +2 -2
  22. package/dist/middleware-D1XEHvyy.mjs.map +1 -0
  23. package/dist/{middleware-CA84nsNN.d.cts → middleware-PeyS-9Ny.d.cts} +2 -2
  24. package/dist/{middleware-CA84nsNN.d.cts.map → middleware-PeyS-9Ny.d.cts.map} +1 -1
  25. package/dist/{middleware-DAceVpfw.d.mts → middleware-oHvo_ZgU.d.mts} +2 -2
  26. package/dist/{middleware-DAceVpfw.d.mts.map → middleware-oHvo_ZgU.d.mts.map} +1 -1
  27. package/dist/{otel-40udNP5g.mjs → otel-B9bNoeZ2.mjs} +3 -3
  28. package/dist/otel-B9bNoeZ2.mjs.map +1 -0
  29. package/dist/{otel-SBVoVEHr.d.cts → otel-Bk89b1lX.d.cts} +3 -3
  30. package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
  31. package/dist/{otel-COrpz_GZ.cjs → otel-BzjOtVxZ.cjs} +3 -3
  32. package/dist/otel-BzjOtVxZ.cjs.map +1 -0
  33. package/dist/{otel-1bJPb2Z7.d.mts → otel-lPMsM26e.d.mts} +3 -3
  34. package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
  35. package/dist/storage/kysely.cjs +48 -38
  36. package/dist/storage/kysely.cjs.map +1 -1
  37. package/dist/storage/kysely.d.cts +29 -9
  38. package/dist/storage/kysely.d.cts.map +1 -1
  39. package/dist/storage/kysely.d.mts +29 -9
  40. package/dist/storage/kysely.d.mts.map +1 -1
  41. package/dist/storage/kysely.mjs +48 -38
  42. package/dist/storage/kysely.mjs.map +1 -1
  43. package/dist/tracing-PnECEbEu.d.mts.map +1 -1
  44. package/package.json +6 -3
  45. package/CHANGELOG.md +0 -72
  46. package/dist/middleware-4-GrQlOT.mjs.map +0 -1
  47. package/dist/middleware-DqPQpcup.cjs.map +0 -1
  48. package/dist/otel-40udNP5g.mjs.map +0 -1
  49. package/dist/otel-COrpz_GZ.cjs.map +0 -1
  50. package/src/Telescope.ts +0 -561
  51. package/src/__tests__/Telescope.spec.ts +0 -438
  52. package/src/__tests__/pino-transport.spec.ts +0 -115
  53. package/src/__tests__/redact.spec.ts +0 -336
  54. package/src/adapters/__tests__/lambda.spec.ts +0 -318
  55. package/src/adapters/__tests__/middy.spec.ts +0 -741
  56. package/src/adapters/index.ts +0 -22
  57. package/src/adapters/lambda.ts +0 -432
  58. package/src/adapters/middy.ts +0 -402
  59. package/src/adapters/types.ts +0 -181
  60. package/src/core.ts +0 -51
  61. package/src/index.ts +0 -34
  62. package/src/instrumentation/__tests__/core.spec.ts +0 -248
  63. package/src/instrumentation/__tests__/hono.spec.ts +0 -348
  64. package/src/instrumentation/__tests__/middleware.spec.ts +0 -528
  65. package/src/instrumentation/__tests__/otel.spec.ts +0 -291
  66. package/src/instrumentation/__tests__/tracing.spec.ts +0 -208
  67. package/src/instrumentation/core.ts +0 -228
  68. package/src/instrumentation/hono.ts +0 -270
  69. package/src/instrumentation/http.ts +0 -306
  70. package/src/instrumentation/index.ts +0 -90
  71. package/src/instrumentation/middleware.ts +0 -297
  72. package/src/instrumentation/otel.ts +0 -271
  73. package/src/instrumentation/setup.ts +0 -246
  74. package/src/instrumentation/tracing.ts +0 -145
  75. package/src/logger/__tests__/console.spec.ts +0 -366
  76. package/src/logger/__tests__/pino.spec.ts +0 -217
  77. package/src/logger/console.ts +0 -230
  78. package/src/logger/pino.ts +0 -201
  79. package/src/metrics/MetricsAggregator.ts +0 -555
  80. package/src/metrics/__tests__/MetricsAggregator.spec.ts +0 -298
  81. package/src/metrics/index.ts +0 -2
  82. package/src/metrics/storage/InMemoryMetricsStorage.ts +0 -380
  83. package/src/metrics/storage/MetricsStorage.ts +0 -74
  84. package/src/metrics/storage/index.ts +0 -3
  85. package/src/metrics/storage/types.ts +0 -243
  86. package/src/otlp/__tests__/receiver.spec.ts +0 -367
  87. package/src/otlp/__tests__/transformer.spec.ts +0 -455
  88. package/src/otlp/hono.ts +0 -120
  89. package/src/otlp/index.ts +0 -22
  90. package/src/otlp/receiver.ts +0 -162
  91. package/src/otlp/transformer.ts +0 -367
  92. package/src/otlp/types.ts +0 -364
  93. package/src/redact.ts +0 -116
  94. package/src/server/__tests__/hono.spec.ts +0 -814
  95. package/src/server/hono.ts +0 -442
  96. package/src/storage/__tests__/kysely.spec.ts +0 -715
  97. package/src/storage/__tests__/memory.spec.ts +0 -694
  98. package/src/storage/kysely.ts +0 -599
  99. package/src/storage/memory.ts +0 -204
  100. package/src/types.ts +0 -447
  101. package/src/ui-assets.ts +0 -40
  102. package/tsconfig.json +0 -9
  103. package/ui/CHANGELOG.md +0 -7
  104. package/ui/index.html +0 -12
  105. package/ui/node_modules/.bin/tsc +0 -21
  106. package/ui/node_modules/.bin/tsserver +0 -21
  107. package/ui/node_modules/.bin/vite +0 -21
  108. package/ui/package.json +0 -24
  109. package/ui/src/App.tsx +0 -595
  110. package/ui/src/api.ts +0 -88
  111. package/ui/src/components/ExceptionDetail.tsx +0 -100
  112. package/ui/src/components/FilterBar.tsx +0 -162
  113. package/ui/src/components/LogDetail.tsx +0 -91
  114. package/ui/src/components/RequestDetail.tsx +0 -143
  115. package/ui/src/main.tsx +0 -10
  116. package/ui/src/styles.css +0 -11
  117. package/ui/src/types.ts +0 -63
  118. package/ui/src/vite-env.d.ts +0 -1
  119. package/ui/src/vite-plugin-gkm-config.ts +0 -54
  120. package/ui/tsconfig.json +0 -20
  121. package/ui/tsconfig.tsbuildinfo +0 -1
  122. package/ui/vite.config.ts +0 -13
@@ -1,528 +0,0 @@
1
- import { trace } from '@opentelemetry/api';
2
- import {
3
- BasicTracerProvider,
4
- InMemorySpanExporter,
5
- SimpleSpanProcessor,
6
- } from '@opentelemetry/sdk-trace-base';
7
- import type { Context as LambdaContext } from 'aws-lambda';
8
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
9
- import {
10
- getContextFromEvent,
11
- getSpanFromEvent,
12
- telemetryMiddleware,
13
- withEventContext,
14
- } from '../middleware';
15
-
16
- describe('telemetryMiddleware', () => {
17
- let mockContext: LambdaContext;
18
- let middleware: ReturnType<typeof telemetryMiddleware>;
19
- let exporter: InMemorySpanExporter;
20
- let provider: BasicTracerProvider;
21
-
22
- beforeEach(() => {
23
- // Set up real OpenTelemetry with in-memory exporter
24
- exporter = new InMemorySpanExporter();
25
- provider = new BasicTracerProvider();
26
- provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
27
- provider.register();
28
-
29
- mockContext = {
30
- callbackWaitsForEmptyEventLoop: true,
31
- functionName: 'test-function',
32
- functionVersion: '1',
33
- invokedFunctionArn: 'arn:aws:lambda:us-east-1:123456789:function:test',
34
- memoryLimitInMB: '256',
35
- awsRequestId: 'test-request-id-123',
36
- logGroupName: '/aws/lambda/test',
37
- logStreamName: '2024/01/01/[$LATEST]abc123',
38
- getRemainingTimeInMillis: () => 10000,
39
- done: vi.fn(),
40
- fail: vi.fn(),
41
- succeed: vi.fn(),
42
- };
43
-
44
- middleware = telemetryMiddleware();
45
- });
46
-
47
- afterEach(async () => {
48
- exporter.reset();
49
- await provider.shutdown();
50
- // Reset global tracer provider
51
- trace.disable();
52
- });
53
-
54
- describe('before hook', () => {
55
- it('should create span for API Gateway v2 event', async () => {
56
- const event = {
57
- rawPath: '/api/users',
58
- headers: {
59
- host: 'api.example.com',
60
- 'content-type': 'application/json',
61
- },
62
- requestContext: {
63
- requestId: 'req-123',
64
- http: {
65
- method: 'POST',
66
- sourceIp: '192.168.1.1',
67
- userAgent: 'test-agent',
68
- path: '/api/users',
69
- },
70
- },
71
- body: JSON.stringify({ name: 'John' }),
72
- routeKey: 'POST /api/users',
73
- };
74
-
75
- const request = { event, context: mockContext, response: null };
76
- await middleware.before?.(request as any);
77
-
78
- // Span should be stored on event
79
- const span = getSpanFromEvent(event);
80
- expect(span).toBeDefined();
81
- expect(getContextFromEvent(event)).toBeDefined();
82
-
83
- // End span to export it
84
- const response = { statusCode: 201, body: '{"id":"123"}' };
85
- await middleware.after?.({
86
- event,
87
- context: mockContext,
88
- response,
89
- } as any);
90
-
91
- // Check exported spans
92
- const spans = exporter.getFinishedSpans();
93
- expect(spans).toHaveLength(1);
94
- expect(spans[0].name).toBe('POST /api/users');
95
- expect(spans[0].attributes['http.request.method']).toBe('POST');
96
- expect(spans[0].attributes['url.path']).toBe('/api/users');
97
- expect(spans[0].attributes['client.address']).toBe('192.168.1.1');
98
- });
99
-
100
- it('should create span for API Gateway v1 event', async () => {
101
- const event = {
102
- httpMethod: 'GET',
103
- path: '/api/items',
104
- headers: {
105
- Host: 'api.example.com',
106
- 'User-Agent': 'test-agent',
107
- },
108
- requestContext: {
109
- requestId: 'req-456',
110
- identity: {
111
- sourceIp: '10.0.0.1',
112
- },
113
- },
114
- resource: '/api/items/{id}',
115
- queryStringParameters: { page: '1' },
116
- };
117
-
118
- const request = { event, context: mockContext, response: null };
119
- await middleware.before?.(request as any);
120
-
121
- expect(getSpanFromEvent(event)).toBeDefined();
122
-
123
- await middleware.after?.({
124
- event,
125
- context: mockContext,
126
- response: { statusCode: 200 },
127
- } as any);
128
-
129
- const spans = exporter.getFinishedSpans();
130
- expect(spans).toHaveLength(1);
131
- expect(spans[0].name).toBe('GET /api/items/{id}');
132
- expect(spans[0].attributes['http.request.method']).toBe('GET');
133
- expect(spans[0].attributes['http.route']).toBe('/api/items/{id}');
134
- });
135
-
136
- it('should handle generic Lambda invocation', async () => {
137
- const event = {
138
- customField: 'value',
139
- headers: {},
140
- };
141
-
142
- const request = { event, context: mockContext, response: null };
143
- await middleware.before?.(request as any);
144
-
145
- expect(getSpanFromEvent(event)).toBeDefined();
146
-
147
- await middleware.after?.({
148
- event,
149
- context: mockContext,
150
- response: { statusCode: 200 },
151
- } as any);
152
-
153
- const spans = exporter.getFinishedSpans();
154
- expect(spans).toHaveLength(1);
155
- expect(spans[0].attributes['http.request.method']).toBe('INVOKE');
156
- });
157
-
158
- it('should skip tracing when shouldSkip returns true', async () => {
159
- const skipMiddleware = telemetryMiddleware({
160
- shouldSkip: (event) => event.skipTrace === true,
161
- });
162
-
163
- const event = {
164
- skipTrace: true,
165
- headers: {},
166
- };
167
-
168
- const request = { event, context: mockContext, response: null };
169
- await skipMiddleware.before?.(request as any);
170
-
171
- expect(getSpanFromEvent(event)).toBeUndefined();
172
- expect(exporter.getFinishedSpans()).toHaveLength(0);
173
- });
174
-
175
- it('should record request body when recordBody is true', async () => {
176
- const bodyMiddleware = telemetryMiddleware({ recordBody: true });
177
- const bodyContent = JSON.stringify({
178
- name: 'John',
179
- email: 'john@example.com',
180
- });
181
-
182
- const event = {
183
- httpMethod: 'POST',
184
- path: '/api/users',
185
- headers: {},
186
- body: bodyContent,
187
- };
188
-
189
- const request = { event, context: mockContext, response: null };
190
- await bodyMiddleware.before?.(request as any);
191
- await bodyMiddleware.after?.({
192
- event,
193
- context: mockContext,
194
- response: { statusCode: 201 },
195
- } as any);
196
-
197
- const spans = exporter.getFinishedSpans();
198
- expect(spans[0].attributes['http.request.body']).toBe(bodyContent);
199
- });
200
-
201
- it('should truncate large request bodies', async () => {
202
- const bodyMiddleware = telemetryMiddleware({ recordBody: true });
203
- const largeBody = 'x'.repeat(5000);
204
-
205
- const event = {
206
- httpMethod: 'POST',
207
- path: '/api/upload',
208
- headers: {},
209
- body: largeBody,
210
- };
211
-
212
- const request = { event, context: mockContext, response: null };
213
- await bodyMiddleware.before?.(request as any);
214
- await bodyMiddleware.after?.({
215
- event,
216
- context: mockContext,
217
- response: { statusCode: 200 },
218
- } as any);
219
-
220
- const spans = exporter.getFinishedSpans();
221
- const recordedBody = spans[0].attributes['http.request.body'] as string;
222
- expect(recordedBody.length).toBeLessThan(largeBody.length);
223
- expect(recordedBody).toContain('...');
224
- });
225
-
226
- it('should add Lambda-specific attributes', async () => {
227
- const event = {
228
- httpMethod: 'GET',
229
- path: '/api/test',
230
- headers: {},
231
- };
232
-
233
- const request = { event, context: mockContext, response: null };
234
- await middleware.before?.(request as any);
235
- await middleware.after?.({
236
- event,
237
- context: mockContext,
238
- response: { statusCode: 200 },
239
- } as any);
240
-
241
- const spans = exporter.getFinishedSpans();
242
- expect(spans[0].attributes['faas.invocation_id']).toBe(
243
- 'test-request-id-123',
244
- );
245
- expect(spans[0].attributes['faas.name']).toBe('test-function');
246
- });
247
- });
248
-
249
- describe('after hook', () => {
250
- it('should record success status code', async () => {
251
- const event = {
252
- httpMethod: 'GET',
253
- path: '/api/users',
254
- headers: {},
255
- };
256
-
257
- await middleware.before?.({
258
- event,
259
- context: mockContext,
260
- response: null,
261
- } as any);
262
- await middleware.after?.({
263
- event,
264
- context: mockContext,
265
- response: { statusCode: 200, body: '{"users":[]}' },
266
- } as any);
267
-
268
- const spans = exporter.getFinishedSpans();
269
- expect(spans[0].attributes['http.response.status_code']).toBe(200);
270
- expect(spans[0].status.code).toBe(1); // SpanStatusCode.OK
271
- });
272
-
273
- it('should record 4xx status as error', async () => {
274
- const event = {
275
- httpMethod: 'GET',
276
- path: '/api/users/999',
277
- headers: {},
278
- };
279
-
280
- await middleware.before?.({
281
- event,
282
- context: mockContext,
283
- response: null,
284
- } as any);
285
- await middleware.after?.({
286
- event,
287
- context: mockContext,
288
- response: { statusCode: 404, body: '{"error":"Not found"}' },
289
- } as any);
290
-
291
- const spans = exporter.getFinishedSpans();
292
- expect(spans[0].attributes['http.response.status_code']).toBe(404);
293
- expect(spans[0].status.code).toBe(2); // SpanStatusCode.ERROR
294
- });
295
-
296
- it('should record response body when recordResponseBody is true', async () => {
297
- const responseMiddleware = telemetryMiddleware({
298
- recordResponseBody: true,
299
- });
300
- const responseBody = '{"users":[{"id":"1","name":"John"}]}';
301
-
302
- const event = {
303
- httpMethod: 'GET',
304
- path: '/api/users',
305
- headers: {},
306
- };
307
-
308
- await responseMiddleware.before?.({
309
- event,
310
- context: mockContext,
311
- response: null,
312
- } as any);
313
- await responseMiddleware.after?.({
314
- event,
315
- context: mockContext,
316
- response: { statusCode: 200, body: responseBody },
317
- } as any);
318
-
319
- const spans = exporter.getFinishedSpans();
320
- expect(spans[0].attributes['http.response.body']).toBe(responseBody);
321
- });
322
- });
323
-
324
- describe('onError hook', () => {
325
- it('should record error with exception', async () => {
326
- const event = {
327
- httpMethod: 'GET',
328
- path: '/api/error',
329
- headers: {},
330
- };
331
-
332
- await middleware.before?.({
333
- event,
334
- context: mockContext,
335
- response: null,
336
- } as any);
337
-
338
- const error = new Error('Database connection failed');
339
- await middleware.onError?.({
340
- event,
341
- context: mockContext,
342
- response: { statusCode: 500 },
343
- error,
344
- } as any);
345
-
346
- const spans = exporter.getFinishedSpans();
347
- expect(spans[0].attributes['http.response.status_code']).toBe(500);
348
- expect(spans[0].status.code).toBe(2); // SpanStatusCode.ERROR
349
- expect(spans[0].events).toHaveLength(1);
350
- expect(spans[0].events[0].name).toBe('exception');
351
- });
352
-
353
- it('should use error statusCode if available', async () => {
354
- const event = {
355
- httpMethod: 'GET',
356
- path: '/api/protected',
357
- headers: {},
358
- };
359
-
360
- await middleware.before?.({
361
- event,
362
- context: mockContext,
363
- response: null,
364
- } as any);
365
-
366
- const error = Object.assign(new Error('Forbidden'), { statusCode: 403 });
367
- await middleware.onError?.({
368
- event,
369
- context: mockContext,
370
- response: null,
371
- error,
372
- } as any);
373
-
374
- const spans = exporter.getFinishedSpans();
375
- expect(spans[0].attributes['http.response.status_code']).toBe(403);
376
- });
377
- });
378
-
379
- describe('withEventContext', () => {
380
- it('should run function within span context', async () => {
381
- const event = {
382
- httpMethod: 'GET',
383
- path: '/api/users',
384
- headers: {},
385
- };
386
-
387
- await middleware.before?.({
388
- event,
389
- context: mockContext,
390
- response: null,
391
- } as any);
392
-
393
- const result = await withEventContext(event, async () => {
394
- return 'executed-in-context';
395
- });
396
-
397
- expect(result).toBe('executed-in-context');
398
- });
399
-
400
- it('should run function normally when no context exists', async () => {
401
- const event = {};
402
-
403
- const result = await withEventContext(event, async () => {
404
- return 'executed-without-context';
405
- });
406
-
407
- expect(result).toBe('executed-without-context');
408
- });
409
- });
410
-
411
- describe('custom extractors', () => {
412
- it('should extract user ID using getUserId', async () => {
413
- const userMiddleware = telemetryMiddleware({
414
- getUserId: (event) => event.requestContext?.authorizer?.userId,
415
- });
416
-
417
- const event = {
418
- httpMethod: 'GET',
419
- path: '/api/profile',
420
- headers: {},
421
- requestContext: {
422
- authorizer: {
423
- userId: 'user-abc123',
424
- },
425
- },
426
- };
427
-
428
- await userMiddleware.before?.({
429
- event,
430
- context: mockContext,
431
- response: null,
432
- } as any);
433
- await userMiddleware.after?.({
434
- event,
435
- context: mockContext,
436
- response: { statusCode: 200 },
437
- } as any);
438
-
439
- const spans = exporter.getFinishedSpans();
440
- expect(spans[0].attributes['enduser.id']).toBe('user-abc123');
441
- });
442
-
443
- it('should extract endpoint name using getEndpointName', async () => {
444
- const endpointMiddleware = telemetryMiddleware({
445
- getEndpointName: (event) => event.endpointName,
446
- });
447
-
448
- const event = {
449
- httpMethod: 'GET',
450
- path: '/api/users',
451
- headers: {},
452
- endpointName: 'ListUsers',
453
- };
454
-
455
- await endpointMiddleware.before?.({
456
- event,
457
- context: mockContext,
458
- response: null,
459
- } as any);
460
- await endpointMiddleware.after?.({
461
- event,
462
- context: mockContext,
463
- response: { statusCode: 200 },
464
- } as any);
465
-
466
- const spans = exporter.getFinishedSpans();
467
- expect(spans[0].attributes['endpoint.name']).toBe('ListUsers');
468
- });
469
-
470
- it('should extract operation ID using getOperationId', async () => {
471
- const opMiddleware = telemetryMiddleware({
472
- getOperationId: (event) => event.operationId,
473
- });
474
-
475
- const event = {
476
- httpMethod: 'POST',
477
- path: '/api/orders',
478
- headers: {},
479
- operationId: 'createOrder',
480
- };
481
-
482
- await opMiddleware.before?.({
483
- event,
484
- context: mockContext,
485
- response: null,
486
- } as any);
487
- await opMiddleware.after?.({
488
- event,
489
- context: mockContext,
490
- response: { statusCode: 201 },
491
- } as any);
492
-
493
- const spans = exporter.getFinishedSpans();
494
- expect(spans[0].attributes['endpoint.operation_id']).toBe('createOrder');
495
- });
496
- });
497
-
498
- describe('trace context propagation', () => {
499
- it('should extract trace context from traceparent header', async () => {
500
- const traceId = '0af7651916cd43dd8448eb211c80319c';
501
- const parentSpanId = 'b7ad6b7169203331';
502
-
503
- const event = {
504
- httpMethod: 'GET',
505
- path: '/api/downstream',
506
- headers: {
507
- traceparent: `00-${traceId}-${parentSpanId}-01`,
508
- },
509
- };
510
-
511
- await middleware.before?.({
512
- event,
513
- context: mockContext,
514
- response: null,
515
- } as any);
516
- await middleware.after?.({
517
- event,
518
- context: mockContext,
519
- response: { statusCode: 200 },
520
- } as any);
521
-
522
- const spans = exporter.getFinishedSpans();
523
- expect(spans).toHaveLength(1);
524
- // The span should be created (even if not linked to parent in this basic setup)
525
- expect(spans[0].name).toContain('GET');
526
- });
527
- });
528
- });