@geekmidas/telescope 9.0.2 → 10.0.0-alpha.0

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 (128) hide show
  1. package/README.md +14 -4
  2. package/dist/{http-D5kn3_Mt.d.mts → http-DULM1u2L.d.cts} +3 -3
  3. package/dist/{http-Dvca6fC3.d.cts.map → http-DULM1u2L.d.cts.map} +1 -1
  4. package/dist/{http-Dvca6fC3.d.cts → http-GB-Nlvwc.d.mts} +3 -3
  5. package/dist/{http-D5kn3_Mt.d.mts.map → http-GB-Nlvwc.d.mts.map} +1 -1
  6. package/dist/instrumentation/http.d.cts +1 -1
  7. package/dist/instrumentation/http.d.mts +1 -1
  8. package/dist/instrumentation/index.cjs +2 -2
  9. package/dist/instrumentation/index.d.cts +3 -3
  10. package/dist/instrumentation/index.d.mts +3 -3
  11. package/dist/instrumentation/index.mjs +2 -2
  12. package/dist/instrumentation/middleware.cjs +1 -1
  13. package/dist/instrumentation/middleware.d.cts +1 -1
  14. package/dist/instrumentation/middleware.d.mts +1 -1
  15. package/dist/instrumentation/middleware.mjs +1 -1
  16. package/dist/instrumentation/otel.cjs +1 -1
  17. package/dist/instrumentation/otel.d.cts +1 -1
  18. package/dist/instrumentation/otel.d.mts +1 -1
  19. package/dist/instrumentation/otel.mjs +1 -1
  20. package/dist/logger/console.d.cts.map +1 -1
  21. package/dist/logger/console.d.mts.map +1 -1
  22. package/dist/logger/pino.d.cts +2 -2
  23. package/dist/{middleware-DqPQpcup.cjs → middleware-Bcq6XXGG.cjs} +2 -2
  24. package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
  25. package/dist/{middleware-4-GrQlOT.mjs → middleware-D1XEHvyy.mjs} +2 -2
  26. package/dist/middleware-D1XEHvyy.mjs.map +1 -0
  27. package/dist/{middleware-CA84nsNN.d.cts → middleware-PeyS-9Ny.d.cts} +2 -2
  28. package/dist/{middleware-CA84nsNN.d.cts.map → middleware-PeyS-9Ny.d.cts.map} +1 -1
  29. package/dist/{middleware-DAceVpfw.d.mts → middleware-oHvo_ZgU.d.mts} +2 -2
  30. package/dist/{middleware-DAceVpfw.d.mts.map → middleware-oHvo_ZgU.d.mts.map} +1 -1
  31. package/dist/{otel-40udNP5g.mjs → otel-B9bNoeZ2.mjs} +3 -3
  32. package/dist/otel-B9bNoeZ2.mjs.map +1 -0
  33. package/dist/{otel-1bJPb2Z7.d.mts → otel-Bk89b1lX.d.cts} +3 -3
  34. package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
  35. package/dist/{otel-COrpz_GZ.cjs → otel-BzjOtVxZ.cjs} +3 -3
  36. package/dist/otel-BzjOtVxZ.cjs.map +1 -0
  37. package/dist/{otel-SBVoVEHr.d.cts → otel-lPMsM26e.d.mts} +3 -3
  38. package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
  39. package/dist/storage/kysely.cjs +48 -38
  40. package/dist/storage/kysely.cjs.map +1 -1
  41. package/dist/storage/kysely.d.cts +29 -9
  42. package/dist/storage/kysely.d.cts.map +1 -1
  43. package/dist/storage/kysely.d.mts +29 -9
  44. package/dist/storage/kysely.d.mts.map +1 -1
  45. package/dist/storage/kysely.mjs +48 -38
  46. package/dist/storage/kysely.mjs.map +1 -1
  47. package/dist/tracing-BX8uY2nR.d.cts.map +1 -1
  48. package/dist/types-B1EIa_cQ.d.mts.map +1 -1
  49. package/dist/types-l7Rlb5Mg.d.cts.map +1 -1
  50. package/package.json +6 -3
  51. package/CHANGELOG.md +0 -72
  52. package/dist/middleware-4-GrQlOT.mjs.map +0 -1
  53. package/dist/middleware-DqPQpcup.cjs.map +0 -1
  54. package/dist/otel-40udNP5g.mjs.map +0 -1
  55. package/dist/otel-COrpz_GZ.cjs.map +0 -1
  56. package/src/Telescope.ts +0 -561
  57. package/src/__tests__/Telescope.spec.ts +0 -438
  58. package/src/__tests__/pino-transport.spec.ts +0 -115
  59. package/src/__tests__/redact.spec.ts +0 -336
  60. package/src/adapters/__tests__/lambda.spec.ts +0 -318
  61. package/src/adapters/__tests__/middy.spec.ts +0 -741
  62. package/src/adapters/index.ts +0 -22
  63. package/src/adapters/lambda.ts +0 -432
  64. package/src/adapters/middy.ts +0 -402
  65. package/src/adapters/types.ts +0 -181
  66. package/src/core.ts +0 -51
  67. package/src/index.ts +0 -34
  68. package/src/instrumentation/__tests__/core.spec.ts +0 -248
  69. package/src/instrumentation/__tests__/hono.spec.ts +0 -348
  70. package/src/instrumentation/__tests__/middleware.spec.ts +0 -528
  71. package/src/instrumentation/__tests__/otel.spec.ts +0 -291
  72. package/src/instrumentation/__tests__/tracing.spec.ts +0 -208
  73. package/src/instrumentation/core.ts +0 -228
  74. package/src/instrumentation/hono.ts +0 -270
  75. package/src/instrumentation/http.ts +0 -306
  76. package/src/instrumentation/index.ts +0 -90
  77. package/src/instrumentation/middleware.ts +0 -297
  78. package/src/instrumentation/otel.ts +0 -271
  79. package/src/instrumentation/setup.ts +0 -246
  80. package/src/instrumentation/tracing.ts +0 -145
  81. package/src/logger/__tests__/console.spec.ts +0 -366
  82. package/src/logger/__tests__/pino.spec.ts +0 -217
  83. package/src/logger/console.ts +0 -230
  84. package/src/logger/pino.ts +0 -201
  85. package/src/metrics/MetricsAggregator.ts +0 -555
  86. package/src/metrics/__tests__/MetricsAggregator.spec.ts +0 -298
  87. package/src/metrics/index.ts +0 -2
  88. package/src/metrics/storage/InMemoryMetricsStorage.ts +0 -380
  89. package/src/metrics/storage/MetricsStorage.ts +0 -74
  90. package/src/metrics/storage/index.ts +0 -3
  91. package/src/metrics/storage/types.ts +0 -243
  92. package/src/otlp/__tests__/receiver.spec.ts +0 -367
  93. package/src/otlp/__tests__/transformer.spec.ts +0 -455
  94. package/src/otlp/hono.ts +0 -120
  95. package/src/otlp/index.ts +0 -22
  96. package/src/otlp/receiver.ts +0 -162
  97. package/src/otlp/transformer.ts +0 -367
  98. package/src/otlp/types.ts +0 -364
  99. package/src/redact.ts +0 -116
  100. package/src/server/__tests__/hono.spec.ts +0 -814
  101. package/src/server/hono.ts +0 -442
  102. package/src/storage/__tests__/kysely.spec.ts +0 -715
  103. package/src/storage/__tests__/memory.spec.ts +0 -694
  104. package/src/storage/kysely.ts +0 -599
  105. package/src/storage/memory.ts +0 -204
  106. package/src/types.ts +0 -447
  107. package/src/ui-assets.ts +0 -40
  108. package/tsconfig.json +0 -9
  109. package/ui/CHANGELOG.md +0 -7
  110. package/ui/index.html +0 -12
  111. package/ui/node_modules/.bin/tsc +0 -21
  112. package/ui/node_modules/.bin/tsserver +0 -21
  113. package/ui/node_modules/.bin/vite +0 -21
  114. package/ui/package.json +0 -24
  115. package/ui/src/App.tsx +0 -595
  116. package/ui/src/api.ts +0 -88
  117. package/ui/src/components/ExceptionDetail.tsx +0 -100
  118. package/ui/src/components/FilterBar.tsx +0 -162
  119. package/ui/src/components/LogDetail.tsx +0 -91
  120. package/ui/src/components/RequestDetail.tsx +0 -143
  121. package/ui/src/main.tsx +0 -10
  122. package/ui/src/styles.css +0 -11
  123. package/ui/src/types.ts +0 -63
  124. package/ui/src/vite-env.d.ts +0 -1
  125. package/ui/src/vite-plugin-gkm-config.ts +0 -54
  126. package/ui/tsconfig.json +0 -20
  127. package/ui/tsconfig.tsbuildinfo +0 -1
  128. package/ui/vite.config.ts +0 -13
