@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.
- package/README.md +14 -4
- package/dist/{http-D5kn3_Mt.d.mts → http-BiNtg85L.d.mts} +3 -3
- package/dist/{http-D5kn3_Mt.d.mts.map → http-BiNtg85L.d.mts.map} +1 -1
- package/dist/instrumentation/http.d.mts +1 -1
- package/dist/instrumentation/index.cjs +2 -2
- package/dist/instrumentation/index.d.cts +2 -2
- package/dist/instrumentation/index.d.mts +3 -3
- package/dist/instrumentation/index.mjs +2 -2
- package/dist/instrumentation/middleware.cjs +1 -1
- package/dist/instrumentation/middleware.d.cts +1 -1
- package/dist/instrumentation/middleware.d.mts +1 -1
- package/dist/instrumentation/middleware.mjs +1 -1
- package/dist/instrumentation/otel.cjs +1 -1
- package/dist/instrumentation/otel.d.cts +1 -1
- package/dist/instrumentation/otel.d.mts +1 -1
- package/dist/instrumentation/otel.mjs +1 -1
- package/dist/logger/console.d.cts.map +1 -1
- package/dist/logger/pino.d.mts +2 -2
- package/dist/{middleware-DqPQpcup.cjs → middleware-Bcq6XXGG.cjs} +2 -2
- package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
- package/dist/{middleware-4-GrQlOT.mjs → middleware-D1XEHvyy.mjs} +2 -2
- package/dist/middleware-D1XEHvyy.mjs.map +1 -0
- package/dist/{middleware-CA84nsNN.d.cts → middleware-PeyS-9Ny.d.cts} +2 -2
- package/dist/{middleware-CA84nsNN.d.cts.map → middleware-PeyS-9Ny.d.cts.map} +1 -1
- package/dist/{middleware-DAceVpfw.d.mts → middleware-oHvo_ZgU.d.mts} +2 -2
- package/dist/{middleware-DAceVpfw.d.mts.map → middleware-oHvo_ZgU.d.mts.map} +1 -1
- package/dist/{otel-40udNP5g.mjs → otel-B9bNoeZ2.mjs} +3 -3
- package/dist/otel-B9bNoeZ2.mjs.map +1 -0
- package/dist/{otel-SBVoVEHr.d.cts → otel-Bk89b1lX.d.cts} +3 -3
- package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
- package/dist/{otel-COrpz_GZ.cjs → otel-BzjOtVxZ.cjs} +3 -3
- package/dist/otel-BzjOtVxZ.cjs.map +1 -0
- package/dist/{otel-1bJPb2Z7.d.mts → otel-lPMsM26e.d.mts} +3 -3
- package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
- package/dist/storage/kysely.cjs +48 -38
- package/dist/storage/kysely.cjs.map +1 -1
- package/dist/storage/kysely.d.cts +29 -9
- package/dist/storage/kysely.d.cts.map +1 -1
- package/dist/storage/kysely.d.mts +29 -9
- package/dist/storage/kysely.d.mts.map +1 -1
- package/dist/storage/kysely.mjs +48 -38
- package/dist/storage/kysely.mjs.map +1 -1
- package/dist/tracing-PnECEbEu.d.mts.map +1 -1
- package/package.json +6 -3
- package/CHANGELOG.md +0 -72
- package/dist/middleware-4-GrQlOT.mjs.map +0 -1
- package/dist/middleware-DqPQpcup.cjs.map +0 -1
- package/dist/otel-40udNP5g.mjs.map +0 -1
- package/dist/otel-COrpz_GZ.cjs.map +0 -1
- package/src/Telescope.ts +0 -561
- package/src/__tests__/Telescope.spec.ts +0 -438
- package/src/__tests__/pino-transport.spec.ts +0 -115
- package/src/__tests__/redact.spec.ts +0 -336
- package/src/adapters/__tests__/lambda.spec.ts +0 -318
- package/src/adapters/__tests__/middy.spec.ts +0 -741
- package/src/adapters/index.ts +0 -22
- package/src/adapters/lambda.ts +0 -432
- package/src/adapters/middy.ts +0 -402
- package/src/adapters/types.ts +0 -181
- package/src/core.ts +0 -51
- package/src/index.ts +0 -34
- package/src/instrumentation/__tests__/core.spec.ts +0 -248
- package/src/instrumentation/__tests__/hono.spec.ts +0 -348
- package/src/instrumentation/__tests__/middleware.spec.ts +0 -528
- package/src/instrumentation/__tests__/otel.spec.ts +0 -291
- package/src/instrumentation/__tests__/tracing.spec.ts +0 -208
- package/src/instrumentation/core.ts +0 -228
- package/src/instrumentation/hono.ts +0 -270
- package/src/instrumentation/http.ts +0 -306
- package/src/instrumentation/index.ts +0 -90
- package/src/instrumentation/middleware.ts +0 -297
- package/src/instrumentation/otel.ts +0 -271
- package/src/instrumentation/setup.ts +0 -246
- package/src/instrumentation/tracing.ts +0 -145
- package/src/logger/__tests__/console.spec.ts +0 -366
- package/src/logger/__tests__/pino.spec.ts +0 -217
- package/src/logger/console.ts +0 -230
- package/src/logger/pino.ts +0 -201
- package/src/metrics/MetricsAggregator.ts +0 -555
- package/src/metrics/__tests__/MetricsAggregator.spec.ts +0 -298
- package/src/metrics/index.ts +0 -2
- package/src/metrics/storage/InMemoryMetricsStorage.ts +0 -380
- package/src/metrics/storage/MetricsStorage.ts +0 -74
- package/src/metrics/storage/index.ts +0 -3
- package/src/metrics/storage/types.ts +0 -243
- package/src/otlp/__tests__/receiver.spec.ts +0 -367
- package/src/otlp/__tests__/transformer.spec.ts +0 -455
- package/src/otlp/hono.ts +0 -120
- package/src/otlp/index.ts +0 -22
- package/src/otlp/receiver.ts +0 -162
- package/src/otlp/transformer.ts +0 -367
- package/src/otlp/types.ts +0 -364
- package/src/redact.ts +0 -116
- package/src/server/__tests__/hono.spec.ts +0 -814
- package/src/server/hono.ts +0 -442
- package/src/storage/__tests__/kysely.spec.ts +0 -715
- package/src/storage/__tests__/memory.spec.ts +0 -694
- package/src/storage/kysely.ts +0 -599
- package/src/storage/memory.ts +0 -204
- package/src/types.ts +0 -447
- package/src/ui-assets.ts +0 -40
- package/tsconfig.json +0 -9
- package/ui/CHANGELOG.md +0 -7
- package/ui/index.html +0 -12
- package/ui/node_modules/.bin/tsc +0 -21
- package/ui/node_modules/.bin/tsserver +0 -21
- package/ui/node_modules/.bin/vite +0 -21
- package/ui/package.json +0 -24
- package/ui/src/App.tsx +0 -595
- package/ui/src/api.ts +0 -88
- package/ui/src/components/ExceptionDetail.tsx +0 -100
- package/ui/src/components/FilterBar.tsx +0 -162
- package/ui/src/components/LogDetail.tsx +0 -91
- package/ui/src/components/RequestDetail.tsx +0 -143
- package/ui/src/main.tsx +0 -10
- package/ui/src/styles.css +0 -11
- package/ui/src/types.ts +0 -63
- package/ui/src/vite-env.d.ts +0 -1
- package/ui/src/vite-plugin-gkm-config.ts +0 -54
- package/ui/tsconfig.json +0 -20
- package/ui/tsconfig.tsbuildinfo +0 -1
- package/ui/vite.config.ts +0 -13
|
@@ -1,291 +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 } from 'aws-lambda';
|
|
8
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
9
|
-
import { OTelTelemetry } from '../otel';
|
|
10
|
-
|
|
11
|
-
describe('OTelTelemetry', () => {
|
|
12
|
-
let exporter: InMemorySpanExporter;
|
|
13
|
-
let provider: BasicTracerProvider;
|
|
14
|
-
|
|
15
|
-
const mockLambdaContext: Context = {
|
|
16
|
-
awsRequestId: 'test-request-id',
|
|
17
|
-
functionName: 'test-function',
|
|
18
|
-
functionVersion: '1',
|
|
19
|
-
invokedFunctionArn: 'arn:aws:lambda:us-east-1:123456789:function:test',
|
|
20
|
-
memoryLimitInMB: '128',
|
|
21
|
-
logGroupName: '/aws/lambda/test',
|
|
22
|
-
logStreamName: '2024/01/01/[$LATEST]abc123',
|
|
23
|
-
callbackWaitsForEmptyEventLoop: true,
|
|
24
|
-
getRemainingTimeInMillis: () => 30000,
|
|
25
|
-
done: () => {},
|
|
26
|
-
fail: () => {},
|
|
27
|
-
succeed: () => {},
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
exporter = new InMemorySpanExporter();
|
|
32
|
-
provider = new BasicTracerProvider();
|
|
33
|
-
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
|
|
34
|
-
provider.register();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
afterEach(async () => {
|
|
38
|
-
exporter.reset();
|
|
39
|
-
await provider.shutdown();
|
|
40
|
-
trace.disable();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
describe('API Gateway v2 events', () => {
|
|
44
|
-
it('should create span for API Gateway v2 request', () => {
|
|
45
|
-
const telemetry = new OTelTelemetry();
|
|
46
|
-
|
|
47
|
-
const event = {
|
|
48
|
-
requestContext: {
|
|
49
|
-
http: {
|
|
50
|
-
method: 'GET',
|
|
51
|
-
path: '/api/users',
|
|
52
|
-
sourceIp: '192.168.1.1',
|
|
53
|
-
userAgent: 'test-agent',
|
|
54
|
-
},
|
|
55
|
-
requestId: 'apigw-request-id',
|
|
56
|
-
},
|
|
57
|
-
rawPath: '/api/users',
|
|
58
|
-
rawQueryString: 'page=1',
|
|
59
|
-
headers: { host: 'api.example.com' },
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const ctx = telemetry.onRequestStart({
|
|
63
|
-
event,
|
|
64
|
-
context: mockLambdaContext,
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
telemetry.onRequestEnd(ctx, { statusCode: 200 });
|
|
68
|
-
|
|
69
|
-
const spans = exporter.getFinishedSpans();
|
|
70
|
-
expect(spans).toHaveLength(1);
|
|
71
|
-
expect(spans[0].name).toBe('GET /api/users');
|
|
72
|
-
expect(spans[0].attributes['http.request.method']).toBe('GET');
|
|
73
|
-
expect(spans[0].attributes['url.path']).toBe('/api/users');
|
|
74
|
-
expect(spans[0].attributes['faas.invocation_id']).toBe('test-request-id');
|
|
75
|
-
expect(spans[0].attributes['faas.name']).toBe('test-function');
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('should record error on request failure', () => {
|
|
79
|
-
const telemetry = new OTelTelemetry();
|
|
80
|
-
|
|
81
|
-
const event = {
|
|
82
|
-
requestContext: {
|
|
83
|
-
http: { method: 'POST', path: '/api/users', sourceIp: '10.0.0.1' },
|
|
84
|
-
requestId: 'req-123',
|
|
85
|
-
},
|
|
86
|
-
rawPath: '/api/users',
|
|
87
|
-
headers: {},
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const ctx = telemetry.onRequestStart({
|
|
91
|
-
event,
|
|
92
|
-
context: mockLambdaContext,
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
telemetry.onRequestError(ctx, new Error('Database connection failed'));
|
|
96
|
-
|
|
97
|
-
const spans = exporter.getFinishedSpans();
|
|
98
|
-
expect(spans).toHaveLength(1);
|
|
99
|
-
expect(spans[0].status.code).toBe(2); // SpanStatusCode.ERROR
|
|
100
|
-
expect(spans[0].events).toHaveLength(1);
|
|
101
|
-
expect(spans[0].events[0].name).toBe('exception');
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
describe('API Gateway v1 events', () => {
|
|
106
|
-
it('should create span for API Gateway v1 request', () => {
|
|
107
|
-
const telemetry = new OTelTelemetry();
|
|
108
|
-
|
|
109
|
-
const event = {
|
|
110
|
-
httpMethod: 'POST',
|
|
111
|
-
path: '/api/orders',
|
|
112
|
-
resource: '/api/orders',
|
|
113
|
-
requestContext: {
|
|
114
|
-
requestId: 'v1-request-id',
|
|
115
|
-
identity: { sourceIp: '10.0.0.1' },
|
|
116
|
-
},
|
|
117
|
-
headers: {
|
|
118
|
-
Host: 'api.example.com',
|
|
119
|
-
'User-Agent': 'test-client',
|
|
120
|
-
},
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const ctx = telemetry.onRequestStart({
|
|
124
|
-
event,
|
|
125
|
-
context: mockLambdaContext,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
telemetry.onRequestEnd(ctx, { statusCode: 201 });
|
|
129
|
-
|
|
130
|
-
const spans = exporter.getFinishedSpans();
|
|
131
|
-
expect(spans).toHaveLength(1);
|
|
132
|
-
expect(spans[0].attributes['http.request.method']).toBe('POST');
|
|
133
|
-
expect(spans[0].attributes['url.path']).toBe('/api/orders');
|
|
134
|
-
expect(spans[0].attributes['http.route']).toBe('/api/orders');
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
describe('options', () => {
|
|
139
|
-
it('should record request body when recordBody is true', () => {
|
|
140
|
-
const telemetry = new OTelTelemetry({ recordBody: true });
|
|
141
|
-
|
|
142
|
-
const event = {
|
|
143
|
-
requestContext: {
|
|
144
|
-
http: { method: 'POST', path: '/api/users', sourceIp: '10.0.0.1' },
|
|
145
|
-
requestId: 'req-123',
|
|
146
|
-
},
|
|
147
|
-
rawPath: '/api/users',
|
|
148
|
-
headers: {},
|
|
149
|
-
body: JSON.stringify({ name: 'John', email: 'john@example.com' }),
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const ctx = telemetry.onRequestStart({
|
|
153
|
-
event,
|
|
154
|
-
context: mockLambdaContext,
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
telemetry.onRequestEnd(ctx, { statusCode: 200 });
|
|
158
|
-
|
|
159
|
-
const spans = exporter.getFinishedSpans();
|
|
160
|
-
expect(spans[0].attributes['http.request.body']).toContain('John');
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('should record response body when recordResponseBody is true', () => {
|
|
164
|
-
const telemetry = new OTelTelemetry({ recordResponseBody: true });
|
|
165
|
-
|
|
166
|
-
const event = {
|
|
167
|
-
requestContext: {
|
|
168
|
-
http: { method: 'GET', path: '/api/users', sourceIp: '10.0.0.1' },
|
|
169
|
-
requestId: 'req-123',
|
|
170
|
-
},
|
|
171
|
-
rawPath: '/api/users',
|
|
172
|
-
headers: {},
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
const ctx = telemetry.onRequestStart({
|
|
176
|
-
event,
|
|
177
|
-
context: mockLambdaContext,
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
telemetry.onRequestEnd(ctx, {
|
|
181
|
-
statusCode: 200,
|
|
182
|
-
body: JSON.stringify({ users: [{ id: '1', name: 'John' }] }),
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
const spans = exporter.getFinishedSpans();
|
|
186
|
-
expect(spans[0].attributes['http.response.body']).toContain('John');
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it('should extract user ID using custom function', () => {
|
|
190
|
-
const telemetry = new OTelTelemetry({
|
|
191
|
-
getUserId: (event) => event.requestContext?.authorizer?.userId,
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
const event = {
|
|
195
|
-
requestContext: {
|
|
196
|
-
http: { method: 'GET', path: '/api/profile', sourceIp: '10.0.0.1' },
|
|
197
|
-
requestId: 'req-123',
|
|
198
|
-
authorizer: { userId: 'user-456' },
|
|
199
|
-
},
|
|
200
|
-
rawPath: '/api/profile',
|
|
201
|
-
headers: {},
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
const ctx = telemetry.onRequestStart({
|
|
205
|
-
event,
|
|
206
|
-
context: mockLambdaContext,
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
telemetry.onRequestEnd(ctx, { statusCode: 200 });
|
|
210
|
-
|
|
211
|
-
const spans = exporter.getFinishedSpans();
|
|
212
|
-
expect(spans[0].attributes['enduser.id']).toBe('user-456');
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it('should extract endpoint name using custom function', () => {
|
|
216
|
-
const telemetry = new OTelTelemetry({
|
|
217
|
-
getEndpointName: (event) => event.endpointName,
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const event = {
|
|
221
|
-
requestContext: {
|
|
222
|
-
http: { method: 'GET', path: '/api/users', sourceIp: '10.0.0.1' },
|
|
223
|
-
requestId: 'req-123',
|
|
224
|
-
},
|
|
225
|
-
rawPath: '/api/users',
|
|
226
|
-
headers: {},
|
|
227
|
-
endpointName: 'ListUsers',
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
const ctx = telemetry.onRequestStart({
|
|
231
|
-
event,
|
|
232
|
-
context: mockLambdaContext,
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
telemetry.onRequestEnd(ctx, { statusCode: 200 });
|
|
236
|
-
|
|
237
|
-
const spans = exporter.getFinishedSpans();
|
|
238
|
-
expect(spans[0].attributes['endpoint.name']).toBe('ListUsers');
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
describe('ALB events', () => {
|
|
243
|
-
it('should create span for ALB request', () => {
|
|
244
|
-
const telemetry = new OTelTelemetry();
|
|
245
|
-
|
|
246
|
-
const event = {
|
|
247
|
-
httpMethod: 'GET',
|
|
248
|
-
path: '/health',
|
|
249
|
-
headers: {
|
|
250
|
-
host: 'alb.example.com',
|
|
251
|
-
'user-agent': 'ALB-HealthChecker',
|
|
252
|
-
'x-forwarded-for': '10.0.0.1, 10.0.0.2',
|
|
253
|
-
},
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
const ctx = telemetry.onRequestStart({
|
|
257
|
-
event,
|
|
258
|
-
context: mockLambdaContext,
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
telemetry.onRequestEnd(ctx, { statusCode: 200 });
|
|
262
|
-
|
|
263
|
-
const spans = exporter.getFinishedSpans();
|
|
264
|
-
expect(spans).toHaveLength(1);
|
|
265
|
-
expect(spans[0].attributes['http.request.method']).toBe('GET');
|
|
266
|
-
expect(spans[0].attributes['url.path']).toBe('/health');
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
describe('direct Lambda invocation', () => {
|
|
271
|
-
it('should create span for direct invocation', () => {
|
|
272
|
-
const telemetry = new OTelTelemetry();
|
|
273
|
-
|
|
274
|
-
const event = {
|
|
275
|
-
action: 'processJob',
|
|
276
|
-
data: { jobId: '123' },
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
const ctx = telemetry.onRequestStart({
|
|
280
|
-
event,
|
|
281
|
-
context: mockLambdaContext,
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
telemetry.onRequestEnd(ctx, { statusCode: 200 });
|
|
285
|
-
|
|
286
|
-
const spans = exporter.getFinishedSpans();
|
|
287
|
-
expect(spans).toHaveLength(1);
|
|
288
|
-
expect(spans[0].attributes['http.request.method']).toBe('INVOKE');
|
|
289
|
-
});
|
|
290
|
-
});
|
|
291
|
-
});
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { trace } from '@opentelemetry/api';
|
|
2
|
-
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
|
|
3
|
-
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
4
|
-
import {
|
|
5
|
-
addSpanEvent,
|
|
6
|
-
createSpan,
|
|
7
|
-
getActiveSpan,
|
|
8
|
-
getSpanId,
|
|
9
|
-
getTraceId,
|
|
10
|
-
recordException,
|
|
11
|
-
setSpanAttributes,
|
|
12
|
-
withSpan,
|
|
13
|
-
withSpanSync,
|
|
14
|
-
} from '../tracing';
|
|
15
|
-
|
|
16
|
-
describe('Tracing Utilities', () => {
|
|
17
|
-
let provider: NodeTracerProvider;
|
|
18
|
-
|
|
19
|
-
beforeAll(() => {
|
|
20
|
-
// Register a real tracer provider for tests
|
|
21
|
-
provider = new NodeTracerProvider();
|
|
22
|
-
provider.register();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
afterAll(async () => {
|
|
26
|
-
await provider.shutdown();
|
|
27
|
-
// Reset to default noop provider
|
|
28
|
-
trace.disable();
|
|
29
|
-
});
|
|
30
|
-
describe('createSpan', () => {
|
|
31
|
-
it('should create a new span', () => {
|
|
32
|
-
const span = createSpan('test-span');
|
|
33
|
-
expect(span).toBeDefined();
|
|
34
|
-
expect(span.spanContext().spanId).toBeDefined();
|
|
35
|
-
span.end();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should create span with attributes', () => {
|
|
39
|
-
const span = createSpan('test-span-attrs', { 'test.attr': 'value' });
|
|
40
|
-
expect(span).toBeDefined();
|
|
41
|
-
span.end();
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
describe('withSpan', () => {
|
|
46
|
-
it('should execute function within span context', async () => {
|
|
47
|
-
const result = await withSpan('async-operation', async (span) => {
|
|
48
|
-
expect(span).toBeDefined();
|
|
49
|
-
expect(span.spanContext().spanId).toBeDefined();
|
|
50
|
-
return 'result';
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
expect(result).toBe('result');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should propagate errors', async () => {
|
|
57
|
-
await expect(
|
|
58
|
-
withSpan('error-span', async () => {
|
|
59
|
-
throw new Error('Test error');
|
|
60
|
-
}),
|
|
61
|
-
).rejects.toThrow('Test error');
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('should pass attributes to span', async () => {
|
|
65
|
-
let spanReceived = false;
|
|
66
|
-
await withSpan(
|
|
67
|
-
'attr-span',
|
|
68
|
-
async (span) => {
|
|
69
|
-
spanReceived = true;
|
|
70
|
-
expect(span).toBeDefined();
|
|
71
|
-
return 'done';
|
|
72
|
-
},
|
|
73
|
-
{ 'custom.attr': 123 },
|
|
74
|
-
);
|
|
75
|
-
expect(spanReceived).toBe(true);
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
describe('withSpanSync', () => {
|
|
80
|
-
it('should execute synchronous function within span context', () => {
|
|
81
|
-
const result = withSpanSync('sync-operation', (span) => {
|
|
82
|
-
expect(span).toBeDefined();
|
|
83
|
-
return 42;
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
expect(result).toBe(42);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('should handle errors in sync functions', () => {
|
|
90
|
-
expect(() =>
|
|
91
|
-
withSpanSync('sync-error', () => {
|
|
92
|
-
throw new Error('Sync error');
|
|
93
|
-
}),
|
|
94
|
-
).toThrow('Sync error');
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
describe('getActiveSpan', () => {
|
|
99
|
-
it('should return active span within withSpan', async () => {
|
|
100
|
-
await withSpan('active-span', async () => {
|
|
101
|
-
const active = getActiveSpan();
|
|
102
|
-
expect(active).toBeDefined();
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
describe('getTraceId and getSpanId', () => {
|
|
108
|
-
it('should return trace and span IDs within span context', async () => {
|
|
109
|
-
let traceId: string | undefined;
|
|
110
|
-
let spanId: string | undefined;
|
|
111
|
-
|
|
112
|
-
await withSpan('id-span', async (span) => {
|
|
113
|
-
traceId = getTraceId();
|
|
114
|
-
spanId = getSpanId();
|
|
115
|
-
// Verify they match the span we're in
|
|
116
|
-
expect(traceId).toBe(span.spanContext().traceId);
|
|
117
|
-
expect(spanId).toBe(span.spanContext().spanId);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
expect(traceId).toBeDefined();
|
|
121
|
-
expect(traceId?.length).toBe(32); // 16 bytes hex
|
|
122
|
-
expect(spanId).toBeDefined();
|
|
123
|
-
expect(spanId?.length).toBe(16); // 8 bytes hex
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('should return undefined outside span context', () => {
|
|
127
|
-
// Outside of any span context
|
|
128
|
-
const traceId = getTraceId();
|
|
129
|
-
const spanId = getSpanId();
|
|
130
|
-
// These may be undefined if no span is active
|
|
131
|
-
expect(traceId === undefined || typeof traceId === 'string').toBe(true);
|
|
132
|
-
expect(spanId === undefined || typeof spanId === 'string').toBe(true);
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
describe('setSpanAttributes', () => {
|
|
137
|
-
it('should set attributes on active span', async () => {
|
|
138
|
-
await withSpan('attrs-span', async (span) => {
|
|
139
|
-
setSpanAttributes({ 'custom.key': 'custom-value', 'custom.num': 42 });
|
|
140
|
-
// Span should still be valid
|
|
141
|
-
expect(span.isRecording()).toBe(true);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('should not throw when no active span', () => {
|
|
146
|
-
// Should not throw even when called outside span context
|
|
147
|
-
expect(() => {
|
|
148
|
-
setSpanAttributes({ key: 'value' });
|
|
149
|
-
}).not.toThrow();
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
describe('recordException', () => {
|
|
154
|
-
it('should record exception on active span', async () => {
|
|
155
|
-
await withSpan('exception-span', async () => {
|
|
156
|
-
const error = new Error('Test exception');
|
|
157
|
-
recordException(error);
|
|
158
|
-
// Should not throw
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('should not throw when no active span', () => {
|
|
163
|
-
expect(() => {
|
|
164
|
-
recordException(new Error('No span error'));
|
|
165
|
-
}).not.toThrow();
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
describe('addSpanEvent', () => {
|
|
170
|
-
it('should add event to active span', async () => {
|
|
171
|
-
await withSpan('event-span', async () => {
|
|
172
|
-
addSpanEvent('test.event', { detail: 'some detail' });
|
|
173
|
-
// Should not throw
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('should add event without attributes', async () => {
|
|
178
|
-
await withSpan('event-span-simple', async () => {
|
|
179
|
-
addSpanEvent('simple.event');
|
|
180
|
-
// Should not throw
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it('should not throw when no active span', () => {
|
|
185
|
-
expect(() => {
|
|
186
|
-
addSpanEvent('orphan.event', { data: 123 });
|
|
187
|
-
}).not.toThrow();
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
describe('error handling edge cases', () => {
|
|
192
|
-
it('should handle non-Error exceptions in withSpan', async () => {
|
|
193
|
-
await expect(
|
|
194
|
-
withSpan('string-error-span', async () => {
|
|
195
|
-
throw 'string error'; // Non-Error exception
|
|
196
|
-
}),
|
|
197
|
-
).rejects.toBe('string error');
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it('should handle non-Error exceptions in withSpanSync', () => {
|
|
201
|
-
expect(() =>
|
|
202
|
-
withSpanSync('sync-string-error', () => {
|
|
203
|
-
throw 'sync string error';
|
|
204
|
-
}),
|
|
205
|
-
).toThrow();
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
});
|