@@ -1,438 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { InMemoryStorage } from '../storage/memory';
3
- import { Telescope } from '../Telescope';
4
-
5
- describe('Telescope', () => {
6
- let telescope: Telescope;
7
- let storage: InMemoryStorage;
8
-
9
- beforeEach(() => {
10
- storage = new InMemoryStorage();
11
- telescope = new Telescope({ storage });
12
- });
13
-
14
- afterEach(() => {
15
- telescope.destroy();
16
- });
17
-
18
- describe('constructor', () => {
19
- it('should create with default options', () => {
20
- expect(telescope.enabled).toBe(true);
21
- expect(telescope.recordBody).toBe(true);
22
- });
23
-
24
- it('should respect enabled option', () => {
25
- const disabled = new Telescope({ storage, enabled: false });
26
- expect(disabled.enabled).toBe(false);
27
- disabled.destroy();
28
- });
29
-
30
- it('should respect recordBody option', () => {
31
- const noBody = new Telescope({ storage, recordBody: false });
32
- expect(noBody.recordBody).toBe(false);
33
- noBody.destroy();
34
- });
35
- });
36
-
37
- describe('recordRequest', () => {
38
- it('should record a request and return an ID', async () => {
39
- const requestId = await telescope.recordRequest({
40
- method: 'GET',
41
- path: '/api/users',
42
- url: 'http://localhost:3000/api/users',
43
- headers: { 'content-type': 'application/json' },
44
- query: { page: '1' },
45
- status: 200,
46
- responseHeaders: { 'content-type': 'application/json' },
47
- responseBody: { users: [] },
48
- duration: 50,
49
- });
50
-
51
- expect(requestId).toBeDefined();
52
- expect(typeof requestId).toBe('string');
53
-
54
- const request = await telescope.getRequest(requestId);
55
- expect(request).not.toBeNull();
56
- expect(request?.method).toBe('GET');
57
- expect(request?.path).toBe('/api/users');
58
- expect(request?.status).toBe(200);
59
- });
60
-
61
- it('should not record when disabled', async () => {
62
- const disabled = new Telescope({ storage, enabled: false });
63
-
64
- const requestId = await disabled.recordRequest({
65
- method: 'GET',
66
- path: '/api/test',
67
- url: 'http://localhost/api/test',
68
- headers: {},
69
- query: {},
70
- status: 200,
71
- responseHeaders: {},
72
- duration: 10,
73
- });
74
-
75
- expect(requestId).toBe('');
76
-
77
- const requests = await storage.getRequests();
78
- expect(requests).toHaveLength(0);
79
-
80
- disabled.destroy();
81
- });
82
- });
83
-
84
- describe('logging', () => {
85
- it('should record a log entry with info()', async () => {
86
- await telescope.info('User logged in', { userId: '123' });
87
-
88
- const logs = await telescope.getLogs();
89
- expect(logs).toHaveLength(1);
90
- expect(logs[0].level).toBe('info');
91
- expect(logs[0].message).toBe('User logged in');
92
- expect(logs[0].context).toEqual({ userId: '123' });
93
- });
94
-
95
- it('should record different log levels', async () => {
96
- await telescope.debug('Debug message');
97
- await telescope.info('Info message');
98
- await telescope.warn('Warning message');
99
- await telescope.error('Error message');
100
-
101
- const logs = await telescope.getLogs();
102
- expect(logs).toHaveLength(4);
103
-
104
- const levels = logs.map((l) => l.level);
105
- expect(levels).toContain('debug');
106
- expect(levels).toContain('info');
107
- expect(levels).toContain('warn');
108
- expect(levels).toContain('error');
109
- });
110
-
111
- it('should associate log with request ID', async () => {
112
- const requestId = await telescope.recordRequest({
113
- method: 'POST',
114
- path: '/api/login',
115
- url: 'http://localhost/api/login',
116
- headers: {},
117
- query: {},
118
- status: 200,
119
- responseHeaders: {},
120
- duration: 100,
121
- });
122
-
123
- await telescope.info('Login successful', {}, requestId);
124
-
125
- const logs = await telescope.getLogs();
126
- expect(logs[0].requestId).toBe(requestId);
127
- });
128
-
129
- it('should not record when disabled', async () => {
130
- const disabled = new Telescope({ storage, enabled: false });
131
-
132
- await disabled.info('Test message');
133
-
134
- const logs = await storage.getLogs();
135
- expect(logs).toHaveLength(0);
136
-
137
- disabled.destroy();
138
- });
139
-
140
- it('should batch log entries with log()', async () => {
141
- await telescope.log([
142
- { level: 'info', message: 'First' },
143
- { level: 'debug', message: 'Second', context: { step: 2 } },
144
- { level: 'warn', message: 'Third' },
145
- ]);
146
-
147
- const logs = await telescope.getLogs();
148
- expect(logs).toHaveLength(3);
149
- });
150
- });
151
-
152
- describe('exception', () => {
153
- it('should record an exception with stack trace', async () => {
154
- const error = new Error('Something went wrong');
155
-
156
- await telescope.exception(error);
157
-
158
- const exceptions = await telescope.getExceptions();
159
- expect(exceptions).toHaveLength(1);
160
- expect(exceptions[0].name).toBe('Error');
161
- expect(exceptions[0].message).toBe('Something went wrong');
162
- expect(exceptions[0].stack.length).toBeGreaterThan(0);
163
- });
164
-
165
- it('should associate exception with request ID', async () => {
166
- const requestId = await telescope.recordRequest({
167
- method: 'GET',
168
- path: '/api/error',
169
- url: 'http://localhost/api/error',
170
- headers: {},
171
- query: {},
172
- status: 500,
173
- responseHeaders: {},
174
- duration: 10,
175
- });
176
-
177
- await telescope.exception(new Error('Request failed'), requestId);
178
-
179
- const exceptions = await telescope.getExceptions();
180
- expect(exceptions[0].requestId).toBe(requestId);
181
- });
182
- });
183
-
184
- describe('shouldIgnore', () => {
185
- it('should ignore paths matching patterns', () => {
186
- const withPatterns = new Telescope({
187
- storage,
188
- ignorePatterns: ['/health', '/metrics', '/__telescope/*'],
189
- });
190
-
191
- expect(withPatterns.shouldIgnore('/health')).toBe(true);
192
- expect(withPatterns.shouldIgnore('/metrics')).toBe(true);
193
- expect(withPatterns.shouldIgnore('/__telescope/api/requests')).toBe(true);
194
- expect(withPatterns.shouldIgnore('/api/users')).toBe(false);
195
-
196
- withPatterns.destroy();
197
- });
198
-
199
- it('should return false when no patterns configured', () => {
200
- expect(telescope.shouldIgnore('/any/path')).toBe(false);
201
- });
202
- });
203
-
204
- describe('getRequests', () => {
205
- it('should return requests with query options', async () => {
206
- for (let i = 0; i < 5; i++) {
207
- await telescope.recordRequest({
208
- method: 'GET',
209
- path: `/api/item/${i}`,
210
- url: `http://localhost/api/item/${i}`,
211
- headers: {},
212
- query: {},
213
- status: 200,
214
- responseHeaders: {},
215
- duration: 10,
216
- });
217
- }
218
-
219
- const requests = await telescope.getRequests({ limit: 2 });
220
- expect(requests).toHaveLength(2);
221
- });
222
- });
223
-
224
- describe('getStats', () => {
225
- it('should return aggregated statistics', async () => {
226
- await telescope.recordRequest({
227
- method: 'GET',
228
- path: '/api/test',
229
- url: 'http://localhost/api/test',
230
- headers: {},
231
- query: {},
232
- status: 200,
233
- responseHeaders: {},
234
- duration: 10,
235
- });
236
-
237
- await telescope.info('Test log');
238
- await telescope.exception(new Error('Test error'));
239
-
240
- const stats = await telescope.getStats();
241
-
242
- expect(stats.requests).toBe(1);
243
- expect(stats.logs).toBe(1);
244
- expect(stats.exceptions).toBe(1);
245
- });
246
- });
247
-
248
- describe('prune', () => {
249
- it('should remove old entries', async () => {
250
- // Add an old entry directly to storage
251
- await storage.saveRequest({
252
- id: 'old-req',
253
- method: 'GET',
254
- path: '/old',
255
- url: 'http://localhost/old',
256
- headers: {},
257
- query: {},
258
- status: 200,
259
- responseHeaders: {},
260
- duration: 10,
261
- timestamp: new Date('2020-01-01'),
262
- });
263
-
264
- // Add a new entry
265
- await telescope.recordRequest({
266
- method: 'GET',
267
- path: '/new',
268
- url: 'http://localhost/new',
269
- headers: {},
270
- query: {},
271
- status: 200,
272
- responseHeaders: {},
273
- duration: 10,
274
- });
275
-
276
- const deleted = await telescope.prune(new Date('2023-01-01'));
277
-
278
- expect(deleted).toBe(1);
279
-
280
- const requests = await telescope.getRequests();
281
- expect(requests).toHaveLength(1);
282
- expect(requests[0].path).toBe('/new');
283
- });
284
- });
285
-
286
- describe('auto-prune', () => {
287
- it('should configure pruneAfterHours option', () => {
288
- const autoPrune = new Telescope({
289
- storage,
290
- pruneAfterHours: 1,
291
- });
292
-
293
- // Verify the telescope was created with pruneAfterHours
294
- // The actual pruning is tested via the prune() method
295
- expect(autoPrune).toBeDefined();
296
-
297
- autoPrune.destroy();
298
- });
299
- });
300
-
301
- describe('getRequestId option', () => {
302
- it('should use custom getRequestId function when provided', async () => {
303
- const customTelescope = new Telescope({
304
- storage,
305
- getRequestId: () => 'custom-request-id-123',
306
- });
307
-
308
- const requestId = await customTelescope.recordRequest({
309
- method: 'GET',
310
- path: '/api/test',
311
- url: 'http://localhost/api/test',
312
- headers: {},
313
- query: {},
314
- status: 200,
315
- responseHeaders: {},
316
- duration: 10,
317
- });
318
-
319
- expect(requestId).toBe('custom-request-id-123');
320
-
321
- const request = await customTelescope.getRequest('custom-request-id-123');
322
- expect(request).not.toBeNull();
323
- expect(request?.id).toBe('custom-request-id-123');
324
-
325
- customTelescope.destroy();
326
- });
327
-
328
- it('should fallback to nanoid when getRequestId returns undefined', async () => {
329
- const customTelescope = new Telescope({
330
- storage,
331
- getRequestId: () => undefined,
332
- });
333
-
334
- const requestId = await customTelescope.recordRequest({
335
- method: 'GET',
336
- path: '/api/test',
337
- url: 'http://localhost/api/test',
338
- headers: {},
339
- query: {},
340
- status: 200,
341
- responseHeaders: {},
342
- duration: 10,
343
- });
344
-
345
- // Should fall back to nanoid (21 chars)
346
- expect(requestId).toBeDefined();
347
- expect(requestId.length).toBe(21);
348
- expect(requestId).not.toBe('');
349
-
350
- customTelescope.destroy();
351
- });
352
-
353
- it('should work with dynamic request ID getter', async () => {
354
- let currentRequestId: string | undefined;
355
-
356
- const customTelescope = new Telescope({
357
- storage,
358
- getRequestId: () => currentRequestId,
359
- });
360
-
361
- // First request - no context
362
- currentRequestId = undefined;
363
- const id1 = await customTelescope.recordRequest({
364
- method: 'GET',
365
- path: '/api/test1',
366
- url: 'http://localhost/api/test1',
367
- headers: {},
368
- query: {},
369
- status: 200,
370
- responseHeaders: {},
371
- duration: 10,
372
- });
373
- expect(id1.length).toBe(21); // nanoid fallback
374
-
375
- // Second request - with context
376
- currentRequestId = 'context-id-456';
377
- const id2 = await customTelescope.recordRequest({
378
- method: 'GET',
379
- path: '/api/test2',
380
- url: 'http://localhost/api/test2',
381
- headers: {},
382
- query: {},
383
- status: 200,
384
- responseHeaders: {},
385
- duration: 10,
386
- });
387
- expect(id2).toBe('context-id-456');
388
-
389
- customTelescope.destroy();
390
- });
391
- });
392
-
393
- describe('WebSocket clients', () => {
394
- it('should manage WebSocket client connections', () => {
395
- const mockWs = {
396
- send: vi.fn(),
397
- readyState: 1, // OPEN
398
- } as unknown as WebSocket;
399
-
400
- telescope.addWsClient(mockWs);
401
-
402
- // Broadcast should send to client (including the 'connected' event)
403
- const callCount = mockWs.send.mock.calls.length;
404
- expect(callCount).toBeGreaterThan(0);
405
-
406
- telescope.removeWsClient(mockWs);
407
-
408
- // After removal, broadcast should not send
409
- const newMock = vi.fn();
410
- mockWs.send = newMock;
411
- telescope.broadcast({
412
- type: 'request',
413
- payload: {},
414
- timestamp: Date.now(),
415
- });
416
-
417
- expect(newMock).not.toHaveBeenCalled();
418
- });
419
-
420
- it('should broadcast to all connected clients', () => {
421
- const ws1 = { send: vi.fn() } as unknown as WebSocket;
422
- const ws2 = { send: vi.fn() } as unknown as WebSocket;
423
-
424
- telescope.addWsClient(ws1);
425
- telescope.addWsClient(ws2);
426
-
427
- telescope.broadcast({
428
- type: 'log',
429
- payload: { test: true },
430
- timestamp: Date.now(),
431
- });
432
-
433
- // Both should receive the broadcast
434
- expect(ws1.send).toHaveBeenCalled();
435
- expect(ws2.send).toHaveBeenCalled();
436
- });
437
- });
438
- });
@@ -1,115 +0,0 @@
1
- import pino from 'pino';
2
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
3
- import { createPinoTransport } from '../logger/pino';
4
- import { InMemoryStorage } from '../storage/memory';
5
- import { Telescope } from '../Telescope';
6
-
7
- describe('createPinoTransport', () => {
8
- let telescope: Telescope;
9
- let storage: InMemoryStorage;
10
-
11
- beforeEach(() => {
12
- storage = new InMemoryStorage({ maxEntries: 100 });
13
- telescope = new Telescope({ storage, enabled: true });
14
- });
15
-
16
- afterEach(() => {
17
- telescope.destroy();
18
- });
19
-
20
- it('should send logs to telescope when configured like apps/example/src/config/logger.ts', async () => {
21
- // This mirrors the exact setup in apps/example/src/config/logger.ts
22
- const logger = pino(
23
- {
24
- level: 'debug',
25
- formatters: {
26
- bindings() {
27
- return { nodeVersion: process.version };
28
- },
29
- level: (label) => {
30
- return { level: label.toUpperCase() };
31
- },
32
- },
33
- },
34
- pino.multistream([
35
- { stream: process.stdout },
36
- { stream: createPinoTransport({ telescope }) },
37
- ]),
38
- );
39
-
40
- logger.info('Test log message');
41
- logger.info({ userId: '123' }, 'User logged in');
42
-
43
- // Wait for the transport to process and flush
44
- await new Promise((resolve) => setTimeout(resolve, 1500));
45
-
46
- const logs = await telescope.getLogs();
47
- expect(logs.length).toBeGreaterThanOrEqual(1);
48
- });
49
-
50
- it('should NOT have logs before flush interval (default 1000ms)', async () => {
51
- const logger = pino(
52
- {
53
- level: 'debug',
54
- formatters: {
55
- bindings() {
56
- return { nodeVersion: process.version };
57
- },
58
- level: (label) => {
59
- return { level: label.toUpperCase() };
60
- },
61
- },
62
- },
63
- pino.multistream([
64
- { stream: process.stdout },
65
- { stream: createPinoTransport({ telescope }) },
66
- ]),
67
- );
68
-
69
- logger.info('Test before flush');
70
-
71
- // Check immediately - should NOT be flushed yet
72
- const _logsImmediate = await telescope.getLogs();
73
-
74
- // Check at 500ms - should NOT be flushed yet
75
- await new Promise((resolve) => setTimeout(resolve, 500));
76
- const _logs500ms = await telescope.getLogs();
77
-
78
- // Check at 1200ms - SHOULD be flushed
79
- await new Promise((resolve) => setTimeout(resolve, 700));
80
- const logs1200ms = await telescope.getLogs();
81
-
82
- expect(logs1200ms.length).toBeGreaterThanOrEqual(1);
83
- });
84
-
85
- it('should verify log content matches what was logged', async () => {
86
- const logger = pino(
87
- {
88
- level: 'debug',
89
- formatters: {
90
- bindings() {
91
- return { nodeVersion: process.version };
92
- },
93
- level: (label) => {
94
- return { level: label.toUpperCase() };
95
- },
96
- },
97
- },
98
- pino.multistream([
99
- { stream: process.stdout },
100
- { stream: createPinoTransport({ telescope }) },
101
- ]),
102
- );
103
-
104
- logger.info({ customField: 'test-value' }, 'Specific test message');
105
-
106
- await new Promise((resolve) => setTimeout(resolve, 1500));
107
-
108
- const logs = await telescope.getLogs();
109
-
110
- const matchingLog = logs.find((l) => l.message === 'Specific test message');
111
- expect(matchingLog).toBeDefined();
112
- expect(matchingLog?.level).toBe('info');
113
- expect(matchingLog?.context?.customField).toBe('test-value');
114
- });
115
- });