@geekmidas/telescope 10.0.0-alpha.99 → 10.0.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.
- package/CHANGELOG.md +79 -0
- package/README.md +18 -28
- package/dist/InMemoryMetricsStorage-BbKCL3YL.d.mts +47 -0
- package/dist/InMemoryMetricsStorage-BbKCL3YL.d.mts.map +1 -0
- package/dist/InMemoryMetricsStorage-C4drxT7G.mjs +247 -0
- package/dist/InMemoryMetricsStorage-C4drxT7G.mjs.map +1 -0
- package/dist/InMemoryMetricsStorage-D0njWUSi.cjs +252 -0
- package/dist/InMemoryMetricsStorage-D0njWUSi.cjs.map +1 -0
- package/dist/InMemoryMetricsStorage-TvPdZjL0.d.cts +47 -0
- package/dist/InMemoryMetricsStorage-TvPdZjL0.d.cts.map +1 -0
- package/dist/{MetricsAggregator-BJdIvfEv.d.mts → MetricsAggregator-4SqelGcG.d.cts} +6 -3
- package/dist/MetricsAggregator-4SqelGcG.d.cts.map +1 -0
- package/dist/MetricsAggregator-B7lUICdH.cjs +363 -0
- package/dist/MetricsAggregator-B7lUICdH.cjs.map +1 -0
- package/dist/{MetricsAggregator-CnC3oT5q.d.cts → MetricsAggregator-DZrW8ls6.d.mts} +6 -3
- package/dist/MetricsAggregator-DZrW8ls6.d.mts.map +1 -0
- package/dist/MetricsAggregator-S3DQWNas.mjs +357 -0
- package/dist/MetricsAggregator-S3DQWNas.mjs.map +1 -0
- package/dist/MetricsStorage-B86e4131.d.cts +60 -0
- package/dist/MetricsStorage-B86e4131.d.cts.map +1 -0
- package/dist/MetricsStorage-BWyP2_12.d.mts +60 -0
- package/dist/MetricsStorage-BWyP2_12.d.mts.map +1 -0
- package/dist/MetricsStorage-BypQXWiv.mjs +0 -0
- package/dist/MetricsStorage-Or8pVCe4.cjs +0 -0
- package/dist/Telescope-Cs3fv8jt.cjs +395 -0
- package/dist/Telescope-Cs3fv8jt.cjs.map +1 -0
- package/dist/{Telescope-BVfDvVvY.d.mts → Telescope-D4nmwDRA.d.cts} +7 -4
- package/dist/Telescope-D4nmwDRA.d.cts.map +1 -0
- package/dist/Telescope-Dh5av3FC.mjs +389 -0
- package/dist/Telescope-Dh5av3FC.mjs.map +1 -0
- package/dist/{Telescope-DeqSHfuB.d.cts → Telescope-Dl6VSfxd.d.mts} +7 -4
- package/dist/Telescope-Dl6VSfxd.d.mts.map +1 -0
- package/dist/Telescope.cjs +4 -385
- package/dist/Telescope.d.cts +3 -1
- package/dist/Telescope.d.mts +3 -1
- package/dist/Telescope.mjs +4 -384
- package/dist/adapters/index.d.cts +2 -2
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +0 -1
- package/dist/adapters/lambda.cjs +10 -9
- package/dist/adapters/lambda.cjs.map +1 -1
- package/dist/adapters/lambda.d.cts +13 -9
- package/dist/adapters/lambda.d.cts.map +1 -1
- package/dist/adapters/lambda.d.mts +13 -9
- package/dist/adapters/lambda.d.mts.map +1 -1
- package/dist/adapters/lambda.mjs +4 -3
- package/dist/adapters/lambda.mjs.map +1 -1
- package/dist/adapters/middy.cjs +4 -236
- package/dist/adapters/middy.d.cts +5 -60
- package/dist/adapters/middy.d.mts +5 -60
- package/dist/adapters/middy.mjs +3 -234
- package/dist/adapters/types.d.cts +2 -162
- package/dist/adapters/types.d.mts +2 -162
- package/dist/adapters/types.mjs +0 -1
- package/dist/{rolldown-runtime-VH7oDXx4.cjs → chunk-CUT6urMc.cjs} +10 -8
- package/dist/core--quSp5Qr.d.mts +78 -0
- package/dist/core--quSp5Qr.d.mts.map +1 -0
- package/dist/core-B4Jpia5H.d.cts +78 -0
- package/dist/core-B4Jpia5H.d.cts.map +1 -0
- package/dist/core-CtVHRJGv.cjs +199 -0
- package/dist/core-CtVHRJGv.cjs.map +1 -0
- package/dist/core-D6hJ6exL.mjs +139 -0
- package/dist/core-D6hJ6exL.mjs.map +1 -0
- package/dist/core.cjs +22 -22
- package/dist/core.d.cts +4 -4
- package/dist/core.d.mts +4 -4
- package/dist/core.mjs +4 -3
- package/dist/hono--uKQ7Jgi.d.mts +71 -0
- package/dist/hono--uKQ7Jgi.d.mts.map +1 -0
- package/dist/hono-C4EgpbKQ.cjs +160 -0
- package/dist/hono-C4EgpbKQ.cjs.map +1 -0
- package/dist/hono-CemCKU87.d.cts +71 -0
- package/dist/hono-CemCKU87.d.cts.map +1 -0
- package/dist/hono-DxhvnVbF.mjs +136 -0
- package/dist/hono-DxhvnVbF.mjs.map +1 -0
- package/dist/http-BiNtg85L.d.mts +107 -0
- package/dist/http-BiNtg85L.d.mts.map +1 -0
- package/dist/http-DQzgLczm.mjs +159 -0
- package/dist/http-DQzgLczm.mjs.map +1 -0
- package/dist/http-D_Z8sYXZ.cjs +219 -0
- package/dist/http-D_Z8sYXZ.cjs.map +1 -0
- package/dist/http-Dvca6fC3.d.cts +107 -0
- package/dist/http-Dvca6fC3.d.cts.map +1 -0
- package/dist/index-BL32-cvv.d.cts +1 -0
- package/dist/index-CsuikFeJ.d.mts +1 -0
- package/dist/index.cjs +9 -8
- package/dist/index.d.cts +6 -5
- package/dist/index.d.mts +6 -5
- package/dist/index.mjs +7 -5
- package/dist/instrumentation/core.cjs +11 -147
- package/dist/instrumentation/core.d.cts +3 -74
- package/dist/instrumentation/core.d.mts +3 -74
- package/dist/instrumentation/core.mjs +2 -137
- package/dist/instrumentation/hono.cjs +6 -174
- package/dist/instrumentation/hono.d.cts +2 -86
- package/dist/instrumentation/hono.d.mts +2 -86
- package/dist/instrumentation/hono.mjs +3 -170
- package/dist/instrumentation/http.cjs +11 -189
- package/dist/instrumentation/http.d.cts +2 -119
- package/dist/instrumentation/http.d.mts +2 -119
- package/dist/instrumentation/http.mjs +2 -178
- package/dist/instrumentation/index.cjs +47 -56
- package/dist/instrumentation/index.d.cts +9 -11
- package/dist/instrumentation/index.d.mts +9 -11
- package/dist/instrumentation/index.mjs +9 -10
- package/dist/instrumentation/middleware.cjs +6 -164
- package/dist/instrumentation/middleware.d.cts +2 -83
- package/dist/instrumentation/middleware.d.mts +2 -83
- package/dist/instrumentation/middleware.mjs +3 -160
- package/dist/instrumentation/otel.cjs +3 -137
- package/dist/instrumentation/otel.d.cts +2 -97
- package/dist/instrumentation/otel.d.mts +2 -97
- package/dist/instrumentation/otel.mjs +3 -136
- package/dist/instrumentation/setup.cjs +4 -142
- package/dist/instrumentation/setup.d.cts +3 -139
- package/dist/instrumentation/setup.d.mts +3 -139
- package/dist/instrumentation/setup.mjs +3 -139
- package/dist/instrumentation/tracing.cjs +10 -114
- package/dist/instrumentation/tracing.d.cts +2 -49
- package/dist/instrumentation/tracing.d.mts +2 -49
- package/dist/instrumentation/tracing.mjs +2 -105
- package/dist/logger/console.cjs +12 -18
- package/dist/logger/console.cjs.map +1 -1
- package/dist/logger/console.d.cts +10 -7
- package/dist/logger/console.d.cts.map +1 -1
- package/dist/logger/console.d.mts +10 -7
- package/dist/logger/console.d.mts.map +1 -1
- package/dist/logger/console.mjs +11 -17
- package/dist/logger/console.mjs.map +1 -1
- package/dist/logger/pino.cjs +5 -6
- package/dist/logger/pino.cjs.map +1 -1
- package/dist/logger/pino.d.cts +10 -6
- package/dist/logger/pino.d.cts.map +1 -1
- package/dist/logger/pino.d.mts +10 -6
- package/dist/logger/pino.d.mts.map +1 -1
- package/dist/logger/pino.mjs +3 -2
- package/dist/logger/pino.mjs.map +1 -1
- package/dist/memory--BK4iWiv.d.cts +40 -0
- package/dist/memory--BK4iWiv.d.cts.map +1 -0
- package/dist/memory-6S9H-IF5.mjs +123 -0
- package/dist/memory-6S9H-IF5.mjs.map +1 -0
- package/dist/memory-B0d_n1g5.cjs +129 -0
- package/dist/memory-B0d_n1g5.cjs.map +1 -0
- package/dist/memory-DCirEVFW.d.mts +40 -0
- package/dist/memory-DCirEVFW.d.mts.map +1 -0
- package/dist/metrics/MetricsAggregator.cjs +2 -354
- package/dist/metrics/MetricsAggregator.d.cts +2 -1
- package/dist/metrics/MetricsAggregator.d.mts +2 -1
- package/dist/metrics/MetricsAggregator.mjs +2 -353
- package/dist/metrics/index.cjs +4 -3
- package/dist/metrics/index.d.cts +4 -2
- package/dist/metrics/index.d.mts +4 -2
- package/dist/metrics/index.mjs +4 -2
- package/dist/metrics/storage/InMemoryMetricsStorage.cjs +3 -240
- package/dist/metrics/storage/InMemoryMetricsStorage.d.cts +4 -43
- package/dist/metrics/storage/InMemoryMetricsStorage.d.mts +4 -43
- package/dist/metrics/storage/InMemoryMetricsStorage.mjs +3 -239
- package/dist/metrics/storage/MetricsStorage.cjs +1 -0
- package/dist/metrics/storage/MetricsStorage.d.cts +3 -56
- package/dist/metrics/storage/MetricsStorage.d.mts +3 -56
- package/dist/metrics/storage/MetricsStorage.mjs +1 -1
- package/dist/metrics/storage/index.cjs +6 -6
- package/dist/metrics/storage/index.d.cts +3 -3
- package/dist/metrics/storage/index.d.mts +3 -3
- package/dist/metrics/storage/index.mjs +5 -4
- package/dist/metrics/storage/types.cjs +2 -34
- package/dist/metrics/storage/types.d.cts +2 -207
- package/dist/metrics/storage/types.d.mts +2 -207
- package/dist/metrics/storage/types.mjs +2 -33
- package/dist/metrics-D5YT-Rnq.mjs +0 -0
- package/dist/metrics-fhD3l3C3.cjs +0 -0
- package/dist/middleware-B2jFUukM.cjs +184 -0
- package/dist/middleware-B2jFUukM.cjs.map +1 -0
- package/dist/middleware-BTDncHwm.mjs +160 -0
- package/dist/middleware-BTDncHwm.mjs.map +1 -0
- package/dist/middleware-CA84nsNN.d.cts +74 -0
- package/dist/middleware-CA84nsNN.d.cts.map +1 -0
- package/dist/middleware-DAceVpfw.d.mts +74 -0
- package/dist/middleware-DAceVpfw.d.mts.map +1 -0
- package/dist/middy-B6Btl8XE.d.mts +64 -0
- package/dist/middy-B6Btl8XE.d.mts.map +1 -0
- package/dist/middy-BTR3cyvk.mjs +236 -0
- package/dist/middy-BTR3cyvk.mjs.map +1 -0
- package/dist/middy-Bq0defVg.d.cts +64 -0
- package/dist/middy-Bq0defVg.d.cts.map +1 -0
- package/dist/middy-y5Zp27eG.cjs +247 -0
- package/dist/middy-y5Zp27eG.cjs.map +1 -0
- package/dist/otel-1bJPb2Z7.d.mts +101 -0
- package/dist/otel-1bJPb2Z7.d.mts.map +1 -0
- package/dist/otel-C1HqHA2O.cjs +136 -0
- package/dist/otel-C1HqHA2O.cjs.map +1 -0
- package/dist/otel-SBVoVEHr.d.cts +101 -0
- package/dist/otel-SBVoVEHr.d.cts.map +1 -0
- package/dist/otel-wulj5B-X.mjs +130 -0
- package/dist/otel-wulj5B-X.mjs.map +1 -0
- package/dist/otlp/hono.cjs +15 -9
- package/dist/otlp/hono.cjs.map +1 -1
- package/dist/otlp/hono.d.cts +13 -3
- package/dist/otlp/hono.d.cts.map +1 -1
- package/dist/otlp/hono.d.mts +13 -3
- package/dist/otlp/hono.d.mts.map +1 -1
- package/dist/otlp/hono.mjs +11 -5
- package/dist/otlp/hono.mjs.map +1 -1
- package/dist/otlp/index.cjs +11 -11
- package/dist/otlp/index.d.cts +7 -4
- package/dist/otlp/index.d.mts +7 -4
- package/dist/otlp/index.mjs +5 -4
- package/dist/otlp/receiver.cjs +4 -88
- package/dist/otlp/receiver.d.cts +7 -59
- package/dist/otlp/receiver.d.mts +7 -59
- package/dist/otlp/receiver.mjs +4 -87
- package/dist/otlp/transformer.cjs +5 -214
- package/dist/otlp/transformer.d.cts +3 -1
- package/dist/otlp/transformer.d.mts +3 -1
- package/dist/otlp/transformer.mjs +3 -211
- package/dist/otlp/types.cjs +5 -57
- package/dist/otlp/types.d.cts +1 -1
- package/dist/otlp/types.d.mts +1 -1
- package/dist/otlp/types.mjs +2 -53
- package/dist/receiver-Cj1lbAOO.cjs +94 -0
- package/dist/receiver-Cj1lbAOO.cjs.map +1 -0
- package/dist/receiver-CxVd_9CB.mjs +89 -0
- package/dist/receiver-CxVd_9CB.mjs.map +1 -0
- package/dist/receiver-DLICx5uU.d.cts +63 -0
- package/dist/receiver-DLICx5uU.d.cts.map +1 -0
- package/dist/receiver-UeZT-H8u.d.mts +63 -0
- package/dist/receiver-UeZT-H8u.d.mts.map +1 -0
- package/dist/redact-BzkITCNW.mjs +83 -0
- package/dist/redact-BzkITCNW.mjs.map +1 -0
- package/dist/redact-DVaSSPZT.cjs +95 -0
- package/dist/redact-DVaSSPZT.cjs.map +1 -0
- package/dist/redact.cjs +3 -84
- package/dist/redact.d.cts +8 -4
- package/dist/redact.d.cts.map +1 -1
- package/dist/redact.d.mts +8 -4
- package/dist/redact.d.mts.map +1 -1
- package/dist/redact.mjs +2 -80
- package/dist/server/hono.cjs +54 -33
- package/dist/server/hono.cjs.map +1 -1
- package/dist/server/hono.d.cts +14 -19
- package/dist/server/hono.d.cts.map +1 -1
- package/dist/server/hono.d.mts +14 -19
- package/dist/server/hono.d.mts.map +1 -1
- package/dist/server/hono.mjs +52 -31
- package/dist/server/hono.mjs.map +1 -1
- package/dist/setup-B9jM77Qk.mjs +98 -0
- package/dist/setup-B9jM77Qk.mjs.map +1 -0
- package/dist/setup-Bkxm4g6b.d.mts +87 -0
- package/dist/setup-Bkxm4g6b.d.mts.map +1 -0
- package/dist/setup-CYpff5B9.cjs +110 -0
- package/dist/setup-CYpff5B9.cjs.map +1 -0
- package/dist/setup-D58N1f9O.d.cts +87 -0
- package/dist/setup-D58N1f9O.d.cts.map +1 -0
- package/dist/storage/kysely.cjs +70 -82
- package/dist/storage/kysely.cjs.map +1 -1
- package/dist/storage/kysely.d.cts +20 -36
- package/dist/storage/kysely.d.cts.map +1 -1
- package/dist/storage/kysely.d.mts +20 -36
- package/dist/storage/kysely.d.mts.map +1 -1
- package/dist/storage/kysely.mjs +69 -81
- package/dist/storage/kysely.mjs.map +1 -1
- package/dist/storage/memory.cjs +2 -122
- package/dist/storage/memory.d.cts +3 -36
- package/dist/storage/memory.d.mts +3 -36
- package/dist/storage/memory.mjs +2 -121
- package/dist/tracing-BX8uY2nR.d.cts +53 -0
- package/dist/tracing-BX8uY2nR.d.cts.map +1 -0
- package/dist/tracing-Bt1zWRlb.cjs +167 -0
- package/dist/tracing-Bt1zWRlb.cjs.map +1 -0
- package/dist/tracing-Cijm_5NI.mjs +113 -0
- package/dist/tracing-Cijm_5NI.mjs.map +1 -0
- package/dist/tracing-PnECEbEu.d.mts +53 -0
- package/dist/tracing-PnECEbEu.d.mts.map +1 -0
- package/dist/transformer-BXQPhzql.mjs +215 -0
- package/dist/transformer-BXQPhzql.mjs.map +1 -0
- package/dist/transformer-CLGZ0EQc.cjs +232 -0
- package/dist/transformer-CLGZ0EQc.cjs.map +1 -0
- package/dist/{transformer-BtqjAs0b.d.cts → transformer-CTGsaVfV.d.mts} +8 -4
- package/dist/transformer-CTGsaVfV.d.mts.map +1 -0
- package/dist/{transformer-DI6t8-YA.d.mts → transformer-ICEbxpFf.d.cts} +8 -4
- package/dist/transformer-ICEbxpFf.d.cts.map +1 -0
- package/dist/{types-BVujq4zd.d.mts → types-B1EIa_cQ.d.mts} +4 -3
- package/dist/types-B1EIa_cQ.d.mts.map +1 -0
- package/dist/types-BRzW1NM8.d.cts +166 -0
- package/dist/types-BRzW1NM8.d.cts.map +1 -0
- package/dist/types-BS3Rx8Sk.d.cts +209 -0
- package/dist/types-BS3Rx8Sk.d.cts.map +1 -0
- package/dist/types-Bwm_jNU7.mjs +54 -0
- package/dist/types-Bwm_jNU7.mjs.map +1 -0
- package/dist/types-BzQ78Efw.d.mts +166 -0
- package/dist/types-BzQ78Efw.d.mts.map +1 -0
- package/dist/types-CbNGXnJE.d.mts +209 -0
- package/dist/types-CbNGXnJE.d.mts.map +1 -0
- package/dist/{types-DVETVdpa.d.cts → types-CmOB7CLO.d.cts} +7 -6
- package/dist/types-CmOB7CLO.d.cts.map +1 -0
- package/dist/{types-DVETVdpa.d.mts → types-DBc0q5KD.d.mts} +7 -6
- package/dist/types-DBc0q5KD.d.mts.map +1 -0
- package/dist/types-Dsh-DIO_.cjs +78 -0
- package/dist/types-Dsh-DIO_.cjs.map +1 -0
- package/dist/types-ZW-nfWf6.cjs +40 -0
- package/dist/types-ZW-nfWf6.cjs.map +1 -0
- package/dist/{types-BVujq4zd.d.cts → types-l7Rlb5Mg.d.cts} +4 -3
- package/dist/types-l7Rlb5Mg.d.cts.map +1 -0
- package/dist/types-ojhnLdwz.mjs +34 -0
- package/dist/types-ojhnLdwz.mjs.map +1 -0
- package/dist/types.d.cts +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +0 -1
- package/dist/ui-assets-BEXqOQLe.cjs +48 -0
- package/dist/ui-assets-BEXqOQLe.cjs.map +1 -0
- package/dist/ui-assets-BhTDUsrM.mjs +30 -0
- package/dist/ui-assets-BhTDUsrM.mjs.map +1 -0
- package/dist/ui-assets.cjs +5 -0
- package/dist/ui-assets.d.cts +13 -0
- package/dist/ui-assets.d.cts.map +1 -0
- package/dist/ui-assets.d.mts +13 -0
- package/dist/ui-assets.d.mts.map +1 -0
- package/dist/ui-assets.mjs +3 -0
- package/package.json +46 -46
- package/src/Telescope.ts +561 -0
- package/src/__tests__/Telescope.spec.ts +438 -0
- package/src/__tests__/pino-transport.spec.ts +115 -0
- package/src/__tests__/redact.spec.ts +336 -0
- package/src/adapters/__tests__/lambda.spec.ts +318 -0
- package/src/adapters/__tests__/middy.spec.ts +741 -0
- package/src/adapters/index.ts +22 -0
- package/src/adapters/lambda.ts +432 -0
- package/src/adapters/middy.ts +402 -0
- package/src/adapters/types.ts +181 -0
- package/src/core.ts +51 -0
- package/src/index.ts +34 -0
- package/src/instrumentation/__tests__/core.spec.ts +248 -0
- package/src/instrumentation/__tests__/hono.spec.ts +348 -0
- package/src/instrumentation/__tests__/middleware.spec.ts +528 -0
- package/src/instrumentation/__tests__/otel.spec.ts +291 -0
- package/src/instrumentation/__tests__/tracing.spec.ts +208 -0
- package/src/instrumentation/core.ts +228 -0
- package/src/instrumentation/hono.ts +270 -0
- package/src/instrumentation/http.ts +306 -0
- package/src/instrumentation/index.ts +90 -0
- package/src/instrumentation/middleware.ts +297 -0
- package/src/instrumentation/otel.ts +271 -0
- package/src/instrumentation/setup.ts +246 -0
- package/src/instrumentation/tracing.ts +145 -0
- package/src/logger/__tests__/console.spec.ts +366 -0
- package/src/logger/__tests__/pino.spec.ts +217 -0
- package/src/logger/console.ts +230 -0
- package/src/logger/pino.ts +201 -0
- package/src/metrics/MetricsAggregator.ts +555 -0
- package/src/metrics/__tests__/MetricsAggregator.spec.ts +298 -0
- package/src/metrics/index.ts +2 -0
- package/src/metrics/storage/InMemoryMetricsStorage.ts +380 -0
- package/src/metrics/storage/MetricsStorage.ts +74 -0
- package/src/metrics/storage/index.ts +3 -0
- package/src/metrics/storage/types.ts +243 -0
- package/src/otlp/__tests__/receiver.spec.ts +367 -0
- package/src/otlp/__tests__/transformer.spec.ts +455 -0
- package/src/otlp/hono.ts +120 -0
- package/src/otlp/index.ts +22 -0
- package/src/otlp/receiver.ts +162 -0
- package/src/otlp/transformer.ts +367 -0
- package/src/otlp/types.ts +364 -0
- package/src/redact.ts +116 -0
- package/src/server/__tests__/hono.spec.ts +814 -0
- package/src/server/hono.ts +442 -0
- package/src/storage/__tests__/kysely.spec.ts +715 -0
- package/src/storage/__tests__/memory.spec.ts +694 -0
- package/src/storage/kysely.ts +599 -0
- package/src/storage/memory.ts +204 -0
- package/src/types.ts +447 -0
- package/src/ui-assets.ts +40 -0
- package/tsconfig.json +9 -0
- package/ui/CHANGELOG.md +7 -0
- package/ui/index.html +12 -0
- package/ui/node_modules/.bin/tsc +21 -0
- package/ui/node_modules/.bin/tsserver +21 -0
- package/ui/node_modules/.bin/vite +21 -0
- package/ui/package.json +24 -0
- package/ui/src/App.tsx +595 -0
- package/ui/src/api.ts +88 -0
- package/ui/src/components/ExceptionDetail.tsx +100 -0
- package/ui/src/components/FilterBar.tsx +162 -0
- package/ui/src/components/LogDetail.tsx +91 -0
- package/ui/src/components/RequestDetail.tsx +143 -0
- package/ui/src/main.tsx +10 -0
- package/ui/src/styles.css +11 -0
- package/ui/src/types.ts +63 -0
- package/ui/src/vite-env.d.ts +1 -0
- package/ui/src/vite-plugin-gkm-config.ts +54 -0
- package/ui/tsconfig.json +20 -0
- package/ui/tsconfig.tsbuildinfo +1 -0
- package/ui/vite.config.ts +13 -0
- package/dist/MetricsAggregator-BJdIvfEv.d.mts.map +0 -1
- package/dist/MetricsAggregator-CnC3oT5q.d.cts.map +0 -1
- package/dist/Telescope-BVfDvVvY.d.mts.map +0 -1
- package/dist/Telescope-DeqSHfuB.d.cts.map +0 -1
- package/dist/Telescope.cjs.map +0 -1
- package/dist/Telescope.mjs.map +0 -1
- package/dist/adapters/middy.cjs.map +0 -1
- package/dist/adapters/middy.d.cts.map +0 -1
- package/dist/adapters/middy.d.mts.map +0 -1
- package/dist/adapters/middy.mjs.map +0 -1
- package/dist/adapters/types.d.cts.map +0 -1
- package/dist/adapters/types.d.mts.map +0 -1
- package/dist/instrumentation/core.cjs.map +0 -1
- package/dist/instrumentation/core.d.cts.map +0 -1
- package/dist/instrumentation/core.d.mts.map +0 -1
- package/dist/instrumentation/core.mjs.map +0 -1
- package/dist/instrumentation/hono.cjs.map +0 -1
- package/dist/instrumentation/hono.d.cts.map +0 -1
- package/dist/instrumentation/hono.d.mts.map +0 -1
- package/dist/instrumentation/hono.mjs.map +0 -1
- package/dist/instrumentation/http.cjs.map +0 -1
- package/dist/instrumentation/http.d.cts.map +0 -1
- package/dist/instrumentation/http.d.mts.map +0 -1
- package/dist/instrumentation/http.mjs.map +0 -1
- package/dist/instrumentation/middleware.cjs.map +0 -1
- package/dist/instrumentation/middleware.d.cts.map +0 -1
- package/dist/instrumentation/middleware.d.mts.map +0 -1
- package/dist/instrumentation/middleware.mjs.map +0 -1
- package/dist/instrumentation/otel.cjs.map +0 -1
- package/dist/instrumentation/otel.d.cts.map +0 -1
- package/dist/instrumentation/otel.d.mts.map +0 -1
- package/dist/instrumentation/otel.mjs.map +0 -1
- package/dist/instrumentation/sampler.cjs +0 -54
- package/dist/instrumentation/sampler.cjs.map +0 -1
- package/dist/instrumentation/sampler.d.cts +0 -38
- package/dist/instrumentation/sampler.d.cts.map +0 -1
- package/dist/instrumentation/sampler.d.mts +0 -38
- package/dist/instrumentation/sampler.d.mts.map +0 -1
- package/dist/instrumentation/sampler.mjs +0 -52
- package/dist/instrumentation/sampler.mjs.map +0 -1
- package/dist/instrumentation/setup.cjs.map +0 -1
- package/dist/instrumentation/setup.d.cts.map +0 -1
- package/dist/instrumentation/setup.d.mts.map +0 -1
- package/dist/instrumentation/setup.mjs.map +0 -1
- package/dist/instrumentation/tracing.cjs.map +0 -1
- package/dist/instrumentation/tracing.d.cts.map +0 -1
- package/dist/instrumentation/tracing.d.mts.map +0 -1
- package/dist/instrumentation/tracing.mjs.map +0 -1
- package/dist/instrumentation/trust.cjs +0 -107
- package/dist/instrumentation/trust.cjs.map +0 -1
- package/dist/instrumentation/trust.d.cts +0 -57
- package/dist/instrumentation/trust.d.cts.map +0 -1
- package/dist/instrumentation/trust.d.mts +0 -57
- package/dist/instrumentation/trust.d.mts.map +0 -1
- package/dist/instrumentation/trust.mjs +0 -104
- package/dist/instrumentation/trust.mjs.map +0 -1
- package/dist/metrics/MetricsAggregator.cjs.map +0 -1
- package/dist/metrics/MetricsAggregator.mjs.map +0 -1
- package/dist/metrics/storage/InMemoryMetricsStorage.cjs.map +0 -1
- package/dist/metrics/storage/InMemoryMetricsStorage.d.cts.map +0 -1
- package/dist/metrics/storage/InMemoryMetricsStorage.d.mts.map +0 -1
- package/dist/metrics/storage/InMemoryMetricsStorage.mjs.map +0 -1
- package/dist/metrics/storage/MetricsStorage.d.cts.map +0 -1
- package/dist/metrics/storage/MetricsStorage.d.mts.map +0 -1
- package/dist/metrics/storage/types.cjs.map +0 -1
- package/dist/metrics/storage/types.d.cts.map +0 -1
- package/dist/metrics/storage/types.d.mts.map +0 -1
- package/dist/metrics/storage/types.mjs.map +0 -1
- package/dist/otlp/receiver.cjs.map +0 -1
- package/dist/otlp/receiver.d.cts.map +0 -1
- package/dist/otlp/receiver.d.mts.map +0 -1
- package/dist/otlp/receiver.mjs.map +0 -1
- package/dist/otlp/transformer.cjs.map +0 -1
- package/dist/otlp/transformer.mjs.map +0 -1
- package/dist/otlp/types.cjs.map +0 -1
- package/dist/otlp/types.mjs.map +0 -1
- package/dist/redact.cjs.map +0 -1
- package/dist/redact.mjs.map +0 -1
- package/dist/storage/memory.cjs.map +0 -1
- package/dist/storage/memory.d.cts.map +0 -1
- package/dist/storage/memory.d.mts.map +0 -1
- package/dist/storage/memory.mjs.map +0 -1
- package/dist/transformer-BtqjAs0b.d.cts.map +0 -1
- package/dist/transformer-DI6t8-YA.d.mts.map +0 -1
- package/dist/types-BVujq4zd.d.cts.map +0 -1
- package/dist/types-BVujq4zd.d.mts.map +0 -1
- package/dist/types-DVETVdpa.d.cts.map +0 -1
- package/dist/types-DVETVdpa.d.mts.map +0 -1
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
//#region src/instrumentation/trust.ts
|
|
2
|
-
/**
|
|
3
|
-
* Whose `traceparent` an API continues.
|
|
4
|
-
*
|
|
5
|
-
* An incoming trace context is a claim made by the caller. Continued, it puts
|
|
6
|
-
* this request's span inside whatever trace the caller named, and its sampled
|
|
7
|
-
* flag asks this API to record it. From the API's own sites and from its own
|
|
8
|
-
* services that is the point; from anyone else it lets a stranger graft spans
|
|
9
|
-
* onto another user's trace, or force traces the stage's rate would not keep.
|
|
10
|
-
*
|
|
11
|
-
* So a request's context is continued only when it comes from a trusted source:
|
|
12
|
-
*
|
|
13
|
-
* - **its own sites** — an `Origin` header naming one of the API's allowed CORS
|
|
14
|
-
* origins (the sites with an edge to it). A browser sets `Origin` itself on
|
|
15
|
-
* every cross-origin request and a page cannot forge it;
|
|
16
|
-
* - **an internal caller** — no `Origin` at all, no header any reverse proxy
|
|
17
|
-
* adds (`X-Forwarded-For`, `Forwarded`, `X-Real-IP`, …), and a TCP peer on a
|
|
18
|
-
* loopback or private address. That is another service calling this one
|
|
19
|
-
* over the private network by its internal URL: a request from the internet
|
|
20
|
-
* reaches the API through the stack's proxy, which always adds a forwarding
|
|
21
|
-
* header, or from a public address.
|
|
22
|
-
*
|
|
23
|
-
* Anything else — an unknown origin, a request through the public proxy with
|
|
24
|
-
* no origin (curl, a server elsewhere) — starts a new trace, linked to the
|
|
25
|
-
* context it claimed so the hop can still be followed.
|
|
26
|
-
*
|
|
27
|
-
* Whether a trusted context is *sampled* is still this API's decision: see
|
|
28
|
-
* `traceSampler`, which caps an incoming sampled flag at the stage's rate.
|
|
29
|
-
*/
|
|
30
|
-
/**
|
|
31
|
-
* Headers a reverse proxy or CDN adds on the way in.
|
|
32
|
-
*
|
|
33
|
-
* Not `x-gkm-client-ip`: that is gkm's own, sent by a service calling another
|
|
34
|
-
* on a client's behalf (an API's session check), and stripped by the stack's
|
|
35
|
-
* edge from everything that arrives from outside.
|
|
36
|
-
*/
|
|
37
|
-
const FORWARDING_HEADERS = [
|
|
38
|
-
"forwarded",
|
|
39
|
-
"x-forwarded-for",
|
|
40
|
-
"x-forwarded-host",
|
|
41
|
-
"x-real-ip",
|
|
42
|
-
"cf-connecting-ip",
|
|
43
|
-
"true-client-ip",
|
|
44
|
-
"fastly-client-ip",
|
|
45
|
-
"x-client-ip"
|
|
46
|
-
];
|
|
47
|
-
/** `origin` normalized the way a browser sends it, or undefined. */
|
|
48
|
-
function normalizeOrigin(origin) {
|
|
49
|
-
try {
|
|
50
|
-
const url = new URL(origin);
|
|
51
|
-
return url.origin === "null" ? void 0 : url.origin;
|
|
52
|
-
} catch {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Whether `origin` is one of `trustedOrigins` — exactly, scheme, host and
|
|
58
|
-
* port. A wildcard trusts nothing: an API that answers any origin's CORS has
|
|
59
|
-
* not said which sites are its own.
|
|
60
|
-
*/
|
|
61
|
-
function isTrustedOrigin(origin, trustedOrigins) {
|
|
62
|
-
if (!origin || !trustedOrigins?.length) return false;
|
|
63
|
-
const normalized = normalizeOrigin(origin);
|
|
64
|
-
if (!normalized) return false;
|
|
65
|
-
return trustedOrigins.some((trusted) => trusted !== "*" && normalizeOrigin(trusted) === normalized);
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Whether `address` is loopback or private: 127/8, 10/8, 172.16/12,
|
|
69
|
-
* 192.168/16, 169.254/16, `::1`, `fc00::/7`, `fe80::/10`, and an IPv4 one
|
|
70
|
-
* mapped into IPv6.
|
|
71
|
-
*/
|
|
72
|
-
function isPrivateAddress(address) {
|
|
73
|
-
if (!address) return false;
|
|
74
|
-
const ip = address.toLowerCase().replace(/^::ffff:/, "");
|
|
75
|
-
const v4 = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
76
|
-
if (v4) {
|
|
77
|
-
const [a, b] = [Number(v4[1]), Number(v4[2])];
|
|
78
|
-
return a === 127 || a === 10 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 169 && b === 254;
|
|
79
|
-
}
|
|
80
|
-
if (ip === "::1") return true;
|
|
81
|
-
return /^f[cd][0-9a-f]{2}:/.test(ip) || /^fe[89ab][0-9a-f]:/.test(ip);
|
|
82
|
-
}
|
|
83
|
-
function header(headers, name) {
|
|
84
|
-
if (headers instanceof Headers) return headers.get(name) ?? void 0;
|
|
85
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
86
|
-
if (key.toLowerCase() !== name) continue;
|
|
87
|
-
return Array.isArray(value) ? value[0] : value;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Whether a request is an internal caller's: no `Origin`, no forwarding
|
|
92
|
-
* header, and a loopback or private peer. Without a peer address — a request
|
|
93
|
-
* handed to the app in-process, a runtime that does not expose the socket —
|
|
94
|
-
* it is not.
|
|
95
|
-
*/
|
|
96
|
-
function isInternalCaller(request) {
|
|
97
|
-
if (header(request.headers, "origin")) return false;
|
|
98
|
-
if (FORWARDING_HEADERS.some((name) => header(request.headers, name))) return false;
|
|
99
|
-
return isPrivateAddress(request.remoteAddress);
|
|
100
|
-
}
|
|
101
|
-
//#endregion
|
|
102
|
-
export { isInternalCaller, isPrivateAddress, isTrustedOrigin };
|
|
103
|
-
|
|
104
|
-
//# sourceMappingURL=trust.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"trust.mjs","names":[],"sources":["../../src/instrumentation/trust.ts"],"sourcesContent":["/**\n * Whose `traceparent` an API continues.\n *\n * An incoming trace context is a claim made by the caller. Continued, it puts\n * this request's span inside whatever trace the caller named, and its sampled\n * flag asks this API to record it. From the API's own sites and from its own\n * services that is the point; from anyone else it lets a stranger graft spans\n * onto another user's trace, or force traces the stage's rate would not keep.\n *\n * So a request's context is continued only when it comes from a trusted source:\n *\n * - **its own sites** — an `Origin` header naming one of the API's allowed CORS\n * origins (the sites with an edge to it). A browser sets `Origin` itself on\n * every cross-origin request and a page cannot forge it;\n * - **an internal caller** — no `Origin` at all, no header any reverse proxy\n * adds (`X-Forwarded-For`, `Forwarded`, `X-Real-IP`, …), and a TCP peer on a\n * loopback or private address. That is another service calling this one\n * over the private network by its internal URL: a request from the internet\n * reaches the API through the stack's proxy, which always adds a forwarding\n * header, or from a public address.\n *\n * Anything else — an unknown origin, a request through the public proxy with\n * no origin (curl, a server elsewhere) — starts a new trace, linked to the\n * context it claimed so the hop can still be followed.\n *\n * Whether a trusted context is *sampled* is still this API's decision: see\n * `traceSampler`, which caps an incoming sampled flag at the stage's rate.\n */\n\n/**\n * Headers a reverse proxy or CDN adds on the way in.\n *\n * Not `x-gkm-client-ip`: that is gkm's own, sent by a service calling another\n * on a client's behalf (an API's session check), and stripped by the stack's\n * edge from everything that arrives from outside.\n */\nconst FORWARDING_HEADERS = [\n\t'forwarded',\n\t'x-forwarded-for',\n\t'x-forwarded-host',\n\t'x-real-ip',\n\t'cf-connecting-ip',\n\t'true-client-ip',\n\t'fastly-client-ip',\n\t'x-client-ip',\n];\n\n/** `origin` normalized the way a browser sends it, or undefined. */\nfunction normalizeOrigin(origin: string): string | undefined {\n\ttry {\n\t\tconst url = new URL(origin);\n\t\treturn url.origin === 'null' ? undefined : url.origin;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Whether `origin` is one of `trustedOrigins` — exactly, scheme, host and\n * port. A wildcard trusts nothing: an API that answers any origin's CORS has\n * not said which sites are its own.\n */\nexport function isTrustedOrigin(\n\torigin: string | undefined,\n\ttrustedOrigins: readonly string[] | undefined,\n): boolean {\n\tif (!origin || !trustedOrigins?.length) return false;\n\tconst normalized = normalizeOrigin(origin);\n\tif (!normalized) return false;\n\treturn trustedOrigins.some(\n\t\t(trusted) => trusted !== '*' && normalizeOrigin(trusted) === normalized,\n\t);\n}\n\n/**\n * Whether `address` is loopback or private: 127/8, 10/8, 172.16/12,\n * 192.168/16, 169.254/16, `::1`, `fc00::/7`, `fe80::/10`, and an IPv4 one\n * mapped into IPv6.\n */\nexport function isPrivateAddress(address: string | undefined): boolean {\n\tif (!address) return false;\n\tconst ip = address.toLowerCase().replace(/^::ffff:/, '');\n\n\tconst v4 = ip.match(/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/);\n\tif (v4) {\n\t\tconst [a, b] = [Number(v4[1]), Number(v4[2])];\n\t\treturn (\n\t\t\ta === 127 ||\n\t\t\ta === 10 ||\n\t\t\t(a === 172 && b >= 16 && b <= 31) ||\n\t\t\t(a === 192 && b === 168) ||\n\t\t\t(a === 169 && b === 254)\n\t\t);\n\t}\n\n\tif (ip === '::1') return true;\n\treturn /^f[cd][0-9a-f]{2}:/.test(ip) || /^fe[89ab][0-9a-f]:/.test(ip);\n}\n\n/** What the internal-caller rule looks at. */\nexport interface IncomingRequestFacts {\n\t/** Every request header. */\n\theaders: Headers | Record<string, string | string[] | undefined>;\n\t/** The TCP peer's address, when the server knows it. */\n\tremoteAddress?: string;\n}\n\nfunction header(\n\theaders: IncomingRequestFacts['headers'],\n\tname: string,\n): string | undefined {\n\tif (headers instanceof Headers) return headers.get(name) ?? undefined;\n\tfor (const [key, value] of Object.entries(headers)) {\n\t\tif (key.toLowerCase() !== name) continue;\n\t\treturn Array.isArray(value) ? value[0] : value;\n\t}\n\treturn undefined;\n}\n\n/**\n * Whether a request is an internal caller's: no `Origin`, no forwarding\n * header, and a loopback or private peer. Without a peer address — a request\n * handed to the app in-process, a runtime that does not expose the socket —\n * it is not.\n */\nexport function isInternalCaller(request: IncomingRequestFacts): boolean {\n\tif (header(request.headers, 'origin')) return false;\n\tif (FORWARDING_HEADERS.some((name) => header(request.headers, name))) {\n\t\treturn false;\n\t}\n\treturn isPrivateAddress(request.remoteAddress);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,MAAM,qBAAqB;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;;AAGA,SAAS,gBAAgB,QAAoC;CAC5D,IAAI;EACH,MAAM,MAAM,IAAI,IAAI,MAAM;EAC1B,OAAO,IAAI,WAAW,SAAS,KAAA,IAAY,IAAI;CAChD,QAAQ;EACP;CACD;AACD;;;;;;AAOA,SAAgB,gBACf,QACA,gBACU;CACV,IAAI,CAAC,UAAU,CAAC,gBAAgB,QAAQ,OAAO;CAC/C,MAAM,aAAa,gBAAgB,MAAM;CACzC,IAAI,CAAC,YAAY,OAAO;CACxB,OAAO,eAAe,MACpB,YAAY,YAAY,OAAO,gBAAgB,OAAO,MAAM,UAC9D;AACD;;;;;;AAOA,SAAgB,iBAAiB,SAAsC;CACtE,IAAI,CAAC,SAAS,OAAO;CACrB,MAAM,KAAK,QAAQ,YAAY,CAAC,CAAC,QAAQ,YAAY,EAAE;CAEvD,MAAM,KAAK,GAAG,MAAM,8CAA8C;CAClE,IAAI,IAAI;EACP,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,GAAG,EAAE,GAAG,OAAO,GAAG,EAAE,CAAC;EAC5C,OACC,MAAM,OACN,MAAM,MACL,MAAM,OAAO,KAAK,MAAM,KAAK,MAC7B,MAAM,OAAO,MAAM,OACnB,MAAM,OAAO,MAAM;CAEtB;CAEA,IAAI,OAAO,OAAO,OAAO;CACzB,OAAO,qBAAqB,KAAK,EAAE,KAAK,qBAAqB,KAAK,EAAE;AACrE;AAUA,SAAS,OACR,SACA,MACqB;CACrB,IAAI,mBAAmB,SAAS,OAAO,QAAQ,IAAI,IAAI,KAAK,KAAA;CAC5D,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAAG;EACnD,IAAI,IAAI,YAAY,MAAM,MAAM;EAChC,OAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK;CAC1C;AAED;;;;;;;AAQA,SAAgB,iBAAiB,SAAwC;CACxE,IAAI,OAAO,QAAQ,SAAS,QAAQ,GAAG,OAAO;CAC9C,IAAI,mBAAmB,MAAM,SAAS,OAAO,QAAQ,SAAS,IAAI,CAAC,GAClE,OAAO;CAER,OAAO,iBAAiB,QAAQ,aAAa;AAC9C"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MetricsAggregator.cjs","names":[],"sources":["../../src/metrics/MetricsAggregator.ts"],"sourcesContent":["import type {\n\tEndpointBucket,\n\tEndpointDetails,\n\tEndpointMetrics,\n\tMetricsBucket,\n\tMetricsQueryOptions,\n\tRequestEntry,\n\tRequestMetrics,\n\tStatusDistribution,\n\tTimeRange,\n\tTimeSeriesPoint,\n} from '../types';\n\n/**\n * Configuration for MetricsAggregator\n */\nexport interface MetricsAggregatorOptions {\n\t/** Bucket size in milliseconds (default: 60000 = 1 minute) */\n\tbucketSize?: number;\n\t/** Maximum number of buckets to retain (default: 1440 = 24 hours at 1 min buckets) */\n\tmaxBuckets?: number;\n\t/** Maximum duration samples to keep per bucket for percentiles (default: 1000) */\n\tmaxSamplesPerBucket?: number;\n}\n\nconst DEFAULT_OPTIONS: Required<MetricsAggregatorOptions> = {\n\tbucketSize: 60_000, // 1 minute\n\tmaxBuckets: 1440, // 24 hours\n\tmaxSamplesPerBucket: 1000,\n};\n\n/**\n * In-memory metrics aggregator for Telescope.\n * Aggregates request data into time-bucketed metrics for efficient querying.\n */\n/**\n * Endpoint time bucket for per-endpoint time series\n */\ninterface EndpointTimeBucket {\n\ttimestamp: number;\n\tcount: number;\n\tdurationSum: number;\n\terrorCount: number;\n\tstatusDistribution: StatusDistribution;\n}\n\nexport class MetricsAggregator {\n\tprivate options: Required<MetricsAggregatorOptions>;\n\tprivate buckets: Map<number, MetricsBucket> = new Map();\n\tprivate endpoints: Map<string, EndpointBucket> = new Map();\n\t// Map of endpoint key -> Map of timestamp -> bucket\n\tprivate endpointTimeBuckets: Map<string, Map<number, EndpointTimeBucket>> =\n\t\tnew Map();\n\n\tconstructor(options: MetricsAggregatorOptions = {}) {\n\t\tthis.options = { ...DEFAULT_OPTIONS, ...options };\n\t}\n\n\t/**\n\t * Record a request for metrics aggregation\n\t */\n\trecord(entry: RequestEntry): void {\n\t\tconst timestamp = entry.timestamp.getTime();\n\t\tconst bucketTs = this.getBucketTimestamp(timestamp);\n\n\t\t// Update time bucket\n\t\tthis.updateBucket(bucketTs, entry);\n\n\t\t// Update endpoint metrics\n\t\tthis.updateEndpoint(entry);\n\n\t\t// Prune old buckets\n\t\tthis.pruneBuckets();\n\t}\n\n\t/**\n\t * Get aggregated request metrics\n\t */\n\tgetMetrics(options: MetricsQueryOptions = {}): RequestMetrics {\n\t\tconst range = options.range ?? this.getDefaultRange();\n\t\tconst bucketSize = options.bucketSize ?? this.options.bucketSize;\n\n\t\t// Get buckets in range\n\t\tconst bucketsInRange = this.getBucketsInRange(range);\n\n\t\tif (bucketsInRange.length === 0) {\n\t\t\treturn this.emptyMetrics();\n\t\t}\n\n\t\t// Aggregate all durations for percentile calculations\n\t\tconst allDurations: number[] = [];\n\t\tlet totalRequests = 0;\n\t\tlet totalDuration = 0;\n\t\tlet totalErrors = 0;\n\n\t\tfor (const bucket of bucketsInRange) {\n\t\t\ttotalRequests += bucket.count;\n\t\t\ttotalDuration += bucket.durationSum;\n\t\t\ttotalErrors += bucket.errorCount;\n\t\t\tallDurations.push(...bucket.durationSamples);\n\t\t}\n\n\t\t// Calculate percentiles\n\t\tallDurations.sort((a, b) => a - b);\n\t\tconst p50 = this.percentile(allDurations, 50);\n\t\tconst p95 = this.percentile(allDurations, 95);\n\t\tconst p99 = this.percentile(allDurations, 99);\n\n\t\t// Calculate rates\n\t\tconst rangeMs = range.end.getTime() - range.start.getTime();\n\t\tconst rangeSeconds = rangeMs / 1000;\n\t\tconst avgDuration = totalRequests > 0 ? totalDuration / totalRequests : 0;\n\t\tconst errorRate =\n\t\t\ttotalRequests > 0 ? (totalErrors / totalRequests) * 100 : 0;\n\n\t\t// Build time series (re-bucket if needed)\n\t\tconst timeSeries = this.buildTimeSeries(bucketsInRange, range, bucketSize);\n\n\t\treturn {\n\t\t\ttotalRequests,\n\t\t\tavgDuration,\n\t\t\tp50Duration: p50,\n\t\t\tp95Duration: p95,\n\t\t\tp99Duration: p99,\n\t\t\terrorRate,\n\t\t\tsuccessRate: 100 - errorRate,\n\t\t\trequestsPerSecond: rangeSeconds > 0 ? totalRequests / rangeSeconds : 0,\n\t\t\ttimeSeries,\n\t\t};\n\t}\n\n\t/**\n\t * Get metrics for individual endpoints\n\t */\n\tgetEndpointMetrics(options: MetricsQueryOptions = {}): EndpointMetrics[] {\n\t\tconst limit = options.limit ?? 50;\n\n\t\tconst results: EndpointMetrics[] = [];\n\n\t\tfor (const [, bucket] of this.endpoints) {\n\t\t\tconst avgDuration =\n\t\t\t\tbucket.count > 0 ? bucket.durationSum / bucket.count : 0;\n\t\t\tbucket.durationSamples.sort((a, b) => a - b);\n\t\t\tconst p95 = this.percentile(bucket.durationSamples, 95);\n\t\t\tconst errorRate =\n\t\t\t\tbucket.count > 0 ? (bucket.errorCount / bucket.count) * 100 : 0;\n\n\t\t\tresults.push({\n\t\t\t\tmethod: bucket.method,\n\t\t\t\tpath: bucket.path,\n\t\t\t\tcount: bucket.count,\n\t\t\t\tavgDuration,\n\t\t\t\tp95Duration: p95,\n\t\t\t\terrorRate,\n\t\t\t\tlastSeen: bucket.lastSeen,\n\t\t\t});\n\t\t}\n\n\t\t// Sort by count descending\n\t\tresults.sort((a, b) => b.count - a.count);\n\n\t\treturn results.slice(0, limit);\n\t}\n\n\t/**\n\t * Get status code distribution\n\t */\n\tgetStatusDistribution(options: MetricsQueryOptions = {}): StatusDistribution {\n\t\tconst range = options.range ?? this.getDefaultRange();\n\t\tconst bucketsInRange = this.getBucketsInRange(range);\n\n\t\tconst distribution: StatusDistribution = {\n\t\t\t'2xx': 0,\n\t\t\t'3xx': 0,\n\t\t\t'4xx': 0,\n\t\t\t'5xx': 0,\n\t\t};\n\n\t\tfor (const bucket of bucketsInRange) {\n\t\t\tdistribution['2xx'] += bucket.statusDistribution['2xx'];\n\t\t\tdistribution['3xx'] += bucket.statusDistribution['3xx'];\n\t\t\tdistribution['4xx'] += bucket.statusDistribution['4xx'];\n\t\t\tdistribution['5xx'] += bucket.statusDistribution['5xx'];\n\t\t}\n\n\t\treturn distribution;\n\t}\n\n\t/**\n\t * Get detailed metrics for a specific endpoint\n\t */\n\tgetEndpointDetails(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions: MetricsQueryOptions = {},\n\t): EndpointDetails | null {\n\t\tconst key = `${method}:${path}`;\n\t\tconst endpoint = this.endpoints.get(key);\n\n\t\tif (!endpoint) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Calculate percentiles\n\t\tconst samples = [...endpoint.durationSamples].sort((a, b) => a - b);\n\t\tconst p50 = this.percentile(samples, 50);\n\t\tconst p95 = this.percentile(samples, 95);\n\t\tconst p99 = this.percentile(samples, 99);\n\n\t\tconst avgDuration =\n\t\t\tendpoint.count > 0 ? endpoint.durationSum / endpoint.count : 0;\n\t\tconst errorRate =\n\t\t\tendpoint.count > 0 ? (endpoint.errorCount / endpoint.count) * 100 : 0;\n\n\t\t// Get time series for this endpoint\n\t\tconst endpointBuckets = this.endpointTimeBuckets.get(key);\n\t\tconst timeSeries: TimeSeriesPoint[] = [];\n\t\tconst statusDistribution: StatusDistribution = {\n\t\t\t'2xx': 0,\n\t\t\t'3xx': 0,\n\t\t\t'4xx': 0,\n\t\t\t'5xx': 0,\n\t\t};\n\n\t\tif (endpointBuckets) {\n\t\t\tconst range = options.range ?? this.getDefaultRange();\n\t\t\tconst startTs = range.start.getTime();\n\t\t\tconst endTs = range.end.getTime();\n\n\t\t\tfor (const [ts, bucket] of endpointBuckets) {\n\t\t\t\tif (ts >= startTs && ts <= endTs) {\n\t\t\t\t\ttimeSeries.push({\n\t\t\t\t\t\ttimestamp: bucket.timestamp,\n\t\t\t\t\t\tcount: bucket.count,\n\t\t\t\t\t\tavgDuration:\n\t\t\t\t\t\t\tbucket.count > 0 ? bucket.durationSum / bucket.count : 0,\n\t\t\t\t\t\terrorCount: bucket.errorCount,\n\t\t\t\t\t});\n\n\t\t\t\t\tstatusDistribution['2xx'] += bucket.statusDistribution['2xx'];\n\t\t\t\t\tstatusDistribution['3xx'] += bucket.statusDistribution['3xx'];\n\t\t\t\t\tstatusDistribution['4xx'] += bucket.statusDistribution['4xx'];\n\t\t\t\t\tstatusDistribution['5xx'] += bucket.statusDistribution['5xx'];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttimeSeries.sort((a, b) => a.timestamp - b.timestamp);\n\t\t}\n\n\t\treturn {\n\t\t\tmethod: endpoint.method,\n\t\t\tpath: endpoint.path,\n\t\t\tcount: endpoint.count,\n\t\t\tavgDuration,\n\t\t\tp50Duration: p50,\n\t\t\tp95Duration: p95,\n\t\t\tp99Duration: p99,\n\t\t\terrorRate,\n\t\t\tsuccessRate: 100 - errorRate,\n\t\t\tlastSeen: endpoint.lastSeen,\n\t\t\tstatusDistribution,\n\t\t\ttimeSeries,\n\t\t};\n\t}\n\n\t/**\n\t * Reset all metrics\n\t */\n\treset(): void {\n\t\tthis.buckets.clear();\n\t\tthis.endpoints.clear();\n\t\tthis.endpointTimeBuckets.clear();\n\t}\n\n\t// ============================================\n\t// Private Methods\n\t// ============================================\n\n\tprivate getBucketTimestamp(timestamp: number): number {\n\t\treturn (\n\t\t\tMath.floor(timestamp / this.options.bucketSize) * this.options.bucketSize\n\t\t);\n\t}\n\n\tprivate updateBucket(bucketTs: number, entry: RequestEntry): void {\n\t\tlet bucket = this.buckets.get(bucketTs);\n\n\t\tif (!bucket) {\n\t\t\tbucket = this.createEmptyBucket(bucketTs);\n\t\t\tthis.buckets.set(bucketTs, bucket);\n\t\t}\n\n\t\tbucket.count++;\n\t\tbucket.durationSum += entry.duration;\n\t\tbucket.durationMin = Math.min(bucket.durationMin, entry.duration);\n\t\tbucket.durationMax = Math.max(bucket.durationMax, entry.duration);\n\n\t\t// Keep samples for percentile calculations (with reservoir sampling if needed)\n\t\tif (bucket.durationSamples.length < this.options.maxSamplesPerBucket) {\n\t\t\tbucket.durationSamples.push(entry.duration);\n\t\t} else {\n\t\t\t// Reservoir sampling: replace random element\n\t\t\tconst idx = Math.floor(Math.random() * bucket.count);\n\t\t\tif (idx < this.options.maxSamplesPerBucket) {\n\t\t\t\tbucket.durationSamples[idx] = entry.duration;\n\t\t\t}\n\t\t}\n\n\t\t// Update status distribution\n\t\tconst isError = entry.status >= 400;\n\t\tif (isError) bucket.errorCount++;\n\n\t\tif (entry.status >= 200 && entry.status < 300) {\n\t\t\tbucket.statusDistribution['2xx']++;\n\t\t} else if (entry.status >= 300 && entry.status < 400) {\n\t\t\tbucket.statusDistribution['3xx']++;\n\t\t} else if (entry.status >= 400 && entry.status < 500) {\n\t\t\tbucket.statusDistribution['4xx']++;\n\t\t} else if (entry.status >= 500) {\n\t\t\tbucket.statusDistribution['5xx']++;\n\t\t}\n\t}\n\n\tprivate updateEndpoint(entry: RequestEntry): void {\n\t\tconst key = `${entry.method}:${entry.path}`;\n\t\tlet endpoint = this.endpoints.get(key);\n\n\t\tif (!endpoint) {\n\t\t\tendpoint = {\n\t\t\t\tmethod: entry.method,\n\t\t\t\tpath: entry.path,\n\t\t\t\tcount: 0,\n\t\t\t\tdurationSum: 0,\n\t\t\t\tdurationSamples: [],\n\t\t\t\terrorCount: 0,\n\t\t\t\tlastSeen: 0,\n\t\t\t};\n\t\t\tthis.endpoints.set(key, endpoint);\n\t\t}\n\n\t\tendpoint.count++;\n\t\tendpoint.durationSum += entry.duration;\n\t\tendpoint.lastSeen = entry.timestamp.getTime();\n\n\t\tif (entry.status >= 400) {\n\t\t\tendpoint.errorCount++;\n\t\t}\n\n\t\t// Keep samples for percentiles\n\t\tif (endpoint.durationSamples.length < this.options.maxSamplesPerBucket) {\n\t\t\tendpoint.durationSamples.push(entry.duration);\n\t\t} else {\n\t\t\tconst idx = Math.floor(Math.random() * endpoint.count);\n\t\t\tif (idx < this.options.maxSamplesPerBucket) {\n\t\t\t\tendpoint.durationSamples[idx] = entry.duration;\n\t\t\t}\n\t\t}\n\n\t\t// Update endpoint time bucket\n\t\tthis.updateEndpointTimeBucket(key, entry);\n\t}\n\n\tprivate updateEndpointTimeBucket(key: string, entry: RequestEntry): void {\n\t\tconst timestamp = entry.timestamp.getTime();\n\t\tconst bucketTs = this.getBucketTimestamp(timestamp);\n\n\t\tlet endpointBuckets = this.endpointTimeBuckets.get(key);\n\t\tif (!endpointBuckets) {\n\t\t\tendpointBuckets = new Map();\n\t\t\tthis.endpointTimeBuckets.set(key, endpointBuckets);\n\t\t}\n\n\t\tlet bucket = endpointBuckets.get(bucketTs);\n\t\tif (!bucket) {\n\t\t\tbucket = {\n\t\t\t\ttimestamp: bucketTs,\n\t\t\t\tcount: 0,\n\t\t\t\tdurationSum: 0,\n\t\t\t\terrorCount: 0,\n\t\t\t\tstatusDistribution: { '2xx': 0, '3xx': 0, '4xx': 0, '5xx': 0 },\n\t\t\t};\n\t\t\tendpointBuckets.set(bucketTs, bucket);\n\t\t}\n\n\t\tbucket.count++;\n\t\tbucket.durationSum += entry.duration;\n\n\t\tif (entry.status >= 400) {\n\t\t\tbucket.errorCount++;\n\t\t}\n\n\t\tif (entry.status >= 200 && entry.status < 300) {\n\t\t\tbucket.statusDistribution['2xx']++;\n\t\t} else if (entry.status >= 300 && entry.status < 400) {\n\t\t\tbucket.statusDistribution['3xx']++;\n\t\t} else if (entry.status >= 400 && entry.status < 500) {\n\t\t\tbucket.statusDistribution['4xx']++;\n\t\t} else if (entry.status >= 500) {\n\t\t\tbucket.statusDistribution['5xx']++;\n\t\t}\n\n\t\t// Prune old endpoint buckets (keep max buckets per endpoint)\n\t\tif (endpointBuckets.size > this.options.maxBuckets) {\n\t\t\tconst timestamps = Array.from(endpointBuckets.keys()).sort(\n\t\t\t\t(a, b) => a - b,\n\t\t\t);\n\t\t\tconst toRemove = timestamps.slice(\n\t\t\t\t0,\n\t\t\t\ttimestamps.length - this.options.maxBuckets,\n\t\t\t);\n\t\t\tfor (const ts of toRemove) {\n\t\t\t\tendpointBuckets.delete(ts);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate createEmptyBucket(timestamp: number): MetricsBucket {\n\t\treturn {\n\t\t\ttimestamp,\n\t\t\tbucketSize: this.options.bucketSize,\n\t\t\tcount: 0,\n\t\t\tdurationSum: 0,\n\t\t\tdurationMin: Infinity,\n\t\t\tdurationMax: 0,\n\t\t\tdurationSamples: [],\n\t\t\terrorCount: 0,\n\t\t\tstatusDistribution: {\n\t\t\t\t'2xx': 0,\n\t\t\t\t'3xx': 0,\n\t\t\t\t'4xx': 0,\n\t\t\t\t'5xx': 0,\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate pruneBuckets(): void {\n\t\tif (this.buckets.size <= this.options.maxBuckets) return;\n\n\t\t// Get sorted timestamps\n\t\tconst timestamps = Array.from(this.buckets.keys()).sort((a, b) => a - b);\n\n\t\t// Remove oldest buckets\n\t\tconst toRemove = timestamps.slice(\n\t\t\t0,\n\t\t\ttimestamps.length - this.options.maxBuckets,\n\t\t);\n\t\tfor (const ts of toRemove) {\n\t\t\tthis.buckets.delete(ts);\n\t\t}\n\t}\n\n\tprivate getDefaultRange(): TimeRange {\n\t\tconst now = new Date();\n\t\tconst oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);\n\t\treturn { start: oneHourAgo, end: now };\n\t}\n\n\tprivate getBucketsInRange(range: TimeRange): MetricsBucket[] {\n\t\tconst startTs = range.start.getTime();\n\t\tconst endTs = range.end.getTime();\n\n\t\tconst results: MetricsBucket[] = [];\n\t\tfor (const [ts, bucket] of this.buckets) {\n\t\t\tif (ts >= startTs && ts <= endTs) {\n\t\t\t\tresults.push(bucket);\n\t\t\t}\n\t\t}\n\n\t\treturn results.sort((a, b) => a.timestamp - b.timestamp);\n\t}\n\n\tprivate buildTimeSeries(\n\t\tbuckets: MetricsBucket[],\n\t\t_range: TimeRange,\n\t\ttargetBucketSize: number,\n\t): TimeSeriesPoint[] {\n\t\tif (buckets.length === 0) return [];\n\n\t\t// If target bucket size matches, just convert\n\t\tif (targetBucketSize === this.options.bucketSize) {\n\t\t\treturn buckets.map((b) => ({\n\t\t\t\ttimestamp: b.timestamp,\n\t\t\t\tcount: b.count,\n\t\t\t\tavgDuration: b.count > 0 ? b.durationSum / b.count : 0,\n\t\t\t\terrorCount: b.errorCount,\n\t\t\t}));\n\t\t}\n\n\t\t// Re-bucket into target size\n\t\tconst points: Map<number, TimeSeriesPoint> = new Map();\n\n\t\tfor (const bucket of buckets) {\n\t\t\tconst targetTs =\n\t\t\t\tMath.floor(bucket.timestamp / targetBucketSize) * targetBucketSize;\n\t\t\tlet point = points.get(targetTs);\n\n\t\t\tif (!point) {\n\t\t\t\tpoint = {\n\t\t\t\t\ttimestamp: targetTs,\n\t\t\t\t\tcount: 0,\n\t\t\t\t\tavgDuration: 0,\n\t\t\t\t\terrorCount: 0,\n\t\t\t\t};\n\t\t\t\tpoints.set(targetTs, point);\n\t\t\t}\n\n\t\t\t// Weighted average for duration\n\t\t\tconst totalCount = point.count + bucket.count;\n\t\t\tif (totalCount > 0) {\n\t\t\t\tpoint.avgDuration =\n\t\t\t\t\t(point.avgDuration * point.count +\n\t\t\t\t\t\t(bucket.count > 0 ? bucket.durationSum / bucket.count : 0) *\n\t\t\t\t\t\t\tbucket.count) /\n\t\t\t\t\ttotalCount;\n\t\t\t}\n\t\t\tpoint.count = totalCount;\n\t\t\tpoint.errorCount += bucket.errorCount;\n\t\t}\n\n\t\treturn Array.from(points.values()).sort(\n\t\t\t(a, b) => a.timestamp - b.timestamp,\n\t\t);\n\t}\n\n\tprivate percentile(sortedValues: number[], p: number): number {\n\t\tif (sortedValues.length === 0) return 0;\n\t\tif (sortedValues.length === 1) return sortedValues[0]!;\n\n\t\tconst index = (p / 100) * (sortedValues.length - 1);\n\t\tconst lower = Math.floor(index);\n\t\tconst upper = Math.ceil(index);\n\n\t\tif (lower === upper) return sortedValues[lower]!;\n\n\t\t// Linear interpolation\n\t\tconst weight = index - lower;\n\t\tconst lowerVal = sortedValues[lower]!;\n\t\tconst upperVal = sortedValues[upper]!;\n\t\treturn lowerVal * (1 - weight) + upperVal * weight;\n\t}\n\n\tprivate emptyMetrics(): RequestMetrics {\n\t\treturn {\n\t\t\ttotalRequests: 0,\n\t\t\tavgDuration: 0,\n\t\t\tp50Duration: 0,\n\t\t\tp95Duration: 0,\n\t\t\tp99Duration: 0,\n\t\t\terrorRate: 0,\n\t\t\tsuccessRate: 100,\n\t\t\trequestsPerSecond: 0,\n\t\t\ttimeSeries: [],\n\t\t};\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MetricsAggregator.mjs","names":[],"sources":["../../src/metrics/MetricsAggregator.ts"],"sourcesContent":["import type {\n\tEndpointBucket,\n\tEndpointDetails,\n\tEndpointMetrics,\n\tMetricsBucket,\n\tMetricsQueryOptions,\n\tRequestEntry,\n\tRequestMetrics,\n\tStatusDistribution,\n\tTimeRange,\n\tTimeSeriesPoint,\n} from '../types';\n\n/**\n * Configuration for MetricsAggregator\n */\nexport interface MetricsAggregatorOptions {\n\t/** Bucket size in milliseconds (default: 60000 = 1 minute) */\n\tbucketSize?: number;\n\t/** Maximum number of buckets to retain (default: 1440 = 24 hours at 1 min buckets) */\n\tmaxBuckets?: number;\n\t/** Maximum duration samples to keep per bucket for percentiles (default: 1000) */\n\tmaxSamplesPerBucket?: number;\n}\n\nconst DEFAULT_OPTIONS: Required<MetricsAggregatorOptions> = {\n\tbucketSize: 60_000, // 1 minute\n\tmaxBuckets: 1440, // 24 hours\n\tmaxSamplesPerBucket: 1000,\n};\n\n/**\n * In-memory metrics aggregator for Telescope.\n * Aggregates request data into time-bucketed metrics for efficient querying.\n */\n/**\n * Endpoint time bucket for per-endpoint time series\n */\ninterface EndpointTimeBucket {\n\ttimestamp: number;\n\tcount: number;\n\tdurationSum: number;\n\terrorCount: number;\n\tstatusDistribution: StatusDistribution;\n}\n\nexport class MetricsAggregator {\n\tprivate options: Required<MetricsAggregatorOptions>;\n\tprivate buckets: Map<number, MetricsBucket> = new Map();\n\tprivate endpoints: Map<string, EndpointBucket> = new Map();\n\t// Map of endpoint key -> Map of timestamp -> bucket\n\tprivate endpointTimeBuckets: Map<string, Map<number, EndpointTimeBucket>> =\n\t\tnew Map();\n\n\tconstructor(options: MetricsAggregatorOptions = {}) {\n\t\tthis.options = { ...DEFAULT_OPTIONS, ...options };\n\t}\n\n\t/**\n\t * Record a request for metrics aggregation\n\t */\n\trecord(entry: RequestEntry): void {\n\t\tconst timestamp = entry.timestamp.getTime();\n\t\tconst bucketTs = this.getBucketTimestamp(timestamp);\n\n\t\t// Update time bucket\n\t\tthis.updateBucket(bucketTs, entry);\n\n\t\t// Update endpoint metrics\n\t\tthis.updateEndpoint(entry);\n\n\t\t// Prune old buckets\n\t\tthis.pruneBuckets();\n\t}\n\n\t/**\n\t * Get aggregated request metrics\n\t */\n\tgetMetrics(options: MetricsQueryOptions = {}): RequestMetrics {\n\t\tconst range = options.range ?? this.getDefaultRange();\n\t\tconst bucketSize = options.bucketSize ?? this.options.bucketSize;\n\n\t\t// Get buckets in range\n\t\tconst bucketsInRange = this.getBucketsInRange(range);\n\n\t\tif (bucketsInRange.length === 0) {\n\t\t\treturn this.emptyMetrics();\n\t\t}\n\n\t\t// Aggregate all durations for percentile calculations\n\t\tconst allDurations: number[] = [];\n\t\tlet totalRequests = 0;\n\t\tlet totalDuration = 0;\n\t\tlet totalErrors = 0;\n\n\t\tfor (const bucket of bucketsInRange) {\n\t\t\ttotalRequests += bucket.count;\n\t\t\ttotalDuration += bucket.durationSum;\n\t\t\ttotalErrors += bucket.errorCount;\n\t\t\tallDurations.push(...bucket.durationSamples);\n\t\t}\n\n\t\t// Calculate percentiles\n\t\tallDurations.sort((a, b) => a - b);\n\t\tconst p50 = this.percentile(allDurations, 50);\n\t\tconst p95 = this.percentile(allDurations, 95);\n\t\tconst p99 = this.percentile(allDurations, 99);\n\n\t\t// Calculate rates\n\t\tconst rangeMs = range.end.getTime() - range.start.getTime();\n\t\tconst rangeSeconds = rangeMs / 1000;\n\t\tconst avgDuration = totalRequests > 0 ? totalDuration / totalRequests : 0;\n\t\tconst errorRate =\n\t\t\ttotalRequests > 0 ? (totalErrors / totalRequests) * 100 : 0;\n\n\t\t// Build time series (re-bucket if needed)\n\t\tconst timeSeries = this.buildTimeSeries(bucketsInRange, range, bucketSize);\n\n\t\treturn {\n\t\t\ttotalRequests,\n\t\t\tavgDuration,\n\t\t\tp50Duration: p50,\n\t\t\tp95Duration: p95,\n\t\t\tp99Duration: p99,\n\t\t\terrorRate,\n\t\t\tsuccessRate: 100 - errorRate,\n\t\t\trequestsPerSecond: rangeSeconds > 0 ? totalRequests / rangeSeconds : 0,\n\t\t\ttimeSeries,\n\t\t};\n\t}\n\n\t/**\n\t * Get metrics for individual endpoints\n\t */\n\tgetEndpointMetrics(options: MetricsQueryOptions = {}): EndpointMetrics[] {\n\t\tconst limit = options.limit ?? 50;\n\n\t\tconst results: EndpointMetrics[] = [];\n\n\t\tfor (const [, bucket] of this.endpoints) {\n\t\t\tconst avgDuration =\n\t\t\t\tbucket.count > 0 ? bucket.durationSum / bucket.count : 0;\n\t\t\tbucket.durationSamples.sort((a, b) => a - b);\n\t\t\tconst p95 = this.percentile(bucket.durationSamples, 95);\n\t\t\tconst errorRate =\n\t\t\t\tbucket.count > 0 ? (bucket.errorCount / bucket.count) * 100 : 0;\n\n\t\t\tresults.push({\n\t\t\t\tmethod: bucket.method,\n\t\t\t\tpath: bucket.path,\n\t\t\t\tcount: bucket.count,\n\t\t\t\tavgDuration,\n\t\t\t\tp95Duration: p95,\n\t\t\t\terrorRate,\n\t\t\t\tlastSeen: bucket.lastSeen,\n\t\t\t});\n\t\t}\n\n\t\t// Sort by count descending\n\t\tresults.sort((a, b) => b.count - a.count);\n\n\t\treturn results.slice(0, limit);\n\t}\n\n\t/**\n\t * Get status code distribution\n\t */\n\tgetStatusDistribution(options: MetricsQueryOptions = {}): StatusDistribution {\n\t\tconst range = options.range ?? this.getDefaultRange();\n\t\tconst bucketsInRange = this.getBucketsInRange(range);\n\n\t\tconst distribution: StatusDistribution = {\n\t\t\t'2xx': 0,\n\t\t\t'3xx': 0,\n\t\t\t'4xx': 0,\n\t\t\t'5xx': 0,\n\t\t};\n\n\t\tfor (const bucket of bucketsInRange) {\n\t\t\tdistribution['2xx'] += bucket.statusDistribution['2xx'];\n\t\t\tdistribution['3xx'] += bucket.statusDistribution['3xx'];\n\t\t\tdistribution['4xx'] += bucket.statusDistribution['4xx'];\n\t\t\tdistribution['5xx'] += bucket.statusDistribution['5xx'];\n\t\t}\n\n\t\treturn distribution;\n\t}\n\n\t/**\n\t * Get detailed metrics for a specific endpoint\n\t */\n\tgetEndpointDetails(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions: MetricsQueryOptions = {},\n\t): EndpointDetails | null {\n\t\tconst key = `${method}:${path}`;\n\t\tconst endpoint = this.endpoints.get(key);\n\n\t\tif (!endpoint) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Calculate percentiles\n\t\tconst samples = [...endpoint.durationSamples].sort((a, b) => a - b);\n\t\tconst p50 = this.percentile(samples, 50);\n\t\tconst p95 = this.percentile(samples, 95);\n\t\tconst p99 = this.percentile(samples, 99);\n\n\t\tconst avgDuration =\n\t\t\tendpoint.count > 0 ? endpoint.durationSum / endpoint.count : 0;\n\t\tconst errorRate =\n\t\t\tendpoint.count > 0 ? (endpoint.errorCount / endpoint.count) * 100 : 0;\n\n\t\t// Get time series for this endpoint\n\t\tconst endpointBuckets = this.endpointTimeBuckets.get(key);\n\t\tconst timeSeries: TimeSeriesPoint[] = [];\n\t\tconst statusDistribution: StatusDistribution = {\n\t\t\t'2xx': 0,\n\t\t\t'3xx': 0,\n\t\t\t'4xx': 0,\n\t\t\t'5xx': 0,\n\t\t};\n\n\t\tif (endpointBuckets) {\n\t\t\tconst range = options.range ?? this.getDefaultRange();\n\t\t\tconst startTs = range.start.getTime();\n\t\t\tconst endTs = range.end.getTime();\n\n\t\t\tfor (const [ts, bucket] of endpointBuckets) {\n\t\t\t\tif (ts >= startTs && ts <= endTs) {\n\t\t\t\t\ttimeSeries.push({\n\t\t\t\t\t\ttimestamp: bucket.timestamp,\n\t\t\t\t\t\tcount: bucket.count,\n\t\t\t\t\t\tavgDuration:\n\t\t\t\t\t\t\tbucket.count > 0 ? bucket.durationSum / bucket.count : 0,\n\t\t\t\t\t\terrorCount: bucket.errorCount,\n\t\t\t\t\t});\n\n\t\t\t\t\tstatusDistribution['2xx'] += bucket.statusDistribution['2xx'];\n\t\t\t\t\tstatusDistribution['3xx'] += bucket.statusDistribution['3xx'];\n\t\t\t\t\tstatusDistribution['4xx'] += bucket.statusDistribution['4xx'];\n\t\t\t\t\tstatusDistribution['5xx'] += bucket.statusDistribution['5xx'];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttimeSeries.sort((a, b) => a.timestamp - b.timestamp);\n\t\t}\n\n\t\treturn {\n\t\t\tmethod: endpoint.method,\n\t\t\tpath: endpoint.path,\n\t\t\tcount: endpoint.count,\n\t\t\tavgDuration,\n\t\t\tp50Duration: p50,\n\t\t\tp95Duration: p95,\n\t\t\tp99Duration: p99,\n\t\t\terrorRate,\n\t\t\tsuccessRate: 100 - errorRate,\n\t\t\tlastSeen: endpoint.lastSeen,\n\t\t\tstatusDistribution,\n\t\t\ttimeSeries,\n\t\t};\n\t}\n\n\t/**\n\t * Reset all metrics\n\t */\n\treset(): void {\n\t\tthis.buckets.clear();\n\t\tthis.endpoints.clear();\n\t\tthis.endpointTimeBuckets.clear();\n\t}\n\n\t// ============================================\n\t// Private Methods\n\t// ============================================\n\n\tprivate getBucketTimestamp(timestamp: number): number {\n\t\treturn (\n\t\t\tMath.floor(timestamp / this.options.bucketSize) * this.options.bucketSize\n\t\t);\n\t}\n\n\tprivate updateBucket(bucketTs: number, entry: RequestEntry): void {\n\t\tlet bucket = this.buckets.get(bucketTs);\n\n\t\tif (!bucket) {\n\t\t\tbucket = this.createEmptyBucket(bucketTs);\n\t\t\tthis.buckets.set(bucketTs, bucket);\n\t\t}\n\n\t\tbucket.count++;\n\t\tbucket.durationSum += entry.duration;\n\t\tbucket.durationMin = Math.min(bucket.durationMin, entry.duration);\n\t\tbucket.durationMax = Math.max(bucket.durationMax, entry.duration);\n\n\t\t// Keep samples for percentile calculations (with reservoir sampling if needed)\n\t\tif (bucket.durationSamples.length < this.options.maxSamplesPerBucket) {\n\t\t\tbucket.durationSamples.push(entry.duration);\n\t\t} else {\n\t\t\t// Reservoir sampling: replace random element\n\t\t\tconst idx = Math.floor(Math.random() * bucket.count);\n\t\t\tif (idx < this.options.maxSamplesPerBucket) {\n\t\t\t\tbucket.durationSamples[idx] = entry.duration;\n\t\t\t}\n\t\t}\n\n\t\t// Update status distribution\n\t\tconst isError = entry.status >= 400;\n\t\tif (isError) bucket.errorCount++;\n\n\t\tif (entry.status >= 200 && entry.status < 300) {\n\t\t\tbucket.statusDistribution['2xx']++;\n\t\t} else if (entry.status >= 300 && entry.status < 400) {\n\t\t\tbucket.statusDistribution['3xx']++;\n\t\t} else if (entry.status >= 400 && entry.status < 500) {\n\t\t\tbucket.statusDistribution['4xx']++;\n\t\t} else if (entry.status >= 500) {\n\t\t\tbucket.statusDistribution['5xx']++;\n\t\t}\n\t}\n\n\tprivate updateEndpoint(entry: RequestEntry): void {\n\t\tconst key = `${entry.method}:${entry.path}`;\n\t\tlet endpoint = this.endpoints.get(key);\n\n\t\tif (!endpoint) {\n\t\t\tendpoint = {\n\t\t\t\tmethod: entry.method,\n\t\t\t\tpath: entry.path,\n\t\t\t\tcount: 0,\n\t\t\t\tdurationSum: 0,\n\t\t\t\tdurationSamples: [],\n\t\t\t\terrorCount: 0,\n\t\t\t\tlastSeen: 0,\n\t\t\t};\n\t\t\tthis.endpoints.set(key, endpoint);\n\t\t}\n\n\t\tendpoint.count++;\n\t\tendpoint.durationSum += entry.duration;\n\t\tendpoint.lastSeen = entry.timestamp.getTime();\n\n\t\tif (entry.status >= 400) {\n\t\t\tendpoint.errorCount++;\n\t\t}\n\n\t\t// Keep samples for percentiles\n\t\tif (endpoint.durationSamples.length < this.options.maxSamplesPerBucket) {\n\t\t\tendpoint.durationSamples.push(entry.duration);\n\t\t} else {\n\t\t\tconst idx = Math.floor(Math.random() * endpoint.count);\n\t\t\tif (idx < this.options.maxSamplesPerBucket) {\n\t\t\t\tendpoint.durationSamples[idx] = entry.duration;\n\t\t\t}\n\t\t}\n\n\t\t// Update endpoint time bucket\n\t\tthis.updateEndpointTimeBucket(key, entry);\n\t}\n\n\tprivate updateEndpointTimeBucket(key: string, entry: RequestEntry): void {\n\t\tconst timestamp = entry.timestamp.getTime();\n\t\tconst bucketTs = this.getBucketTimestamp(timestamp);\n\n\t\tlet endpointBuckets = this.endpointTimeBuckets.get(key);\n\t\tif (!endpointBuckets) {\n\t\t\tendpointBuckets = new Map();\n\t\t\tthis.endpointTimeBuckets.set(key, endpointBuckets);\n\t\t}\n\n\t\tlet bucket = endpointBuckets.get(bucketTs);\n\t\tif (!bucket) {\n\t\t\tbucket = {\n\t\t\t\ttimestamp: bucketTs,\n\t\t\t\tcount: 0,\n\t\t\t\tdurationSum: 0,\n\t\t\t\terrorCount: 0,\n\t\t\t\tstatusDistribution: { '2xx': 0, '3xx': 0, '4xx': 0, '5xx': 0 },\n\t\t\t};\n\t\t\tendpointBuckets.set(bucketTs, bucket);\n\t\t}\n\n\t\tbucket.count++;\n\t\tbucket.durationSum += entry.duration;\n\n\t\tif (entry.status >= 400) {\n\t\t\tbucket.errorCount++;\n\t\t}\n\n\t\tif (entry.status >= 200 && entry.status < 300) {\n\t\t\tbucket.statusDistribution['2xx']++;\n\t\t} else if (entry.status >= 300 && entry.status < 400) {\n\t\t\tbucket.statusDistribution['3xx']++;\n\t\t} else if (entry.status >= 400 && entry.status < 500) {\n\t\t\tbucket.statusDistribution['4xx']++;\n\t\t} else if (entry.status >= 500) {\n\t\t\tbucket.statusDistribution['5xx']++;\n\t\t}\n\n\t\t// Prune old endpoint buckets (keep max buckets per endpoint)\n\t\tif (endpointBuckets.size > this.options.maxBuckets) {\n\t\t\tconst timestamps = Array.from(endpointBuckets.keys()).sort(\n\t\t\t\t(a, b) => a - b,\n\t\t\t);\n\t\t\tconst toRemove = timestamps.slice(\n\t\t\t\t0,\n\t\t\t\ttimestamps.length - this.options.maxBuckets,\n\t\t\t);\n\t\t\tfor (const ts of toRemove) {\n\t\t\t\tendpointBuckets.delete(ts);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate createEmptyBucket(timestamp: number): MetricsBucket {\n\t\treturn {\n\t\t\ttimestamp,\n\t\t\tbucketSize: this.options.bucketSize,\n\t\t\tcount: 0,\n\t\t\tdurationSum: 0,\n\t\t\tdurationMin: Infinity,\n\t\t\tdurationMax: 0,\n\t\t\tdurationSamples: [],\n\t\t\terrorCount: 0,\n\t\t\tstatusDistribution: {\n\t\t\t\t'2xx': 0,\n\t\t\t\t'3xx': 0,\n\t\t\t\t'4xx': 0,\n\t\t\t\t'5xx': 0,\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate pruneBuckets(): void {\n\t\tif (this.buckets.size <= this.options.maxBuckets) return;\n\n\t\t// Get sorted timestamps\n\t\tconst timestamps = Array.from(this.buckets.keys()).sort((a, b) => a - b);\n\n\t\t// Remove oldest buckets\n\t\tconst toRemove = timestamps.slice(\n\t\t\t0,\n\t\t\ttimestamps.length - this.options.maxBuckets,\n\t\t);\n\t\tfor (const ts of toRemove) {\n\t\t\tthis.buckets.delete(ts);\n\t\t}\n\t}\n\n\tprivate getDefaultRange(): TimeRange {\n\t\tconst now = new Date();\n\t\tconst oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);\n\t\treturn { start: oneHourAgo, end: now };\n\t}\n\n\tprivate getBucketsInRange(range: TimeRange): MetricsBucket[] {\n\t\tconst startTs = range.start.getTime();\n\t\tconst endTs = range.end.getTime();\n\n\t\tconst results: MetricsBucket[] = [];\n\t\tfor (const [ts, bucket] of this.buckets) {\n\t\t\tif (ts >= startTs && ts <= endTs) {\n\t\t\t\tresults.push(bucket);\n\t\t\t}\n\t\t}\n\n\t\treturn results.sort((a, b) => a.timestamp - b.timestamp);\n\t}\n\n\tprivate buildTimeSeries(\n\t\tbuckets: MetricsBucket[],\n\t\t_range: TimeRange,\n\t\ttargetBucketSize: number,\n\t): TimeSeriesPoint[] {\n\t\tif (buckets.length === 0) return [];\n\n\t\t// If target bucket size matches, just convert\n\t\tif (targetBucketSize === this.options.bucketSize) {\n\t\t\treturn buckets.map((b) => ({\n\t\t\t\ttimestamp: b.timestamp,\n\t\t\t\tcount: b.count,\n\t\t\t\tavgDuration: b.count > 0 ? b.durationSum / b.count : 0,\n\t\t\t\terrorCount: b.errorCount,\n\t\t\t}));\n\t\t}\n\n\t\t// Re-bucket into target size\n\t\tconst points: Map<number, TimeSeriesPoint> = new Map();\n\n\t\tfor (const bucket of buckets) {\n\t\t\tconst targetTs =\n\t\t\t\tMath.floor(bucket.timestamp / targetBucketSize) * targetBucketSize;\n\t\t\tlet point = points.get(targetTs);\n\n\t\t\tif (!point) {\n\t\t\t\tpoint = {\n\t\t\t\t\ttimestamp: targetTs,\n\t\t\t\t\tcount: 0,\n\t\t\t\t\tavgDuration: 0,\n\t\t\t\t\terrorCount: 0,\n\t\t\t\t};\n\t\t\t\tpoints.set(targetTs, point);\n\t\t\t}\n\n\t\t\t// Weighted average for duration\n\t\t\tconst totalCount = point.count + bucket.count;\n\t\t\tif (totalCount > 0) {\n\t\t\t\tpoint.avgDuration =\n\t\t\t\t\t(point.avgDuration * point.count +\n\t\t\t\t\t\t(bucket.count > 0 ? bucket.durationSum / bucket.count : 0) *\n\t\t\t\t\t\t\tbucket.count) /\n\t\t\t\t\ttotalCount;\n\t\t\t}\n\t\t\tpoint.count = totalCount;\n\t\t\tpoint.errorCount += bucket.errorCount;\n\t\t}\n\n\t\treturn Array.from(points.values()).sort(\n\t\t\t(a, b) => a.timestamp - b.timestamp,\n\t\t);\n\t}\n\n\tprivate percentile(sortedValues: number[], p: number): number {\n\t\tif (sortedValues.length === 0) return 0;\n\t\tif (sortedValues.length === 1) return sortedValues[0]!;\n\n\t\tconst index = (p / 100) * (sortedValues.length - 1);\n\t\tconst lower = Math.floor(index);\n\t\tconst upper = Math.ceil(index);\n\n\t\tif (lower === upper) return sortedValues[lower]!;\n\n\t\t// Linear interpolation\n\t\tconst weight = index - lower;\n\t\tconst lowerVal = sortedValues[lower]!;\n\t\tconst upperVal = sortedValues[upper]!;\n\t\treturn lowerVal * (1 - weight) + upperVal * weight;\n\t}\n\n\tprivate emptyMetrics(): RequestMetrics {\n\t\treturn {\n\t\t\ttotalRequests: 0,\n\t\t\tavgDuration: 0,\n\t\t\tp50Duration: 0,\n\t\t\tp95Duration: 0,\n\t\t\tp99Duration: 0,\n\t\t\terrorRate: 0,\n\t\t\tsuccessRate: 100,\n\t\t\trequestsPerSecond: 0,\n\t\t\ttimeSeries: [],\n\t\t};\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"InMemoryMetricsStorage.cjs","names":["DEFAULT_METRICS_CONFIG"],"sources":["../../../src/metrics/storage/InMemoryMetricsStorage.ts"],"sourcesContent":["import type { MetricsStorage } from './MetricsStorage';\nimport {\n\ttype AggregationInterval,\n\tDEFAULT_METRICS_CONFIG,\n\ttype MetricBucket,\n\ttype MetricLabels,\n\ttype MetricPoint,\n\ttype MetricQuery,\n\ttype MetricResult,\n\ttype MetricsStorageConfig,\n\ttype PartitionInfo,\n\ttype RollupOptions,\n} from './types';\n\n/**\n * In-memory metrics storage for development and testing.\n *\n * Features:\n * - Buffered writes with configurable flush interval\n * - Time-bucketed aggregation\n * - Basic percentile calculation (reservoir sampling)\n * - Automatic pruning based on retention\n *\n * Not suitable for production - use a proper time-series database.\n */\nexport class InMemoryMetricsStorage implements MetricsStorage {\n\tprivate config: MetricsStorageConfig;\n\tprivate buffer: MetricPoint[] = [];\n\tprivate buckets: Map<string, MetricBucket> = new Map();\n\tprivate samples: Map<string, number[]> = new Map(); // For percentile calculations\n\tprivate flushTimer: ReturnType<typeof setInterval> | null = null;\n\n\tconstructor(config: Partial<MetricsStorageConfig> = {}) {\n\t\tthis.config = { ...DEFAULT_METRICS_CONFIG, ...config };\n\n\t\tif (this.config.flushInterval > 0) {\n\t\t\tthis.flushTimer = setInterval(() => {\n\t\t\t\tthis.flush().catch(console.error);\n\t\t\t}, this.config.flushInterval);\n\t\t}\n\t}\n\n\tasync write(points: MetricPoint[]): Promise<void> {\n\t\tthis.buffer.push(...points);\n\n\t\tif (this.buffer.length >= this.config.maxBatchSize) {\n\t\t\tawait this.flush();\n\t\t}\n\t}\n\n\tasync flush(): Promise<void> {\n\t\tif (this.buffer.length === 0) return;\n\n\t\tconst points = this.buffer.splice(0);\n\n\t\tfor (const point of points) {\n\t\t\tthis.aggregatePoint(point);\n\t\t}\n\n\t\t// Prune if auto-rollup is enabled\n\t\tif (this.config.autoRollup) {\n\t\t\tawait this.prune();\n\t\t}\n\t}\n\n\tprivate aggregatePoint(point: MetricPoint): void {\n\t\tconst bucketTime = this.getBucketTime(point.timestamp, '1m');\n\t\tconst key = this.getBucketKey(point, bucketTime);\n\n\t\tconst existing = this.buckets.get(key);\n\n\t\tif (existing) {\n\t\t\texisting.count += 1;\n\t\t\texisting.sum += point.value;\n\t\t\texisting.min = Math.min(existing.min, point.value);\n\t\t\texisting.max = Math.max(existing.max, point.value);\n\t\t} else {\n\t\t\tthis.buckets.set(key, {\n\t\t\t\tbucket: bucketTime,\n\t\t\t\tprojectId: point.projectId,\n\t\t\t\tservice: point.service,\n\t\t\t\tenvironment: point.environment,\n\t\t\t\tname: point.name,\n\t\t\t\tlabelsHash: this.hashLabels(point.labels),\n\t\t\t\tlabels: { ...point.labels },\n\t\t\t\tcount: 1,\n\t\t\t\tsum: point.value,\n\t\t\t\tmin: point.value,\n\t\t\t\tmax: point.value,\n\t\t\t});\n\t\t}\n\n\t\t// Store samples for percentile calculations (reservoir sampling)\n\t\tconst sampleKey = `${point.projectId}:${point.name}:${bucketTime.getTime()}`;\n\t\tconst samples = this.samples.get(sampleKey) ?? [];\n\t\tif (samples.length < 1000) {\n\t\t\tsamples.push(point.value);\n\t\t} else {\n\t\t\t// Reservoir sampling\n\t\t\tconst idx = Math.floor(Math.random() * (samples.length + 1));\n\t\t\tif (idx < samples.length) {\n\t\t\t\tsamples[idx] = point.value;\n\t\t\t}\n\t\t}\n\t\tthis.samples.set(sampleKey, samples);\n\t}\n\n\tasync query(query: MetricQuery): Promise<MetricResult[]> {\n\t\tawait this.flush();\n\n\t\tconst results = new Map<string, MetricResult>();\n\t\tconst startTime = query.range.start.getTime();\n\t\tconst endTime = query.range.end.getTime();\n\t\tconst interval = query.interval ?? '1m';\n\t\tconst intervalMs = this.getIntervalMs(interval);\n\n\t\tfor (const [, bucket] of this.buckets) {\n\t\t\tif (bucket.projectId !== query.projectId) continue;\n\t\t\tif (query.service && bucket.service !== query.service) continue;\n\t\t\tif (query.environment && bucket.environment !== query.environment)\n\t\t\t\tcontinue;\n\t\t\tif (query.name && !this.matchesPattern(bucket.name, query.name)) continue;\n\t\t\tif (query.labels && !this.matchesLabels(bucket.labels, query.labels))\n\t\t\t\tcontinue;\n\n\t\t\tconst bucketTime = bucket.bucket.getTime();\n\t\t\tif (bucketTime < startTime || bucketTime > endTime) continue;\n\n\t\t\t// Group by metric name + labels\n\t\t\tconst groupKey = query.groupBy\n\t\t\t\t? this.getGroupKey(bucket, query.groupBy)\n\t\t\t\t: bucket.name;\n\n\t\t\tlet result = results.get(groupKey);\n\t\t\tif (!result) {\n\t\t\t\tresult = {\n\t\t\t\t\tname: bucket.name,\n\t\t\t\t\tlabels: query.groupBy\n\t\t\t\t\t\t? this.filterLabels(bucket.labels, query.groupBy)\n\t\t\t\t\t\t: bucket.labels,\n\t\t\t\t\ttimeSeries: [],\n\t\t\t\t\tstats: {\n\t\t\t\t\t\tcount: 0,\n\t\t\t\t\t\tsum: 0,\n\t\t\t\t\t\tavg: 0,\n\t\t\t\t\t\tmin: Infinity,\n\t\t\t\t\t\tmax: -Infinity,\n\t\t\t\t\t\tp50: 0,\n\t\t\t\t\t\tp95: 0,\n\t\t\t\t\t\tp99: 0,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tresults.set(groupKey, result);\n\t\t\t}\n\n\t\t\t// Aggregate into time series\n\t\t\tconst tsIndex = Math.floor((bucketTime - startTime) / intervalMs);\n\t\t\twhile (result.timeSeries.length <= tsIndex) {\n\t\t\t\tresult.timeSeries.push({\n\t\t\t\t\ttimestamp: new Date(\n\t\t\t\t\t\tstartTime + result.timeSeries.length * intervalMs,\n\t\t\t\t\t),\n\t\t\t\t\tcount: 0,\n\t\t\t\t\tsum: 0,\n\t\t\t\t\tavg: 0,\n\t\t\t\t\tmin: Infinity,\n\t\t\t\t\tmax: -Infinity,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst tsPoint = result.timeSeries[tsIndex];\n\t\t\tif (tsPoint) {\n\t\t\t\ttsPoint.count += bucket.count;\n\t\t\t\ttsPoint.sum += bucket.sum;\n\t\t\t\ttsPoint.min = Math.min(tsPoint.min, bucket.min);\n\t\t\t\ttsPoint.max = Math.max(tsPoint.max, bucket.max);\n\t\t\t\ttsPoint.avg = tsPoint.sum / tsPoint.count;\n\t\t\t}\n\n\t\t\t// Update overall stats\n\t\t\tresult.stats.count += bucket.count;\n\t\t\tresult.stats.sum += bucket.sum;\n\t\t\tresult.stats.min = Math.min(result.stats.min, bucket.min);\n\t\t\tresult.stats.max = Math.max(result.stats.max, bucket.max);\n\t\t}\n\n\t\t// Calculate percentiles and finalize\n\t\tfor (const result of results.values()) {\n\t\t\tif (result.stats.count > 0) {\n\t\t\t\tresult.stats.avg = result.stats.sum / result.stats.count;\n\n\t\t\t\t// Gather all samples for this result\n\t\t\t\tconst allSamples: number[] = [];\n\t\t\t\tfor (const [key, samples] of this.samples) {\n\t\t\t\t\tif (key.startsWith(`${query.projectId}:${result.name}:`)) {\n\t\t\t\t\t\tallSamples.push(...samples);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (allSamples.length > 0) {\n\t\t\t\t\tallSamples.sort((a, b) => a - b);\n\t\t\t\t\tresult.stats.p50 = this.percentile(allSamples, 50);\n\t\t\t\t\tresult.stats.p95 = this.percentile(allSamples, 95);\n\t\t\t\t\tresult.stats.p99 = this.percentile(allSamples, 99);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Fix infinity values\n\t\t\tif (result.stats.min === Infinity) result.stats.min = 0;\n\t\t\tif (result.stats.max === -Infinity) result.stats.max = 0;\n\n\t\t\tfor (const point of result.timeSeries) {\n\t\t\t\tif (point.min === Infinity) point.min = 0;\n\t\t\t\tif (point.max === -Infinity) point.max = 0;\n\t\t\t}\n\t\t}\n\n\t\tconst resultArray = Array.from(results.values());\n\n\t\tif (query.limit) {\n\t\t\treturn resultArray.slice(0, query.limit);\n\t\t}\n\n\t\treturn resultArray;\n\t}\n\n\tasync getBucket(\n\t\tprojectId: string,\n\t\tname: string,\n\t\tbucket: Date,\n\t): Promise<MetricBucket | null> {\n\t\tawait this.flush();\n\n\t\tfor (const [, b] of this.buckets) {\n\t\t\tif (\n\t\t\t\tb.projectId === projectId &&\n\t\t\t\tb.name === name &&\n\t\t\t\tb.bucket.getTime() === bucket.getTime()\n\t\t\t) {\n\t\t\t\treturn b;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tasync rollup(_options: RollupOptions): Promise<number> {\n\t\t// In-memory storage doesn't need rollup - data is already aggregated\n\t\treturn 0;\n\t}\n\n\tasync prune(): Promise<number> {\n\t\tconst now = Date.now();\n\t\tlet deleted = 0;\n\n\t\t// Use the shortest retention from tiers\n\t\tconst retentionMs = Math.min(\n\t\t\t...this.config.tiers\n\t\t\t\t.filter((t) => t.retention > 0)\n\t\t\t\t.map((t) => t.retention),\n\t\t);\n\n\t\tif (retentionMs === Infinity) return 0;\n\n\t\tconst cutoff = now - retentionMs;\n\n\t\tfor (const [key, bucket] of this.buckets) {\n\t\t\tif (bucket.bucket.getTime() < cutoff) {\n\t\t\t\tthis.buckets.delete(key);\n\t\t\t\tdeleted++;\n\t\t\t}\n\t\t}\n\n\t\t// Also prune samples\n\t\tfor (const [key] of this.samples) {\n\t\t\tconst timestamp = parseInt(key.split(':').pop() ?? '0', 10);\n\t\t\tif (timestamp < cutoff) {\n\t\t\t\tthis.samples.delete(key);\n\t\t\t}\n\t\t}\n\n\t\treturn deleted;\n\t}\n\n\tasync listPartitions(_tier?: string): Promise<PartitionInfo[]> {\n\t\t// In-memory storage doesn't use partitions\n\t\treturn [];\n\t}\n\n\tgetConfig(): MetricsStorageConfig {\n\t\treturn this.config;\n\t}\n\n\tasync close(): Promise<void> {\n\t\tif (this.flushTimer) {\n\t\t\tclearInterval(this.flushTimer);\n\t\t\tthis.flushTimer = null;\n\t\t}\n\t\tawait this.flush();\n\t\tthis.buckets.clear();\n\t\tthis.samples.clear();\n\t}\n\n\t// Helper methods\n\n\tprivate getBucketTime(timestamp: Date, interval: AggregationInterval): Date {\n\t\tconst ms = this.getIntervalMs(interval);\n\t\treturn new Date(Math.floor(timestamp.getTime() / ms) * ms);\n\t}\n\n\tprivate getBucketKey(point: MetricPoint, bucketTime: Date): string {\n\t\treturn [\n\t\t\tpoint.projectId,\n\t\t\tpoint.service,\n\t\t\tpoint.environment,\n\t\t\tpoint.name,\n\t\t\tthis.hashLabels(point.labels),\n\t\t\tbucketTime.getTime(),\n\t\t].join(':');\n\t}\n\n\tprivate hashLabels(labels: MetricLabels): string {\n\t\tconst sorted = Object.keys(labels)\n\t\t\t.sort()\n\t\t\t.map((k) => `${k}=${labels[k]}`)\n\t\t\t.join(',');\n\t\treturn sorted || '_empty_';\n\t}\n\n\tprivate getIntervalMs(interval: AggregationInterval): number {\n\t\tconst map: Record<AggregationInterval, number> = {\n\t\t\t'1m': 60_000,\n\t\t\t'5m': 300_000,\n\t\t\t'15m': 900_000,\n\t\t\t'1h': 3_600_000,\n\t\t\t'6h': 21_600_000,\n\t\t\t'1d': 86_400_000,\n\t\t};\n\t\treturn map[interval];\n\t}\n\n\tprivate matchesPattern(name: string, pattern: string): boolean {\n\t\tif (!pattern.includes('*')) return name === pattern;\n\t\tconst regex = new RegExp(\n\t\t\t`^${pattern.replace(/\\./g, '\\\\.').replace(/\\*/g, '.*')}$`,\n\t\t);\n\t\treturn regex.test(name);\n\t}\n\n\tprivate matchesLabels(labels: MetricLabels, filter: MetricLabels): boolean {\n\t\tfor (const [key, value] of Object.entries(filter)) {\n\t\t\tif (labels[key] !== value) return false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate getGroupKey(bucket: MetricBucket, groupBy: string[]): string {\n\t\tconst parts = [bucket.name];\n\t\tfor (const key of groupBy) {\n\t\t\tparts.push(`${key}=${bucket.labels[key] ?? ''}`);\n\t\t}\n\t\treturn parts.join(':');\n\t}\n\n\tprivate filterLabels(labels: MetricLabels, keys: string[]): MetricLabels {\n\t\tconst result: MetricLabels = {};\n\t\tfor (const key of keys) {\n\t\t\tif (labels[key] !== undefined) {\n\t\t\t\tresult[key] = labels[key];\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate percentile(sorted: number[], p: number): number {\n\t\tif (sorted.length === 0) return 0;\n\t\tconst index = Math.ceil((p / 100) * sorted.length) - 1;\n\t\treturn sorted[Math.max(0, index)] ?? 0;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"InMemoryMetricsStorage.d.cts","names":[],"sources":["../../../src/metrics/storage/InMemoryMetricsStorage.ts"],"mappings":";;;;;;;;;;;;;;qBAyBa,kCAAkC;UACtC;UACA;UACA;UACA;UACA;EAER,YAAY,SAAQ,QAAQ;EAUtB,MAAM,QAAQ,gBAAgB;EAQ9B,SAAS;UAeP;EA0CF,MAAM,OAAO,cAAc,QAAQ;EAuHnC,UACL,mBACA,cACA,QAAQ,OACN,QAAQ;EAgBL,OAAO,UAAU,gBAAgB;EAKjC,SAAS;EAiCT,eAAe,iBAAiB,QAAQ;EAK9C,aAAa;EAIP,SAAS;UAYP;UAKA;UAWA;UAQA;UAYA;UAQA;UAOA;UAQA;UAUA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"InMemoryMetricsStorage.d.mts","names":[],"sources":["../../../src/metrics/storage/InMemoryMetricsStorage.ts"],"mappings":";;;;;;;;;;;;;;qBAyBa,kCAAkC;UACtC;UACA;UACA;UACA;UACA;EAER,YAAY,SAAQ,QAAQ;EAUtB,MAAM,QAAQ,gBAAgB;EAQ9B,SAAS;UAeP;EA0CF,MAAM,OAAO,cAAc,QAAQ;EAuHnC,UACL,mBACA,cACA,QAAQ,OACN,QAAQ;EAgBL,OAAO,UAAU,gBAAgB;EAKjC,SAAS;EAiCT,eAAe,iBAAiB,QAAQ;EAK9C,aAAa;EAIP,SAAS;UAYP;UAKA;UAWA;UAQA;UAYA;UAQA;UAOA;UAQA;UAUA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"InMemoryMetricsStorage.mjs","names":[],"sources":["../../../src/metrics/storage/InMemoryMetricsStorage.ts"],"sourcesContent":["import type { MetricsStorage } from './MetricsStorage';\nimport {\n\ttype AggregationInterval,\n\tDEFAULT_METRICS_CONFIG,\n\ttype MetricBucket,\n\ttype MetricLabels,\n\ttype MetricPoint,\n\ttype MetricQuery,\n\ttype MetricResult,\n\ttype MetricsStorageConfig,\n\ttype PartitionInfo,\n\ttype RollupOptions,\n} from './types';\n\n/**\n * In-memory metrics storage for development and testing.\n *\n * Features:\n * - Buffered writes with configurable flush interval\n * - Time-bucketed aggregation\n * - Basic percentile calculation (reservoir sampling)\n * - Automatic pruning based on retention\n *\n * Not suitable for production - use a proper time-series database.\n */\nexport class InMemoryMetricsStorage implements MetricsStorage {\n\tprivate config: MetricsStorageConfig;\n\tprivate buffer: MetricPoint[] = [];\n\tprivate buckets: Map<string, MetricBucket> = new Map();\n\tprivate samples: Map<string, number[]> = new Map(); // For percentile calculations\n\tprivate flushTimer: ReturnType<typeof setInterval> | null = null;\n\n\tconstructor(config: Partial<MetricsStorageConfig> = {}) {\n\t\tthis.config = { ...DEFAULT_METRICS_CONFIG, ...config };\n\n\t\tif (this.config.flushInterval > 0) {\n\t\t\tthis.flushTimer = setInterval(() => {\n\t\t\t\tthis.flush().catch(console.error);\n\t\t\t}, this.config.flushInterval);\n\t\t}\n\t}\n\n\tasync write(points: MetricPoint[]): Promise<void> {\n\t\tthis.buffer.push(...points);\n\n\t\tif (this.buffer.length >= this.config.maxBatchSize) {\n\t\t\tawait this.flush();\n\t\t}\n\t}\n\n\tasync flush(): Promise<void> {\n\t\tif (this.buffer.length === 0) return;\n\n\t\tconst points = this.buffer.splice(0);\n\n\t\tfor (const point of points) {\n\t\t\tthis.aggregatePoint(point);\n\t\t}\n\n\t\t// Prune if auto-rollup is enabled\n\t\tif (this.config.autoRollup) {\n\t\t\tawait this.prune();\n\t\t}\n\t}\n\n\tprivate aggregatePoint(point: MetricPoint): void {\n\t\tconst bucketTime = this.getBucketTime(point.timestamp, '1m');\n\t\tconst key = this.getBucketKey(point, bucketTime);\n\n\t\tconst existing = this.buckets.get(key);\n\n\t\tif (existing) {\n\t\t\texisting.count += 1;\n\t\t\texisting.sum += point.value;\n\t\t\texisting.min = Math.min(existing.min, point.value);\n\t\t\texisting.max = Math.max(existing.max, point.value);\n\t\t} else {\n\t\t\tthis.buckets.set(key, {\n\t\t\t\tbucket: bucketTime,\n\t\t\t\tprojectId: point.projectId,\n\t\t\t\tservice: point.service,\n\t\t\t\tenvironment: point.environment,\n\t\t\t\tname: point.name,\n\t\t\t\tlabelsHash: this.hashLabels(point.labels),\n\t\t\t\tlabels: { ...point.labels },\n\t\t\t\tcount: 1,\n\t\t\t\tsum: point.value,\n\t\t\t\tmin: point.value,\n\t\t\t\tmax: point.value,\n\t\t\t});\n\t\t}\n\n\t\t// Store samples for percentile calculations (reservoir sampling)\n\t\tconst sampleKey = `${point.projectId}:${point.name}:${bucketTime.getTime()}`;\n\t\tconst samples = this.samples.get(sampleKey) ?? [];\n\t\tif (samples.length < 1000) {\n\t\t\tsamples.push(point.value);\n\t\t} else {\n\t\t\t// Reservoir sampling\n\t\t\tconst idx = Math.floor(Math.random() * (samples.length + 1));\n\t\t\tif (idx < samples.length) {\n\t\t\t\tsamples[idx] = point.value;\n\t\t\t}\n\t\t}\n\t\tthis.samples.set(sampleKey, samples);\n\t}\n\n\tasync query(query: MetricQuery): Promise<MetricResult[]> {\n\t\tawait this.flush();\n\n\t\tconst results = new Map<string, MetricResult>();\n\t\tconst startTime = query.range.start.getTime();\n\t\tconst endTime = query.range.end.getTime();\n\t\tconst interval = query.interval ?? '1m';\n\t\tconst intervalMs = this.getIntervalMs(interval);\n\n\t\tfor (const [, bucket] of this.buckets) {\n\t\t\tif (bucket.projectId !== query.projectId) continue;\n\t\t\tif (query.service && bucket.service !== query.service) continue;\n\t\t\tif (query.environment && bucket.environment !== query.environment)\n\t\t\t\tcontinue;\n\t\t\tif (query.name && !this.matchesPattern(bucket.name, query.name)) continue;\n\t\t\tif (query.labels && !this.matchesLabels(bucket.labels, query.labels))\n\t\t\t\tcontinue;\n\n\t\t\tconst bucketTime = bucket.bucket.getTime();\n\t\t\tif (bucketTime < startTime || bucketTime > endTime) continue;\n\n\t\t\t// Group by metric name + labels\n\t\t\tconst groupKey = query.groupBy\n\t\t\t\t? this.getGroupKey(bucket, query.groupBy)\n\t\t\t\t: bucket.name;\n\n\t\t\tlet result = results.get(groupKey);\n\t\t\tif (!result) {\n\t\t\t\tresult = {\n\t\t\t\t\tname: bucket.name,\n\t\t\t\t\tlabels: query.groupBy\n\t\t\t\t\t\t? this.filterLabels(bucket.labels, query.groupBy)\n\t\t\t\t\t\t: bucket.labels,\n\t\t\t\t\ttimeSeries: [],\n\t\t\t\t\tstats: {\n\t\t\t\t\t\tcount: 0,\n\t\t\t\t\t\tsum: 0,\n\t\t\t\t\t\tavg: 0,\n\t\t\t\t\t\tmin: Infinity,\n\t\t\t\t\t\tmax: -Infinity,\n\t\t\t\t\t\tp50: 0,\n\t\t\t\t\t\tp95: 0,\n\t\t\t\t\t\tp99: 0,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tresults.set(groupKey, result);\n\t\t\t}\n\n\t\t\t// Aggregate into time series\n\t\t\tconst tsIndex = Math.floor((bucketTime - startTime) / intervalMs);\n\t\t\twhile (result.timeSeries.length <= tsIndex) {\n\t\t\t\tresult.timeSeries.push({\n\t\t\t\t\ttimestamp: new Date(\n\t\t\t\t\t\tstartTime + result.timeSeries.length * intervalMs,\n\t\t\t\t\t),\n\t\t\t\t\tcount: 0,\n\t\t\t\t\tsum: 0,\n\t\t\t\t\tavg: 0,\n\t\t\t\t\tmin: Infinity,\n\t\t\t\t\tmax: -Infinity,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst tsPoint = result.timeSeries[tsIndex];\n\t\t\tif (tsPoint) {\n\t\t\t\ttsPoint.count += bucket.count;\n\t\t\t\ttsPoint.sum += bucket.sum;\n\t\t\t\ttsPoint.min = Math.min(tsPoint.min, bucket.min);\n\t\t\t\ttsPoint.max = Math.max(tsPoint.max, bucket.max);\n\t\t\t\ttsPoint.avg = tsPoint.sum / tsPoint.count;\n\t\t\t}\n\n\t\t\t// Update overall stats\n\t\t\tresult.stats.count += bucket.count;\n\t\t\tresult.stats.sum += bucket.sum;\n\t\t\tresult.stats.min = Math.min(result.stats.min, bucket.min);\n\t\t\tresult.stats.max = Math.max(result.stats.max, bucket.max);\n\t\t}\n\n\t\t// Calculate percentiles and finalize\n\t\tfor (const result of results.values()) {\n\t\t\tif (result.stats.count > 0) {\n\t\t\t\tresult.stats.avg = result.stats.sum / result.stats.count;\n\n\t\t\t\t// Gather all samples for this result\n\t\t\t\tconst allSamples: number[] = [];\n\t\t\t\tfor (const [key, samples] of this.samples) {\n\t\t\t\t\tif (key.startsWith(`${query.projectId}:${result.name}:`)) {\n\t\t\t\t\t\tallSamples.push(...samples);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (allSamples.length > 0) {\n\t\t\t\t\tallSamples.sort((a, b) => a - b);\n\t\t\t\t\tresult.stats.p50 = this.percentile(allSamples, 50);\n\t\t\t\t\tresult.stats.p95 = this.percentile(allSamples, 95);\n\t\t\t\t\tresult.stats.p99 = this.percentile(allSamples, 99);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Fix infinity values\n\t\t\tif (result.stats.min === Infinity) result.stats.min = 0;\n\t\t\tif (result.stats.max === -Infinity) result.stats.max = 0;\n\n\t\t\tfor (const point of result.timeSeries) {\n\t\t\t\tif (point.min === Infinity) point.min = 0;\n\t\t\t\tif (point.max === -Infinity) point.max = 0;\n\t\t\t}\n\t\t}\n\n\t\tconst resultArray = Array.from(results.values());\n\n\t\tif (query.limit) {\n\t\t\treturn resultArray.slice(0, query.limit);\n\t\t}\n\n\t\treturn resultArray;\n\t}\n\n\tasync getBucket(\n\t\tprojectId: string,\n\t\tname: string,\n\t\tbucket: Date,\n\t): Promise<MetricBucket | null> {\n\t\tawait this.flush();\n\n\t\tfor (const [, b] of this.buckets) {\n\t\t\tif (\n\t\t\t\tb.projectId === projectId &&\n\t\t\t\tb.name === name &&\n\t\t\t\tb.bucket.getTime() === bucket.getTime()\n\t\t\t) {\n\t\t\t\treturn b;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tasync rollup(_options: RollupOptions): Promise<number> {\n\t\t// In-memory storage doesn't need rollup - data is already aggregated\n\t\treturn 0;\n\t}\n\n\tasync prune(): Promise<number> {\n\t\tconst now = Date.now();\n\t\tlet deleted = 0;\n\n\t\t// Use the shortest retention from tiers\n\t\tconst retentionMs = Math.min(\n\t\t\t...this.config.tiers\n\t\t\t\t.filter((t) => t.retention > 0)\n\t\t\t\t.map((t) => t.retention),\n\t\t);\n\n\t\tif (retentionMs === Infinity) return 0;\n\n\t\tconst cutoff = now - retentionMs;\n\n\t\tfor (const [key, bucket] of this.buckets) {\n\t\t\tif (bucket.bucket.getTime() < cutoff) {\n\t\t\t\tthis.buckets.delete(key);\n\t\t\t\tdeleted++;\n\t\t\t}\n\t\t}\n\n\t\t// Also prune samples\n\t\tfor (const [key] of this.samples) {\n\t\t\tconst timestamp = parseInt(key.split(':').pop() ?? '0', 10);\n\t\t\tif (timestamp < cutoff) {\n\t\t\t\tthis.samples.delete(key);\n\t\t\t}\n\t\t}\n\n\t\treturn deleted;\n\t}\n\n\tasync listPartitions(_tier?: string): Promise<PartitionInfo[]> {\n\t\t// In-memory storage doesn't use partitions\n\t\treturn [];\n\t}\n\n\tgetConfig(): MetricsStorageConfig {\n\t\treturn this.config;\n\t}\n\n\tasync close(): Promise<void> {\n\t\tif (this.flushTimer) {\n\t\t\tclearInterval(this.flushTimer);\n\t\t\tthis.flushTimer = null;\n\t\t}\n\t\tawait this.flush();\n\t\tthis.buckets.clear();\n\t\tthis.samples.clear();\n\t}\n\n\t// Helper methods\n\n\tprivate getBucketTime(timestamp: Date, interval: AggregationInterval): Date {\n\t\tconst ms = this.getIntervalMs(interval);\n\t\treturn new Date(Math.floor(timestamp.getTime() / ms) * ms);\n\t}\n\n\tprivate getBucketKey(point: MetricPoint, bucketTime: Date): string {\n\t\treturn [\n\t\t\tpoint.projectId,\n\t\t\tpoint.service,\n\t\t\tpoint.environment,\n\t\t\tpoint.name,\n\t\t\tthis.hashLabels(point.labels),\n\t\t\tbucketTime.getTime(),\n\t\t].join(':');\n\t}\n\n\tprivate hashLabels(labels: MetricLabels): string {\n\t\tconst sorted = Object.keys(labels)\n\t\t\t.sort()\n\t\t\t.map((k) => `${k}=${labels[k]}`)\n\t\t\t.join(',');\n\t\treturn sorted || '_empty_';\n\t}\n\n\tprivate getIntervalMs(interval: AggregationInterval): number {\n\t\tconst map: Record<AggregationInterval, number> = {\n\t\t\t'1m': 60_000,\n\t\t\t'5m': 300_000,\n\t\t\t'15m': 900_000,\n\t\t\t'1h': 3_600_000,\n\t\t\t'6h': 21_600_000,\n\t\t\t'1d': 86_400_000,\n\t\t};\n\t\treturn map[interval];\n\t}\n\n\tprivate matchesPattern(name: string, pattern: string): boolean {\n\t\tif (!pattern.includes('*')) return name === pattern;\n\t\tconst regex = new RegExp(\n\t\t\t`^${pattern.replace(/\\./g, '\\\\.').replace(/\\*/g, '.*')}$`,\n\t\t);\n\t\treturn regex.test(name);\n\t}\n\n\tprivate matchesLabels(labels: MetricLabels, filter: MetricLabels): boolean {\n\t\tfor (const [key, value] of Object.entries(filter)) {\n\t\t\tif (labels[key] !== value) return false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate getGroupKey(bucket: MetricBucket, groupBy: string[]): string {\n\t\tconst parts = [bucket.name];\n\t\tfor (const key of groupBy) {\n\t\t\tparts.push(`${key}=${bucket.labels[key] ?? ''}`);\n\t\t}\n\t\treturn parts.join(':');\n\t}\n\n\tprivate filterLabels(labels: MetricLabels, keys: string[]): MetricLabels {\n\t\tconst result: MetricLabels = {};\n\t\tfor (const key of keys) {\n\t\t\tif (labels[key] !== undefined) {\n\t\t\t\tresult[key] = labels[key];\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate percentile(sorted: number[], p: number): number {\n\t\tif (sorted.length === 0) return 0;\n\t\tconst index = Math.ceil((p / 100) * sorted.length) - 1;\n\t\treturn sorted[Math.max(0, index)] ?? 0;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MetricsStorage.d.cts","names":[],"sources":["../../../src/metrics/storage/MetricsStorage.ts"],"mappings":";;;;;;;;;;;iBAmBiB;;;;;EAKhB,MAAM,QAAQ,gBAAgB;;;;;EAM9B,MAAM,OAAO,cAAc,QAAQ;;;;;EAMnC,UACC,mBACA,cACA,QAAQ,OACN,QAAQ;;;;;EAMX,OAAO,SAAS,gBAAgB;;;;;EAMhC,SAAS;;;;EAKT,eAAe,gBAAgB,QAAQ;;;;EAKvC,aAAa;;;;EAKb,SAAS;;;;EAKT,SAAS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MetricsStorage.d.mts","names":[],"sources":["../../../src/metrics/storage/MetricsStorage.ts"],"mappings":";;;;;;;;;;;iBAmBiB;;;;;EAKhB,MAAM,QAAQ,gBAAgB;;;;;EAM9B,MAAM,OAAO,cAAc,QAAQ;;;;;EAMnC,UACC,mBACA,cACA,QAAQ,OACN,QAAQ;;;;;EAMX,OAAO,SAAS,gBAAgB;;;;;EAMhC,SAAS;;;;EAKT,eAAe,gBAAgB,QAAQ;;;;EAKvC,aAAa;;;;EAKb,SAAS;;;;EAKT,SAAS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.cjs","names":[],"sources":["../../../src/metrics/storage/types.ts"],"sourcesContent":["/**\n * Metric types supported by the storage system\n */\nexport type MetricType = 'counter' | 'gauge' | 'histogram';\n\n/**\n * Labels/dimensions for metric filtering and grouping\n */\nexport type MetricLabels = Record<string, string>;\n\n/**\n * A single metric data point\n */\nexport interface MetricPoint {\n\t/** Timestamp of the metric */\n\ttimestamp: Date;\n\t/** Project/app identifier for multi-tenant isolation */\n\tprojectId: string;\n\t/** Service name (e.g., 'api', 'worker', 'cron') */\n\tservice: string;\n\t/** Environment (e.g., 'development', 'staging', 'production') */\n\tenvironment: string;\n\t/** Metric name (e.g., 'http.request.duration', 'orders.created') */\n\tname: string;\n\t/** Metric type */\n\ttype: MetricType;\n\t/** Numeric value */\n\tvalue: number;\n\t/** Dimensions for filtering/grouping */\n\tlabels: MetricLabels;\n}\n\n/**\n * Aggregated metric bucket (pre-computed for efficient queries)\n */\nexport interface MetricBucket {\n\t/** Bucket start timestamp */\n\tbucket: Date;\n\t/** Project identifier */\n\tprojectId: string;\n\t/** Service name */\n\tservice: string;\n\t/** Environment */\n\tenvironment: string;\n\t/** Metric name */\n\tname: string;\n\t/** Hash of labels for grouping */\n\tlabelsHash: string;\n\t/** Original labels */\n\tlabels: MetricLabels;\n\t/** Number of data points in bucket */\n\tcount: number;\n\t/** Sum of values */\n\tsum: number;\n\t/** Minimum value */\n\tmin: number;\n\t/** Maximum value */\n\tmax: number;\n\t/** T-Digest sketch for percentile calculations (serialized) */\n\tsketch?: TDigestData;\n}\n\n/**\n * Serialized T-Digest data structure for percentile calculations\n * Stores centroids (mean, weight) that can be merged across buckets\n */\nexport interface TDigestData {\n\t/** Centroids: [mean, weight][] */\n\tcentroids: [number, number][];\n\t/** Compression factor (higher = more accuracy, more memory) */\n\tcompression: number;\n\t/** Total count of values */\n\tcount: number;\n\t/** Minimum value seen */\n\tmin: number;\n\t/** Maximum value seen */\n\tmax: number;\n}\n\n/**\n * Time range for queries\n */\nexport interface TimeRange {\n\tstart: Date;\n\tend: Date;\n}\n\n/**\n * Aggregation granularity\n */\nexport type AggregationInterval = '1m' | '5m' | '15m' | '1h' | '6h' | '1d';\n\n/**\n * Query parameters for retrieving metrics\n */\nexport interface MetricQuery {\n\t/** Project filter (required for multi-tenant) */\n\tprojectId: string;\n\t/** Optional service filter */\n\tservice?: string;\n\t/** Optional environment filter */\n\tenvironment?: string;\n\t/** Metric name pattern (supports wildcards like 'http.*') */\n\tname?: string;\n\t/** Label filters */\n\tlabels?: MetricLabels;\n\t/** Time range */\n\trange: TimeRange;\n\t/** Aggregation interval */\n\tinterval?: AggregationInterval;\n\t/** Group by these label keys */\n\tgroupBy?: string[];\n\t/** Maximum number of results */\n\tlimit?: number;\n}\n\n/**\n * Query result with aggregated values\n */\nexport interface MetricResult {\n\t/** Metric name */\n\tname: string;\n\t/** Labels (grouped by keys if specified) */\n\tlabels: MetricLabels;\n\t/** Time series data points */\n\ttimeSeries: MetricTimeSeriesPoint[];\n\t/** Overall statistics for the query range */\n\tstats: {\n\t\tcount: number;\n\t\tsum: number;\n\t\tavg: number;\n\t\tmin: number;\n\t\tmax: number;\n\t\tp50: number;\n\t\tp95: number;\n\t\tp99: number;\n\t};\n}\n\n/**\n * Single point in a time series result\n */\nexport interface MetricTimeSeriesPoint {\n\ttimestamp: Date;\n\tcount: number;\n\tsum: number;\n\tavg: number;\n\tmin: number;\n\tmax: number;\n\tp50?: number;\n\tp95?: number;\n\tp99?: number;\n}\n\n/**\n * Storage tier configuration\n */\nexport interface StorageTier {\n\t/** Table/collection name for this tier */\n\tname: string;\n\t/** Bucket interval for aggregation */\n\tinterval: AggregationInterval;\n\t/** Retention duration in milliseconds (0 = forever) */\n\tretention: number;\n\t/** Partition interval for efficient pruning */\n\tpartitionInterval: 'hourly' | 'daily' | 'weekly' | 'monthly';\n}\n\n/**\n * Metrics storage configuration\n */\nexport interface MetricsStorageConfig {\n\t/** Storage tiers (raw, minute, hourly, etc.) */\n\ttiers: StorageTier[];\n\t/** Flush interval in milliseconds */\n\tflushInterval: number;\n\t/** Maximum batch size for writes */\n\tmaxBatchSize: number;\n\t/** Enable automatic rollup between tiers */\n\tautoRollup: boolean;\n\t/** T-Digest compression factor (default: 100) */\n\ttdigestCompression: number;\n}\n\n/**\n * Default configuration with hybrid storage strategy\n */\nexport const DEFAULT_METRICS_CONFIG: MetricsStorageConfig = {\n\ttiers: [\n\t\t{\n\t\t\tname: 'raw',\n\t\t\tinterval: '1m',\n\t\t\tretention: 60 * 60 * 1000, // 1 hour\n\t\t\tpartitionInterval: 'hourly',\n\t\t},\n\t\t{\n\t\t\tname: '1m',\n\t\t\tinterval: '1m',\n\t\t\tretention: 7 * 24 * 60 * 60 * 1000, // 7 days\n\t\t\tpartitionInterval: 'daily',\n\t\t},\n\t\t{\n\t\t\tname: '1h',\n\t\t\tinterval: '1h',\n\t\t\tretention: 0, // Forever\n\t\t\tpartitionInterval: 'monthly',\n\t\t},\n\t],\n\tflushInterval: 10_000, // 10 seconds\n\tmaxBatchSize: 1000,\n\tautoRollup: true,\n\ttdigestCompression: 100,\n};\n\n/**\n * Rollup options for aggregating data between tiers\n */\nexport interface RollupOptions {\n\t/** Source tier */\n\tfrom: string;\n\t/** Target tier */\n\tto: string;\n\t/** Only rollup data older than this */\n\tolderThan: Date;\n}\n\n/**\n * Partition info for management\n */\nexport interface PartitionInfo {\n\t/** Partition name */\n\tname: string;\n\t/** Tier this partition belongs to */\n\ttier: string;\n\t/** Partition start time */\n\tstart: Date;\n\t/** Partition end time */\n\tend: Date;\n\t/** Approximate row count */\n\trowCount?: number;\n\t/** Size in bytes */\n\tsizeBytes?: number;\n}\n"],"mappings":";;;;;AA2LA,MAAa,yBAA+C;CAC3D,OAAO;EACN;GACC,MAAM;GACN,UAAU;GACV,WAAW;GACX,mBAAmB;EACpB;EACA;GACC,MAAM;GACN,UAAU;GACV,WAAW;GACX,mBAAmB;EACpB;EACA;GACC,MAAM;GACN,UAAU;GACV,WAAW;GACX,mBAAmB;EACpB;CACD;CACA,eAAe;CACf,cAAc;CACd,YAAY;CACZ,oBAAoB;AACrB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.cts","names":[],"sources":["../../../src/metrics/storage/types.ts"],"mappings":";;;;YAGY;;;;YAKA,eAAe;;;;iBAKV;;EAEhB,WAAW;;EAEX;;EAEA;;EAEA;;EAEA;;EAEA,MAAM;;EAEN;;EAEA,QAAQ;;;;;iBAMQ;;EAEhB,QAAQ;;EAER;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA,QAAQ;;EAER;;EAEA;;EAEA;;EAEA;;EAEA,SAAS;;;;;;iBAOO;;EAEhB;;EAEA;;EAEA;;EAEA;;EAEA;;;;;iBAMgB;EAChB,OAAO;EACP,KAAK;;;;;YAMM;;;;iBAKK;;EAEhB;;EAEA;;EAEA;;EAEA;;EAEA,SAAS;;EAET,OAAO;;EAEP,WAAW;;EAEX;;EAEA;;;;;iBAMgB;;EAEhB;;EAEA,QAAQ;;EAER,YAAY;;EAEZ;IACC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;;;;iBAOe;EAChB,WAAW;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;iBAMgB;;EAEhB;;EAEA,UAAU;;EAEV;;EAEA;;;;;iBAMgB;;EAEhB,OAAO;;EAEP;;EAEA;;EAEA;;EAEA;;;;;qBAMY,wBAAwB;;;;iBA8BpB;;EAEhB;;EAEA;;EAEA,WAAW;;;;;iBAMK;;EAEhB;;EAEA;;EAEA,OAAO;;EAEP,KAAK;;EAEL;;EAEA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/metrics/storage/types.ts"],"mappings":";;;;YAGY;;;;YAKA,eAAe;;;;iBAKV;;EAEhB,WAAW;;EAEX;;EAEA;;EAEA;;EAEA;;EAEA,MAAM;;EAEN;;EAEA,QAAQ;;;;;iBAMQ;;EAEhB,QAAQ;;EAER;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA,QAAQ;;EAER;;EAEA;;EAEA;;EAEA;;EAEA,SAAS;;;;;;iBAOO;;EAEhB;;EAEA;;EAEA;;EAEA;;EAEA;;;;;iBAMgB;EAChB,OAAO;EACP,KAAK;;;;;YAMM;;;;iBAKK;;EAEhB;;EAEA;;EAEA;;EAEA;;EAEA,SAAS;;EAET,OAAO;;EAEP,WAAW;;EAEX;;EAEA;;;;;iBAMgB;;EAEhB;;EAEA,QAAQ;;EAER,YAAY;;EAEZ;IACC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;;;;iBAOe;EAChB,WAAW;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;iBAMgB;;EAEhB;;EAEA,UAAU;;EAEV;;EAEA;;;;;iBAMgB;;EAEhB,OAAO;;EAEP;;EAEA;;EAEA;;EAEA;;;;;qBAMY,wBAAwB;;;;iBA8BpB;;EAEhB;;EAEA;;EAEA,WAAW;;;;;iBAMK;;EAEhB;;EAEA;;EAEA,OAAO;;EAEP,KAAK;;EAEL;;EAEA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.mjs","names":[],"sources":["../../../src/metrics/storage/types.ts"],"sourcesContent":["/**\n * Metric types supported by the storage system\n */\nexport type MetricType = 'counter' | 'gauge' | 'histogram';\n\n/**\n * Labels/dimensions for metric filtering and grouping\n */\nexport type MetricLabels = Record<string, string>;\n\n/**\n * A single metric data point\n */\nexport interface MetricPoint {\n\t/** Timestamp of the metric */\n\ttimestamp: Date;\n\t/** Project/app identifier for multi-tenant isolation */\n\tprojectId: string;\n\t/** Service name (e.g., 'api', 'worker', 'cron') */\n\tservice: string;\n\t/** Environment (e.g., 'development', 'staging', 'production') */\n\tenvironment: string;\n\t/** Metric name (e.g., 'http.request.duration', 'orders.created') */\n\tname: string;\n\t/** Metric type */\n\ttype: MetricType;\n\t/** Numeric value */\n\tvalue: number;\n\t/** Dimensions for filtering/grouping */\n\tlabels: MetricLabels;\n}\n\n/**\n * Aggregated metric bucket (pre-computed for efficient queries)\n */\nexport interface MetricBucket {\n\t/** Bucket start timestamp */\n\tbucket: Date;\n\t/** Project identifier */\n\tprojectId: string;\n\t/** Service name */\n\tservice: string;\n\t/** Environment */\n\tenvironment: string;\n\t/** Metric name */\n\tname: string;\n\t/** Hash of labels for grouping */\n\tlabelsHash: string;\n\t/** Original labels */\n\tlabels: MetricLabels;\n\t/** Number of data points in bucket */\n\tcount: number;\n\t/** Sum of values */\n\tsum: number;\n\t/** Minimum value */\n\tmin: number;\n\t/** Maximum value */\n\tmax: number;\n\t/** T-Digest sketch for percentile calculations (serialized) */\n\tsketch?: TDigestData;\n}\n\n/**\n * Serialized T-Digest data structure for percentile calculations\n * Stores centroids (mean, weight) that can be merged across buckets\n */\nexport interface TDigestData {\n\t/** Centroids: [mean, weight][] */\n\tcentroids: [number, number][];\n\t/** Compression factor (higher = more accuracy, more memory) */\n\tcompression: number;\n\t/** Total count of values */\n\tcount: number;\n\t/** Minimum value seen */\n\tmin: number;\n\t/** Maximum value seen */\n\tmax: number;\n}\n\n/**\n * Time range for queries\n */\nexport interface TimeRange {\n\tstart: Date;\n\tend: Date;\n}\n\n/**\n * Aggregation granularity\n */\nexport type AggregationInterval = '1m' | '5m' | '15m' | '1h' | '6h' | '1d';\n\n/**\n * Query parameters for retrieving metrics\n */\nexport interface MetricQuery {\n\t/** Project filter (required for multi-tenant) */\n\tprojectId: string;\n\t/** Optional service filter */\n\tservice?: string;\n\t/** Optional environment filter */\n\tenvironment?: string;\n\t/** Metric name pattern (supports wildcards like 'http.*') */\n\tname?: string;\n\t/** Label filters */\n\tlabels?: MetricLabels;\n\t/** Time range */\n\trange: TimeRange;\n\t/** Aggregation interval */\n\tinterval?: AggregationInterval;\n\t/** Group by these label keys */\n\tgroupBy?: string[];\n\t/** Maximum number of results */\n\tlimit?: number;\n}\n\n/**\n * Query result with aggregated values\n */\nexport interface MetricResult {\n\t/** Metric name */\n\tname: string;\n\t/** Labels (grouped by keys if specified) */\n\tlabels: MetricLabels;\n\t/** Time series data points */\n\ttimeSeries: MetricTimeSeriesPoint[];\n\t/** Overall statistics for the query range */\n\tstats: {\n\t\tcount: number;\n\t\tsum: number;\n\t\tavg: number;\n\t\tmin: number;\n\t\tmax: number;\n\t\tp50: number;\n\t\tp95: number;\n\t\tp99: number;\n\t};\n}\n\n/**\n * Single point in a time series result\n */\nexport interface MetricTimeSeriesPoint {\n\ttimestamp: Date;\n\tcount: number;\n\tsum: number;\n\tavg: number;\n\tmin: number;\n\tmax: number;\n\tp50?: number;\n\tp95?: number;\n\tp99?: number;\n}\n\n/**\n * Storage tier configuration\n */\nexport interface StorageTier {\n\t/** Table/collection name for this tier */\n\tname: string;\n\t/** Bucket interval for aggregation */\n\tinterval: AggregationInterval;\n\t/** Retention duration in milliseconds (0 = forever) */\n\tretention: number;\n\t/** Partition interval for efficient pruning */\n\tpartitionInterval: 'hourly' | 'daily' | 'weekly' | 'monthly';\n}\n\n/**\n * Metrics storage configuration\n */\nexport interface MetricsStorageConfig {\n\t/** Storage tiers (raw, minute, hourly, etc.) */\n\ttiers: StorageTier[];\n\t/** Flush interval in milliseconds */\n\tflushInterval: number;\n\t/** Maximum batch size for writes */\n\tmaxBatchSize: number;\n\t/** Enable automatic rollup between tiers */\n\tautoRollup: boolean;\n\t/** T-Digest compression factor (default: 100) */\n\ttdigestCompression: number;\n}\n\n/**\n * Default configuration with hybrid storage strategy\n */\nexport const DEFAULT_METRICS_CONFIG: MetricsStorageConfig = {\n\ttiers: [\n\t\t{\n\t\t\tname: 'raw',\n\t\t\tinterval: '1m',\n\t\t\tretention: 60 * 60 * 1000, // 1 hour\n\t\t\tpartitionInterval: 'hourly',\n\t\t},\n\t\t{\n\t\t\tname: '1m',\n\t\t\tinterval: '1m',\n\t\t\tretention: 7 * 24 * 60 * 60 * 1000, // 7 days\n\t\t\tpartitionInterval: 'daily',\n\t\t},\n\t\t{\n\t\t\tname: '1h',\n\t\t\tinterval: '1h',\n\t\t\tretention: 0, // Forever\n\t\t\tpartitionInterval: 'monthly',\n\t\t},\n\t],\n\tflushInterval: 10_000, // 10 seconds\n\tmaxBatchSize: 1000,\n\tautoRollup: true,\n\ttdigestCompression: 100,\n};\n\n/**\n * Rollup options for aggregating data between tiers\n */\nexport interface RollupOptions {\n\t/** Source tier */\n\tfrom: string;\n\t/** Target tier */\n\tto: string;\n\t/** Only rollup data older than this */\n\tolderThan: Date;\n}\n\n/**\n * Partition info for management\n */\nexport interface PartitionInfo {\n\t/** Partition name */\n\tname: string;\n\t/** Tier this partition belongs to */\n\ttier: string;\n\t/** Partition start time */\n\tstart: Date;\n\t/** Partition end time */\n\tend: Date;\n\t/** Approximate row count */\n\trowCount?: number;\n\t/** Size in bytes */\n\tsizeBytes?: number;\n}\n"],"mappings":";;;;AA2LA,MAAa,yBAA+C;CAC3D,OAAO;EACN;GACC,MAAM;GACN,UAAU;GACV,WAAW;GACX,mBAAmB;EACpB;EACA;GACC,MAAM;GACN,UAAU;GACV,WAAW;GACX,mBAAmB;EACpB;EACA;GACC,MAAM;GACN,UAAU;GACV,WAAW;GACX,mBAAmB;EACpB;CACD;CACA,eAAe;CACf,cAAc;CACd,YAAY;CACZ,oBAAoB;AACrB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"receiver.cjs","names":["transformTraces","transformLogs","transformMetrics"],"sources":["../../src/otlp/receiver.ts"],"sourcesContent":["import type { Telescope } from '../Telescope';\nimport {\n\ttype MetricDataPoint,\n\ttransformLogs,\n\ttransformMetrics,\n\ttransformTraces,\n} from './transformer';\nimport type {\n\tExportLogsServiceRequest,\n\tExportLogsServiceResponse,\n\tExportMetricsServiceRequest,\n\tExportMetricsServiceResponse,\n\tExportTraceServiceRequest,\n\tExportTraceServiceResponse,\n} from './types';\n\n/**\n * Callback for handling OTLP metrics\n */\nexport type MetricsHandler = (\n\tpoints: MetricDataPoint[],\n) => void | Promise<void>;\n\n/**\n * Options for OTLPReceiver\n */\nexport interface OTLPReceiverOptions {\n\t/**\n\t * The Telescope instance to record data to\n\t */\n\ttelescope: Telescope;\n\n\t/**\n\t * Optional callback for handling OTLP metrics.\n\t * OTLP metrics are more granular than Telescope's request metrics,\n\t * so a custom handler allows integration with metrics systems like Prometheus.\n\t */\n\tonMetrics?: MetricsHandler;\n\n\t/**\n\t * Whether to also log OTLP metrics to Telescope as log entries.\n\t * Useful for debugging OTLP integration. Default: false\n\t */\n\tlogMetrics?: boolean;\n}\n\n/**\n * OTLP Receiver for ingesting OpenTelemetry data into Telescope.\n *\n * Supports the OTLP/JSON protocol for:\n * - Traces (POST /v1/traces) - HTTP server spans become RequestEntries\n * - Logs (POST /v1/logs) - Log records become LogEntries\n * - Metrics (POST /v1/metrics) - Metrics can be forwarded to custom handlers\n */\nexport class OTLPReceiver {\n\tprivate telescope: Telescope;\n\tprivate onMetrics?: MetricsHandler;\n\tprivate logMetrics: boolean;\n\n\tconstructor(options: OTLPReceiverOptions) {\n\t\tthis.telescope = options.telescope;\n\t\tthis.onMetrics = options.onMetrics;\n\t\tthis.logMetrics = options.logMetrics ?? false;\n\t}\n\n\t/**\n\t * Handle incoming trace data\n\t * Transforms HTTP server spans to Telescope request entries\n\t */\n\tasync receiveTraces(\n\t\trequest: ExportTraceServiceRequest,\n\t): Promise<ExportTraceServiceResponse> {\n\t\tconst entries = transformTraces(request);\n\t\tlet rejected = 0;\n\n\t\tfor (const entry of entries) {\n\t\t\ttry {\n\t\t\t\tawait this.telescope.recordRequest(entry);\n\t\t\t} catch {\n\t\t\t\trejected++;\n\t\t\t}\n\t\t}\n\n\t\treturn rejected > 0\n\t\t\t? { partialSuccess: { rejectedSpans: String(rejected) } }\n\t\t\t: {};\n\t}\n\n\t/**\n\t * Handle incoming log data\n\t * Transforms OTLP log records to Telescope log entries\n\t */\n\tasync receiveLogs(\n\t\trequest: ExportLogsServiceRequest,\n\t): Promise<ExportLogsServiceResponse> {\n\t\tconst entries = transformLogs(request);\n\t\tlet rejected = 0;\n\n\t\t// Batch log entries for efficiency\n\t\tconst batchEntries = entries.map((entry) => ({\n\t\t\tlevel: entry.level,\n\t\t\tmessage: entry.message,\n\t\t\tcontext: entry.context,\n\t\t\trequestId: entry.requestId,\n\t\t}));\n\n\t\ttry {\n\t\t\tawait this.telescope.log(batchEntries);\n\t\t} catch {\n\t\t\trejected = entries.length;\n\t\t}\n\n\t\treturn rejected > 0\n\t\t\t? { partialSuccess: { rejectedLogRecords: String(rejected) } }\n\t\t\t: {};\n\t}\n\n\t/**\n\t * Handle incoming metrics data\n\t * Forwards to custom handler and optionally logs to Telescope\n\t */\n\tasync receiveMetrics(\n\t\trequest: ExportMetricsServiceRequest,\n\t): Promise<ExportMetricsServiceResponse> {\n\t\tconst points = transformMetrics(request);\n\t\tlet rejected = 0;\n\n\t\t// Forward to custom metrics handler\n\t\tif (this.onMetrics) {\n\t\t\ttry {\n\t\t\t\tawait this.onMetrics(points);\n\t\t\t} catch {\n\t\t\t\trejected = points.length;\n\t\t\t}\n\t\t}\n\n\t\t// Optionally log metrics to Telescope for debugging\n\t\tif (this.logMetrics && points.length > 0) {\n\t\t\tconst logEntries = points.map((point) => ({\n\t\t\t\tlevel: 'debug' as const,\n\t\t\t\tmessage: `OTLP Metric: ${point.name}`,\n\t\t\t\tcontext: {\n\t\t\t\t\tname: point.name,\n\t\t\t\t\tvalue: point.value,\n\t\t\t\t\ttype: point.type,\n\t\t\t\t\tunit: point.unit,\n\t\t\t\t\tattributes: point.attributes,\n\t\t\t\t},\n\t\t\t}));\n\n\t\t\ttry {\n\t\t\t\tawait this.telescope.log(logEntries);\n\t\t\t} catch {\n\t\t\t\t// Ignore logging errors\n\t\t\t}\n\t\t}\n\n\t\treturn rejected > 0\n\t\t\t? { partialSuccess: { rejectedDataPoints: String(rejected) } }\n\t\t\t: {};\n\t}\n}\n"],"mappings":";;;;;;;;;;;AAsDA,IAAa,eAAb,MAA0B;CACzB;CACA;CACA;CAEA,YAAY,SAA8B;EACzC,KAAK,YAAY,QAAQ;EACzB,KAAK,YAAY,QAAQ;EACzB,KAAK,aAAa,QAAQ,cAAc;CACzC;;;;;CAMA,MAAM,cACL,SACsC;EACtC,MAAM,UAAUA,yBAAAA,gBAAgB,OAAO;EACvC,IAAI,WAAW;EAEf,KAAK,MAAM,SAAS,SACnB,IAAI;GACH,MAAM,KAAK,UAAU,cAAc,KAAK;EACzC,QAAQ;GACP;EACD;EAGD,OAAO,WAAW,IACf,EAAE,gBAAgB,EAAE,eAAe,OAAO,QAAQ,EAAE,EAAE,IACtD,CAAC;CACL;;;;;CAMA,MAAM,YACL,SACqC;EACrC,MAAM,UAAUC,yBAAAA,cAAc,OAAO;EACrC,IAAI,WAAW;EAGf,MAAM,eAAe,QAAQ,KAAK,WAAW;GAC5C,OAAO,MAAM;GACb,SAAS,MAAM;GACf,SAAS,MAAM;GACf,WAAW,MAAM;EAClB,EAAE;EAEF,IAAI;GACH,MAAM,KAAK,UAAU,IAAI,YAAY;EACtC,QAAQ;GACP,WAAW,QAAQ;EACpB;EAEA,OAAO,WAAW,IACf,EAAE,gBAAgB,EAAE,oBAAoB,OAAO,QAAQ,EAAE,EAAE,IAC3D,CAAC;CACL;;;;;CAMA,MAAM,eACL,SACwC;EACxC,MAAM,SAASC,yBAAAA,iBAAiB,OAAO;EACvC,IAAI,WAAW;EAGf,IAAI,KAAK,WACR,IAAI;GACH,MAAM,KAAK,UAAU,MAAM;EAC5B,QAAQ;GACP,WAAW,OAAO;EACnB;EAID,IAAI,KAAK,cAAc,OAAO,SAAS,GAAG;GACzC,MAAM,aAAa,OAAO,KAAK,WAAW;IACzC,OAAO;IACP,SAAS,gBAAgB,MAAM;IAC/B,SAAS;KACR,MAAM,MAAM;KACZ,OAAO,MAAM;KACb,MAAM,MAAM;KACZ,MAAM,MAAM;KACZ,YAAY,MAAM;IACnB;GACD,EAAE;GAEF,IAAI;IACH,MAAM,KAAK,UAAU,IAAI,UAAU;GACpC,QAAQ,CAER;EACD;EAEA,OAAO,WAAW,IACf,EAAE,gBAAgB,EAAE,oBAAoB,OAAO,QAAQ,EAAE,EAAE,IAC3D,CAAC;CACL;AACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"receiver.d.cts","names":[],"sources":["../../src/otlp/receiver.ts"],"mappings":";;;;;;;YAmBY,kBACX,QAAQ,6BACG;;;;iBAKK;;;;EAIhB,WAAW;;;;;;EAOX,YAAY;;;;;EAMZ;;;;;;;;;;qBAWY;UACJ;UACA;UACA;EAER,YAAY,SAAS;;;;;EAUf,cACL,SAAS,4BACP,QAAQ;;;;;EAqBL,YACL,SAAS,2BACP,QAAQ;;;;;EA2BL,eACL,SAAS,8BACP,QAAQ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"receiver.d.mts","names":[],"sources":["../../src/otlp/receiver.ts"],"mappings":";;;;;;;YAmBY,kBACX,QAAQ,6BACG;;;;iBAKK;;;;EAIhB,WAAW;;;;;;EAOX,YAAY;;;;;EAMZ;;;;;;;;;;qBAWY;UACJ;UACA;UACA;EAER,YAAY,SAAS;;;;;EAUf,cACL,SAAS,4BACP,QAAQ;;;;;EAqBL,YACL,SAAS,2BACP,QAAQ;;;;;EA2BL,eACL,SAAS,8BACP,QAAQ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"receiver.mjs","names":[],"sources":["../../src/otlp/receiver.ts"],"sourcesContent":["import type { Telescope } from '../Telescope';\nimport {\n\ttype MetricDataPoint,\n\ttransformLogs,\n\ttransformMetrics,\n\ttransformTraces,\n} from './transformer';\nimport type {\n\tExportLogsServiceRequest,\n\tExportLogsServiceResponse,\n\tExportMetricsServiceRequest,\n\tExportMetricsServiceResponse,\n\tExportTraceServiceRequest,\n\tExportTraceServiceResponse,\n} from './types';\n\n/**\n * Callback for handling OTLP metrics\n */\nexport type MetricsHandler = (\n\tpoints: MetricDataPoint[],\n) => void | Promise<void>;\n\n/**\n * Options for OTLPReceiver\n */\nexport interface OTLPReceiverOptions {\n\t/**\n\t * The Telescope instance to record data to\n\t */\n\ttelescope: Telescope;\n\n\t/**\n\t * Optional callback for handling OTLP metrics.\n\t * OTLP metrics are more granular than Telescope's request metrics,\n\t * so a custom handler allows integration with metrics systems like Prometheus.\n\t */\n\tonMetrics?: MetricsHandler;\n\n\t/**\n\t * Whether to also log OTLP metrics to Telescope as log entries.\n\t * Useful for debugging OTLP integration. Default: false\n\t */\n\tlogMetrics?: boolean;\n}\n\n/**\n * OTLP Receiver for ingesting OpenTelemetry data into Telescope.\n *\n * Supports the OTLP/JSON protocol for:\n * - Traces (POST /v1/traces) - HTTP server spans become RequestEntries\n * - Logs (POST /v1/logs) - Log records become LogEntries\n * - Metrics (POST /v1/metrics) - Metrics can be forwarded to custom handlers\n */\nexport class OTLPReceiver {\n\tprivate telescope: Telescope;\n\tprivate onMetrics?: MetricsHandler;\n\tprivate logMetrics: boolean;\n\n\tconstructor(options: OTLPReceiverOptions) {\n\t\tthis.telescope = options.telescope;\n\t\tthis.onMetrics = options.onMetrics;\n\t\tthis.logMetrics = options.logMetrics ?? false;\n\t}\n\n\t/**\n\t * Handle incoming trace data\n\t * Transforms HTTP server spans to Telescope request entries\n\t */\n\tasync receiveTraces(\n\t\trequest: ExportTraceServiceRequest,\n\t): Promise<ExportTraceServiceResponse> {\n\t\tconst entries = transformTraces(request);\n\t\tlet rejected = 0;\n\n\t\tfor (const entry of entries) {\n\t\t\ttry {\n\t\t\t\tawait this.telescope.recordRequest(entry);\n\t\t\t} catch {\n\t\t\t\trejected++;\n\t\t\t}\n\t\t}\n\n\t\treturn rejected > 0\n\t\t\t? { partialSuccess: { rejectedSpans: String(rejected) } }\n\t\t\t: {};\n\t}\n\n\t/**\n\t * Handle incoming log data\n\t * Transforms OTLP log records to Telescope log entries\n\t */\n\tasync receiveLogs(\n\t\trequest: ExportLogsServiceRequest,\n\t): Promise<ExportLogsServiceResponse> {\n\t\tconst entries = transformLogs(request);\n\t\tlet rejected = 0;\n\n\t\t// Batch log entries for efficiency\n\t\tconst batchEntries = entries.map((entry) => ({\n\t\t\tlevel: entry.level,\n\t\t\tmessage: entry.message,\n\t\t\tcontext: entry.context,\n\t\t\trequestId: entry.requestId,\n\t\t}));\n\n\t\ttry {\n\t\t\tawait this.telescope.log(batchEntries);\n\t\t} catch {\n\t\t\trejected = entries.length;\n\t\t}\n\n\t\treturn rejected > 0\n\t\t\t? { partialSuccess: { rejectedLogRecords: String(rejected) } }\n\t\t\t: {};\n\t}\n\n\t/**\n\t * Handle incoming metrics data\n\t * Forwards to custom handler and optionally logs to Telescope\n\t */\n\tasync receiveMetrics(\n\t\trequest: ExportMetricsServiceRequest,\n\t): Promise<ExportMetricsServiceResponse> {\n\t\tconst points = transformMetrics(request);\n\t\tlet rejected = 0;\n\n\t\t// Forward to custom metrics handler\n\t\tif (this.onMetrics) {\n\t\t\ttry {\n\t\t\t\tawait this.onMetrics(points);\n\t\t\t} catch {\n\t\t\t\trejected = points.length;\n\t\t\t}\n\t\t}\n\n\t\t// Optionally log metrics to Telescope for debugging\n\t\tif (this.logMetrics && points.length > 0) {\n\t\t\tconst logEntries = points.map((point) => ({\n\t\t\t\tlevel: 'debug' as const,\n\t\t\t\tmessage: `OTLP Metric: ${point.name}`,\n\t\t\t\tcontext: {\n\t\t\t\t\tname: point.name,\n\t\t\t\t\tvalue: point.value,\n\t\t\t\t\ttype: point.type,\n\t\t\t\t\tunit: point.unit,\n\t\t\t\t\tattributes: point.attributes,\n\t\t\t\t},\n\t\t\t}));\n\n\t\t\ttry {\n\t\t\t\tawait this.telescope.log(logEntries);\n\t\t\t} catch {\n\t\t\t\t// Ignore logging errors\n\t\t\t}\n\t\t}\n\n\t\treturn rejected > 0\n\t\t\t? { partialSuccess: { rejectedDataPoints: String(rejected) } }\n\t\t\t: {};\n\t}\n}\n"],"mappings":";;;;;;;;;;AAsDA,IAAa,eAAb,MAA0B;CACzB;CACA;CACA;CAEA,YAAY,SAA8B;EACzC,KAAK,YAAY,QAAQ;EACzB,KAAK,YAAY,QAAQ;EACzB,KAAK,aAAa,QAAQ,cAAc;CACzC;;;;;CAMA,MAAM,cACL,SACsC;EACtC,MAAM,UAAU,gBAAgB,OAAO;EACvC,IAAI,WAAW;EAEf,KAAK,MAAM,SAAS,SACnB,IAAI;GACH,MAAM,KAAK,UAAU,cAAc,KAAK;EACzC,QAAQ;GACP;EACD;EAGD,OAAO,WAAW,IACf,EAAE,gBAAgB,EAAE,eAAe,OAAO,QAAQ,EAAE,EAAE,IACtD,CAAC;CACL;;;;;CAMA,MAAM,YACL,SACqC;EACrC,MAAM,UAAU,cAAc,OAAO;EACrC,IAAI,WAAW;EAGf,MAAM,eAAe,QAAQ,KAAK,WAAW;GAC5C,OAAO,MAAM;GACb,SAAS,MAAM;GACf,SAAS,MAAM;GACf,WAAW,MAAM;EAClB,EAAE;EAEF,IAAI;GACH,MAAM,KAAK,UAAU,IAAI,YAAY;EACtC,QAAQ;GACP,WAAW,QAAQ;EACpB;EAEA,OAAO,WAAW,IACf,EAAE,gBAAgB,EAAE,oBAAoB,OAAO,QAAQ,EAAE,EAAE,IAC3D,CAAC;CACL;;;;;CAMA,MAAM,eACL,SACwC;EACxC,MAAM,SAAS,iBAAiB,OAAO;EACvC,IAAI,WAAW;EAGf,IAAI,KAAK,WACR,IAAI;GACH,MAAM,KAAK,UAAU,MAAM;EAC5B,QAAQ;GACP,WAAW,OAAO;EACnB;EAID,IAAI,KAAK,cAAc,OAAO,SAAS,GAAG;GACzC,MAAM,aAAa,OAAO,KAAK,WAAW;IACzC,OAAO;IACP,SAAS,gBAAgB,MAAM;IAC/B,SAAS;KACR,MAAM,MAAM;KACZ,OAAO,MAAM;KACb,MAAM,MAAM;KACZ,MAAM,MAAM;KACZ,YAAY,MAAM;IACnB;GACD,EAAE;GAEF,IAAI;IACH,MAAM,KAAK,UAAU,IAAI,UAAU;GACpC,QAAQ,CAER;EACD;EAEA,OAAO,WAAW,IACf,EAAE,gBAAgB,EAAE,oBAAoB,OAAO,QAAQ,EAAE,EAAE,IAC3D,CAAC;CACL;AACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transformer.cjs","names":[],"sources":["../../src/otlp/transformer.ts"],"sourcesContent":["import type { LogEntry, RequestEntry } from '../types';\nimport {\n\ttype AnyValue,\n\ttype ExportLogsServiceRequest,\n\ttype ExportMetricsServiceRequest,\n\ttype ExportTraceServiceRequest,\n\ttype KeyValue,\n\ttype LogRecord,\n\tSeverityNumber,\n\ttype Span,\n\tSpanKind,\n\tSpanStatusCode,\n} from './types';\n\n/**\n * Extract a primitive value from an AnyValue\n */\nfunction extractValue(value?: AnyValue): unknown {\n\tif (!value) return undefined;\n\tif (value.stringValue !== undefined) return value.stringValue;\n\tif (value.boolValue !== undefined) return value.boolValue;\n\tif (value.intValue !== undefined) return parseInt(value.intValue, 10);\n\tif (value.doubleValue !== undefined) return value.doubleValue;\n\tif (value.bytesValue !== undefined) return value.bytesValue;\n\tif (value.arrayValue) return value.arrayValue.values.map(extractValue);\n\tif (value.kvlistValue) return attributesToObject(value.kvlistValue.values);\n\treturn undefined;\n}\n\n/**\n * Convert KeyValue array to a plain object\n */\nfunction attributesToObject(attrs?: KeyValue[]): Record<string, unknown> {\n\tif (!attrs) return {};\n\tconst result: Record<string, unknown> = {};\n\tfor (const attr of attrs) {\n\t\tresult[attr.key] = extractValue(attr.value);\n\t}\n\treturn result;\n}\n\n/**\n * Convert nanoseconds string to Date\n */\nfunction nanoToDate(nanoStr: string): Date {\n\tconst nano = BigInt(nanoStr);\n\tconst ms = Number(nano / BigInt(1_000_000));\n\treturn new Date(ms);\n}\n\n/**\n * Convert nanoseconds string to milliseconds number\n */\nfunction nanoToMs(nanoStr: string): number {\n\tconst nano = BigInt(nanoStr);\n\treturn Number(nano / BigInt(1_000_000));\n}\n\n/**\n * Map OTLP severity number to Telescope log level\n */\nfunction mapSeverity(\n\tseverity?: SeverityNumber,\n): 'debug' | 'info' | 'warn' | 'error' {\n\tif (severity === undefined) return 'info';\n\tif (severity <= SeverityNumber.SEVERITY_NUMBER_DEBUG4) return 'debug';\n\tif (severity <= SeverityNumber.SEVERITY_NUMBER_INFO4) return 'info';\n\tif (severity <= SeverityNumber.SEVERITY_NUMBER_WARN4) return 'warn';\n\treturn 'error';\n}\n\n/**\n * Determine HTTP status from span attributes and status\n */\nfunction getHttpStatus(span: Span): number {\n\tconst attrs = attributesToObject(span.attributes);\n\n\t// Look for HTTP status code in various attribute names\n\tconst statusCode =\n\t\tattrs['http.status_code'] ??\n\t\tattrs['http.response.status_code'] ??\n\t\tattrs['http.response_status_code'];\n\n\tif (typeof statusCode === 'number') return statusCode;\n\tif (typeof statusCode === 'string') return parseInt(statusCode, 10) || 200;\n\n\t// Fall back to span status\n\tif (span.status?.code === SpanStatusCode.STATUS_CODE_ERROR) return 500;\n\tif (span.status?.code === SpanStatusCode.STATUS_CODE_OK) return 200;\n\n\treturn 200;\n}\n\n/**\n * Check if a span represents an HTTP server request\n */\nfunction isHttpServerSpan(span: Span): boolean {\n\tif (span.kind !== SpanKind.SPAN_KIND_SERVER) return false;\n\n\tconst attrs = attributesToObject(span.attributes);\n\treturn !!(\n\t\tattrs['http.method'] ||\n\t\tattrs['http.request.method'] ||\n\t\tattrs['http.url'] ||\n\t\tattrs['http.target'] ||\n\t\tattrs['url.path']\n\t);\n}\n\n/**\n * Transform HTTP-related span attributes to RequestEntry format\n */\nfunction transformHttpSpan(\n\tspan: Span,\n\tresourceAttrs: Record<string, unknown>,\n): Omit<RequestEntry, 'id' | 'timestamp'> {\n\tconst attrs = attributesToObject(span.attributes);\n\n\t// Extract HTTP method\n\tconst method = String(\n\t\tattrs['http.method'] ?? attrs['http.request.method'] ?? 'GET',\n\t).toUpperCase();\n\n\t// Extract path\n\tconst path = String(\n\t\tattrs['http.target'] ?? attrs['url.path'] ?? attrs['http.route'] ?? '/',\n\t);\n\n\t// Extract full URL\n\tconst url = String(\n\t\tattrs['http.url'] ?? attrs['url.full'] ?? `http://localhost${path}`,\n\t);\n\n\t// Extract headers (if available)\n\tconst headers: Record<string, string> = {};\n\tconst userAgent = attrs['http.user_agent'] ?? attrs['user_agent.original'];\n\tif (userAgent) headers['user-agent'] = String(userAgent);\n\n\tconst contentType = attrs['http.request.header.content_type'];\n\tif (contentType) headers['content-type'] = String(contentType);\n\n\t// Calculate duration\n\tconst startTime = nanoToMs(span.startTimeUnixNano);\n\tconst endTime = nanoToMs(span.endTimeUnixNano);\n\tconst duration = endTime - startTime;\n\n\t// Get status code\n\tconst status = getHttpStatus(span);\n\n\t// Extract client IP\n\tconst ip =\n\t\tattrs['net.peer.ip'] ?? attrs['client.address'] ?? attrs['http.client_ip'];\n\n\treturn {\n\t\tmethod,\n\t\tpath,\n\t\turl,\n\t\theaders,\n\t\tquery: {},\n\t\tstatus,\n\t\tresponseHeaders: {},\n\t\tduration,\n\t\tip: ip ? String(ip) : undefined,\n\t\ttags: [\n\t\t\t`trace:${span.traceId}`,\n\t\t\t`span:${span.spanId}`,\n\t\t\t...(resourceAttrs['service.name']\n\t\t\t\t? [`service:${resourceAttrs['service.name']}`]\n\t\t\t\t: []),\n\t\t],\n\t};\n}\n\n/**\n * Transform OTLP traces to Telescope RequestEntries\n * Only transforms HTTP server spans to request entries\n */\nexport function transformTraces(\n\trequest: ExportTraceServiceRequest,\n): Array<Omit<RequestEntry, 'id' | 'timestamp'>> {\n\tconst entries: Array<Omit<RequestEntry, 'id' | 'timestamp'>> = [];\n\n\tfor (const resourceSpans of request.resourceSpans ?? []) {\n\t\tconst resourceAttrs = attributesToObject(\n\t\t\tresourceSpans.resource?.attributes,\n\t\t);\n\n\t\tfor (const scopeSpans of resourceSpans.scopeSpans ?? []) {\n\t\t\tfor (const span of scopeSpans.spans ?? []) {\n\t\t\t\t// Only transform HTTP server spans\n\t\t\t\tif (isHttpServerSpan(span)) {\n\t\t\t\t\tentries.push(transformHttpSpan(span, resourceAttrs));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn entries;\n}\n\n/**\n * Transform a single OTLP log record to Telescope LogEntry\n */\nfunction transformLogRecord(\n\trecord: LogRecord,\n\tresourceAttrs: Record<string, unknown>,\n\tscopeName?: string,\n): Omit<LogEntry, 'id' | 'timestamp'> {\n\tconst attrs = attributesToObject(record.attributes);\n\n\t// Extract message from body\n\tlet message = '';\n\tif (record.body) {\n\t\tconst bodyValue = extractValue(record.body);\n\t\tmessage =\n\t\t\ttypeof bodyValue === 'string' ? bodyValue : JSON.stringify(bodyValue);\n\t}\n\n\t// Build context from attributes\n\tconst context: Record<string, unknown> = {\n\t\t...attrs,\n\t\t...resourceAttrs,\n\t};\n\n\tif (scopeName) {\n\t\tcontext['instrumentation.scope'] = scopeName;\n\t}\n\n\t// Add severity text if present\n\tif (record.severityText) {\n\t\tcontext['severity.text'] = record.severityText;\n\t}\n\n\treturn {\n\t\tlevel: mapSeverity(record.severityNumber),\n\t\tmessage,\n\t\tcontext: Object.keys(context).length > 0 ? context : undefined,\n\t\trequestId: record.spanId ? `span:${record.spanId}` : undefined,\n\t};\n}\n\n/**\n * Transform OTLP logs to Telescope LogEntries\n */\nexport function transformLogs(\n\trequest: ExportLogsServiceRequest,\n): Array<Omit<LogEntry, 'id' | 'timestamp'>> {\n\tconst entries: Array<Omit<LogEntry, 'id' | 'timestamp'>> = [];\n\n\tfor (const resourceLogs of request.resourceLogs ?? []) {\n\t\tconst resourceAttrs = attributesToObject(resourceLogs.resource?.attributes);\n\n\t\tfor (const scopeLogs of resourceLogs.scopeLogs ?? []) {\n\t\t\tconst scopeName = scopeLogs.scope?.name;\n\n\t\t\tfor (const record of scopeLogs.logRecords ?? []) {\n\t\t\t\tentries.push(transformLogRecord(record, resourceAttrs, scopeName));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn entries;\n}\n\n/**\n * Extracted metric data point for recording\n */\nexport interface MetricDataPoint {\n\tname: string;\n\tdescription?: string;\n\tunit?: string;\n\tvalue: number;\n\ttimestamp: Date;\n\tattributes: Record<string, unknown>;\n\tresourceAttributes: Record<string, unknown>;\n\ttype: 'gauge' | 'sum' | 'histogram' | 'summary';\n}\n\n/**\n * Transform OTLP metrics to normalized data points\n * These can be used for custom metrics processing or forwarding\n */\nexport function transformMetrics(\n\trequest: ExportMetricsServiceRequest,\n): MetricDataPoint[] {\n\tconst points: MetricDataPoint[] = [];\n\n\tfor (const resourceMetrics of request.resourceMetrics ?? []) {\n\t\tconst resourceAttrs = attributesToObject(\n\t\t\tresourceMetrics.resource?.attributes,\n\t\t);\n\n\t\tfor (const scopeMetrics of resourceMetrics.scopeMetrics ?? []) {\n\t\t\tfor (const metric of scopeMetrics.metrics ?? []) {\n\t\t\t\tconst baseMeta = {\n\t\t\t\t\tname: metric.name,\n\t\t\t\t\tdescription: metric.description,\n\t\t\t\t\tunit: metric.unit,\n\t\t\t\t\tresourceAttributes: resourceAttrs,\n\t\t\t\t};\n\n\t\t\t\t// Handle gauge\n\t\t\t\tif (metric.gauge) {\n\t\t\t\t\tfor (const dp of metric.gauge.dataPoints) {\n\t\t\t\t\t\tpoints.push({\n\t\t\t\t\t\t\t...baseMeta,\n\t\t\t\t\t\t\tvalue: dp.asDouble ?? (dp.asInt ? parseInt(dp.asInt, 10) : 0),\n\t\t\t\t\t\t\ttimestamp: nanoToDate(dp.timeUnixNano),\n\t\t\t\t\t\t\tattributes: attributesToObject(dp.attributes),\n\t\t\t\t\t\t\ttype: 'gauge',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Handle sum (counter)\n\t\t\t\tif (metric.sum) {\n\t\t\t\t\tfor (const dp of metric.sum.dataPoints) {\n\t\t\t\t\t\tpoints.push({\n\t\t\t\t\t\t\t...baseMeta,\n\t\t\t\t\t\t\tvalue: dp.asDouble ?? (dp.asInt ? parseInt(dp.asInt, 10) : 0),\n\t\t\t\t\t\t\ttimestamp: nanoToDate(dp.timeUnixNano),\n\t\t\t\t\t\t\tattributes: attributesToObject(dp.attributes),\n\t\t\t\t\t\t\ttype: 'sum',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Handle histogram (extract sum as the value)\n\t\t\t\tif (metric.histogram) {\n\t\t\t\t\tfor (const dp of metric.histogram.dataPoints) {\n\t\t\t\t\t\tpoints.push({\n\t\t\t\t\t\t\t...baseMeta,\n\t\t\t\t\t\t\tvalue: dp.sum ?? 0,\n\t\t\t\t\t\t\ttimestamp: nanoToDate(dp.timeUnixNano),\n\t\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t\t...attributesToObject(dp.attributes),\n\t\t\t\t\t\t\t\tcount: parseInt(dp.count, 10),\n\t\t\t\t\t\t\t\tmin: dp.min,\n\t\t\t\t\t\t\t\tmax: dp.max,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttype: 'histogram',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Handle summary\n\t\t\t\tif (metric.summary) {\n\t\t\t\t\tfor (const dp of metric.summary.dataPoints) {\n\t\t\t\t\t\tpoints.push({\n\t\t\t\t\t\t\t...baseMeta,\n\t\t\t\t\t\t\tvalue: dp.sum ?? 0,\n\t\t\t\t\t\t\ttimestamp: nanoToDate(dp.timeUnixNano),\n\t\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t\t...attributesToObject(dp.attributes),\n\t\t\t\t\t\t\t\tcount: parseInt(dp.count, 10),\n\t\t\t\t\t\t\t\tquantiles: dp.quantileValues,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttype: 'summary',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn points;\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transformer.mjs","names":[],"sources":["../../src/otlp/transformer.ts"],"sourcesContent":["import type { LogEntry, RequestEntry } from '../types';\nimport {\n\ttype AnyValue,\n\ttype ExportLogsServiceRequest,\n\ttype ExportMetricsServiceRequest,\n\ttype ExportTraceServiceRequest,\n\ttype KeyValue,\n\ttype LogRecord,\n\tSeverityNumber,\n\ttype Span,\n\tSpanKind,\n\tSpanStatusCode,\n} from './types';\n\n/**\n * Extract a primitive value from an AnyValue\n */\nfunction extractValue(value?: AnyValue): unknown {\n\tif (!value) return undefined;\n\tif (value.stringValue !== undefined) return value.stringValue;\n\tif (value.boolValue !== undefined) return value.boolValue;\n\tif (value.intValue !== undefined) return parseInt(value.intValue, 10);\n\tif (value.doubleValue !== undefined) return value.doubleValue;\n\tif (value.bytesValue !== undefined) return value.bytesValue;\n\tif (value.arrayValue) return value.arrayValue.values.map(extractValue);\n\tif (value.kvlistValue) return attributesToObject(value.kvlistValue.values);\n\treturn undefined;\n}\n\n/**\n * Convert KeyValue array to a plain object\n */\nfunction attributesToObject(attrs?: KeyValue[]): Record<string, unknown> {\n\tif (!attrs) return {};\n\tconst result: Record<string, unknown> = {};\n\tfor (const attr of attrs) {\n\t\tresult[attr.key] = extractValue(attr.value);\n\t}\n\treturn result;\n}\n\n/**\n * Convert nanoseconds string to Date\n */\nfunction nanoToDate(nanoStr: string): Date {\n\tconst nano = BigInt(nanoStr);\n\tconst ms = Number(nano / BigInt(1_000_000));\n\treturn new Date(ms);\n}\n\n/**\n * Convert nanoseconds string to milliseconds number\n */\nfunction nanoToMs(nanoStr: string): number {\n\tconst nano = BigInt(nanoStr);\n\treturn Number(nano / BigInt(1_000_000));\n}\n\n/**\n * Map OTLP severity number to Telescope log level\n */\nfunction mapSeverity(\n\tseverity?: SeverityNumber,\n): 'debug' | 'info' | 'warn' | 'error' {\n\tif (severity === undefined) return 'info';\n\tif (severity <= SeverityNumber.SEVERITY_NUMBER_DEBUG4) return 'debug';\n\tif (severity <= SeverityNumber.SEVERITY_NUMBER_INFO4) return 'info';\n\tif (severity <= SeverityNumber.SEVERITY_NUMBER_WARN4) return 'warn';\n\treturn 'error';\n}\n\n/**\n * Determine HTTP status from span attributes and status\n */\nfunction getHttpStatus(span: Span): number {\n\tconst attrs = attributesToObject(span.attributes);\n\n\t// Look for HTTP status code in various attribute names\n\tconst statusCode =\n\t\tattrs['http.status_code'] ??\n\t\tattrs['http.response.status_code'] ??\n\t\tattrs['http.response_status_code'];\n\n\tif (typeof statusCode === 'number') return statusCode;\n\tif (typeof statusCode === 'string') return parseInt(statusCode, 10) || 200;\n\n\t// Fall back to span status\n\tif (span.status?.code === SpanStatusCode.STATUS_CODE_ERROR) return 500;\n\tif (span.status?.code === SpanStatusCode.STATUS_CODE_OK) return 200;\n\n\treturn 200;\n}\n\n/**\n * Check if a span represents an HTTP server request\n */\nfunction isHttpServerSpan(span: Span): boolean {\n\tif (span.kind !== SpanKind.SPAN_KIND_SERVER) return false;\n\n\tconst attrs = attributesToObject(span.attributes);\n\treturn !!(\n\t\tattrs['http.method'] ||\n\t\tattrs['http.request.method'] ||\n\t\tattrs['http.url'] ||\n\t\tattrs['http.target'] ||\n\t\tattrs['url.path']\n\t);\n}\n\n/**\n * Transform HTTP-related span attributes to RequestEntry format\n */\nfunction transformHttpSpan(\n\tspan: Span,\n\tresourceAttrs: Record<string, unknown>,\n): Omit<RequestEntry, 'id' | 'timestamp'> {\n\tconst attrs = attributesToObject(span.attributes);\n\n\t// Extract HTTP method\n\tconst method = String(\n\t\tattrs['http.method'] ?? attrs['http.request.method'] ?? 'GET',\n\t).toUpperCase();\n\n\t// Extract path\n\tconst path = String(\n\t\tattrs['http.target'] ?? attrs['url.path'] ?? attrs['http.route'] ?? '/',\n\t);\n\n\t// Extract full URL\n\tconst url = String(\n\t\tattrs['http.url'] ?? attrs['url.full'] ?? `http://localhost${path}`,\n\t);\n\n\t// Extract headers (if available)\n\tconst headers: Record<string, string> = {};\n\tconst userAgent = attrs['http.user_agent'] ?? attrs['user_agent.original'];\n\tif (userAgent) headers['user-agent'] = String(userAgent);\n\n\tconst contentType = attrs['http.request.header.content_type'];\n\tif (contentType) headers['content-type'] = String(contentType);\n\n\t// Calculate duration\n\tconst startTime = nanoToMs(span.startTimeUnixNano);\n\tconst endTime = nanoToMs(span.endTimeUnixNano);\n\tconst duration = endTime - startTime;\n\n\t// Get status code\n\tconst status = getHttpStatus(span);\n\n\t// Extract client IP\n\tconst ip =\n\t\tattrs['net.peer.ip'] ?? attrs['client.address'] ?? attrs['http.client_ip'];\n\n\treturn {\n\t\tmethod,\n\t\tpath,\n\t\turl,\n\t\theaders,\n\t\tquery: {},\n\t\tstatus,\n\t\tresponseHeaders: {},\n\t\tduration,\n\t\tip: ip ? String(ip) : undefined,\n\t\ttags: [\n\t\t\t`trace:${span.traceId}`,\n\t\t\t`span:${span.spanId}`,\n\t\t\t...(resourceAttrs['service.name']\n\t\t\t\t? [`service:${resourceAttrs['service.name']}`]\n\t\t\t\t: []),\n\t\t],\n\t};\n}\n\n/**\n * Transform OTLP traces to Telescope RequestEntries\n * Only transforms HTTP server spans to request entries\n */\nexport function transformTraces(\n\trequest: ExportTraceServiceRequest,\n): Array<Omit<RequestEntry, 'id' | 'timestamp'>> {\n\tconst entries: Array<Omit<RequestEntry, 'id' | 'timestamp'>> = [];\n\n\tfor (const resourceSpans of request.resourceSpans ?? []) {\n\t\tconst resourceAttrs = attributesToObject(\n\t\t\tresourceSpans.resource?.attributes,\n\t\t);\n\n\t\tfor (const scopeSpans of resourceSpans.scopeSpans ?? []) {\n\t\t\tfor (const span of scopeSpans.spans ?? []) {\n\t\t\t\t// Only transform HTTP server spans\n\t\t\t\tif (isHttpServerSpan(span)) {\n\t\t\t\t\tentries.push(transformHttpSpan(span, resourceAttrs));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn entries;\n}\n\n/**\n * Transform a single OTLP log record to Telescope LogEntry\n */\nfunction transformLogRecord(\n\trecord: LogRecord,\n\tresourceAttrs: Record<string, unknown>,\n\tscopeName?: string,\n): Omit<LogEntry, 'id' | 'timestamp'> {\n\tconst attrs = attributesToObject(record.attributes);\n\n\t// Extract message from body\n\tlet message = '';\n\tif (record.body) {\n\t\tconst bodyValue = extractValue(record.body);\n\t\tmessage =\n\t\t\ttypeof bodyValue === 'string' ? bodyValue : JSON.stringify(bodyValue);\n\t}\n\n\t// Build context from attributes\n\tconst context: Record<string, unknown> = {\n\t\t...attrs,\n\t\t...resourceAttrs,\n\t};\n\n\tif (scopeName) {\n\t\tcontext['instrumentation.scope'] = scopeName;\n\t}\n\n\t// Add severity text if present\n\tif (record.severityText) {\n\t\tcontext['severity.text'] = record.severityText;\n\t}\n\n\treturn {\n\t\tlevel: mapSeverity(record.severityNumber),\n\t\tmessage,\n\t\tcontext: Object.keys(context).length > 0 ? context : undefined,\n\t\trequestId: record.spanId ? `span:${record.spanId}` : undefined,\n\t};\n}\n\n/**\n * Transform OTLP logs to Telescope LogEntries\n */\nexport function transformLogs(\n\trequest: ExportLogsServiceRequest,\n): Array<Omit<LogEntry, 'id' | 'timestamp'>> {\n\tconst entries: Array<Omit<LogEntry, 'id' | 'timestamp'>> = [];\n\n\tfor (const resourceLogs of request.resourceLogs ?? []) {\n\t\tconst resourceAttrs = attributesToObject(resourceLogs.resource?.attributes);\n\n\t\tfor (const scopeLogs of resourceLogs.scopeLogs ?? []) {\n\t\t\tconst scopeName = scopeLogs.scope?.name;\n\n\t\t\tfor (const record of scopeLogs.logRecords ?? []) {\n\t\t\t\tentries.push(transformLogRecord(record, resourceAttrs, scopeName));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn entries;\n}\n\n/**\n * Extracted metric data point for recording\n */\nexport interface MetricDataPoint {\n\tname: string;\n\tdescription?: string;\n\tunit?: string;\n\tvalue: number;\n\ttimestamp: Date;\n\tattributes: Record<string, unknown>;\n\tresourceAttributes: Record<string, unknown>;\n\ttype: 'gauge' | 'sum' | 'histogram' | 'summary';\n}\n\n/**\n * Transform OTLP metrics to normalized data points\n * These can be used for custom metrics processing or forwarding\n */\nexport function transformMetrics(\n\trequest: ExportMetricsServiceRequest,\n): MetricDataPoint[] {\n\tconst points: MetricDataPoint[] = [];\n\n\tfor (const resourceMetrics of request.resourceMetrics ?? []) {\n\t\tconst resourceAttrs = attributesToObject(\n\t\t\tresourceMetrics.resource?.attributes,\n\t\t);\n\n\t\tfor (const scopeMetrics of resourceMetrics.scopeMetrics ?? []) {\n\t\t\tfor (const metric of scopeMetrics.metrics ?? []) {\n\t\t\t\tconst baseMeta = {\n\t\t\t\t\tname: metric.name,\n\t\t\t\t\tdescription: metric.description,\n\t\t\t\t\tunit: metric.unit,\n\t\t\t\t\tresourceAttributes: resourceAttrs,\n\t\t\t\t};\n\n\t\t\t\t// Handle gauge\n\t\t\t\tif (metric.gauge) {\n\t\t\t\t\tfor (const dp of metric.gauge.dataPoints) {\n\t\t\t\t\t\tpoints.push({\n\t\t\t\t\t\t\t...baseMeta,\n\t\t\t\t\t\t\tvalue: dp.asDouble ?? (dp.asInt ? parseInt(dp.asInt, 10) : 0),\n\t\t\t\t\t\t\ttimestamp: nanoToDate(dp.timeUnixNano),\n\t\t\t\t\t\t\tattributes: attributesToObject(dp.attributes),\n\t\t\t\t\t\t\ttype: 'gauge',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Handle sum (counter)\n\t\t\t\tif (metric.sum) {\n\t\t\t\t\tfor (const dp of metric.sum.dataPoints) {\n\t\t\t\t\t\tpoints.push({\n\t\t\t\t\t\t\t...baseMeta,\n\t\t\t\t\t\t\tvalue: dp.asDouble ?? (dp.asInt ? parseInt(dp.asInt, 10) : 0),\n\t\t\t\t\t\t\ttimestamp: nanoToDate(dp.timeUnixNano),\n\t\t\t\t\t\t\tattributes: attributesToObject(dp.attributes),\n\t\t\t\t\t\t\ttype: 'sum',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Handle histogram (extract sum as the value)\n\t\t\t\tif (metric.histogram) {\n\t\t\t\t\tfor (const dp of metric.histogram.dataPoints) {\n\t\t\t\t\t\tpoints.push({\n\t\t\t\t\t\t\t...baseMeta,\n\t\t\t\t\t\t\tvalue: dp.sum ?? 0,\n\t\t\t\t\t\t\ttimestamp: nanoToDate(dp.timeUnixNano),\n\t\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t\t...attributesToObject(dp.attributes),\n\t\t\t\t\t\t\t\tcount: parseInt(dp.count, 10),\n\t\t\t\t\t\t\t\tmin: dp.min,\n\t\t\t\t\t\t\t\tmax: dp.max,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttype: 'histogram',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Handle summary\n\t\t\t\tif (metric.summary) {\n\t\t\t\t\tfor (const dp of metric.summary.dataPoints) {\n\t\t\t\t\t\tpoints.push({\n\t\t\t\t\t\t\t...baseMeta,\n\t\t\t\t\t\t\tvalue: dp.sum ?? 0,\n\t\t\t\t\t\t\ttimestamp: nanoToDate(dp.timeUnixNano),\n\t\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t\t...attributesToObject(dp.attributes),\n\t\t\t\t\t\t\t\tcount: parseInt(dp.count, 10),\n\t\t\t\t\t\t\t\tquantiles: dp.quantileValues,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttype: 'summary',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn points;\n}\n"],"mappings":"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"}
|
package/dist/otlp/types.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.cjs","names":[],"sources":["../../src/otlp/types.ts"],"sourcesContent":["/**\n * OTLP JSON types based on OpenTelemetry Protocol specification.\n * These types represent the JSON encoding of OTLP protobuf messages.\n * @see https://opentelemetry.io/docs/specs/otlp/\n */\n\n// ============================================\n// Common Types\n// ============================================\n\n/**\n * Key-value pair for attributes\n */\nexport interface KeyValue {\n\tkey: string;\n\tvalue: AnyValue;\n}\n\n/**\n * Any value type (string, bool, int, double, array, kvlist, bytes)\n */\nexport interface AnyValue {\n\tstringValue?: string;\n\tboolValue?: boolean;\n\tintValue?: string; // int64 as string\n\tdoubleValue?: number;\n\tarrayValue?: ArrayValue;\n\tkvlistValue?: KeyValueList;\n\tbytesValue?: string; // base64 encoded\n}\n\nexport interface ArrayValue {\n\tvalues: AnyValue[];\n}\n\nexport interface KeyValueList {\n\tvalues: KeyValue[];\n}\n\n/**\n * Resource represents the entity producing telemetry\n */\nexport interface Resource {\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n}\n\n/**\n * InstrumentationScope represents the instrumentation library\n */\nexport interface InstrumentationScope {\n\tname: string;\n\tversion?: string;\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n}\n\n// ============================================\n// Trace Types\n// ============================================\n\n/**\n * Root message for trace export\n */\nexport interface ExportTraceServiceRequest {\n\tresourceSpans?: ResourceSpans[];\n}\n\nexport interface ResourceSpans {\n\tresource?: Resource;\n\tscopeSpans?: ScopeSpans[];\n\tschemaUrl?: string;\n}\n\nexport interface ScopeSpans {\n\tscope?: InstrumentationScope;\n\tspans?: Span[];\n\tschemaUrl?: string;\n}\n\nexport interface Span {\n\ttraceId: string; // hex encoded 16 bytes\n\tspanId: string; // hex encoded 8 bytes\n\ttraceState?: string;\n\tparentSpanId?: string; // hex encoded 8 bytes\n\tflags?: number;\n\tname: string;\n\tkind?: SpanKind;\n\tstartTimeUnixNano: string; // uint64 as string\n\tendTimeUnixNano: string; // uint64 as string\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n\tevents?: SpanEvent[];\n\tdroppedEventsCount?: number;\n\tlinks?: SpanLink[];\n\tdroppedLinksCount?: number;\n\tstatus?: SpanStatus;\n}\n\nexport enum SpanKind {\n\tSPAN_KIND_UNSPECIFIED = 0,\n\tSPAN_KIND_INTERNAL = 1,\n\tSPAN_KIND_SERVER = 2,\n\tSPAN_KIND_CLIENT = 3,\n\tSPAN_KIND_PRODUCER = 4,\n\tSPAN_KIND_CONSUMER = 5,\n}\n\nexport interface SpanEvent {\n\ttimeUnixNano: string;\n\tname: string;\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n}\n\nexport interface SpanLink {\n\ttraceId: string;\n\tspanId: string;\n\ttraceState?: string;\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n\tflags?: number;\n}\n\nexport interface SpanStatus {\n\tmessage?: string;\n\tcode?: SpanStatusCode;\n}\n\nexport enum SpanStatusCode {\n\tSTATUS_CODE_UNSET = 0,\n\tSTATUS_CODE_OK = 1,\n\tSTATUS_CODE_ERROR = 2,\n}\n\n// ============================================\n// Log Types\n// ============================================\n\n/**\n * Root message for log export\n */\nexport interface ExportLogsServiceRequest {\n\tresourceLogs?: ResourceLogs[];\n}\n\nexport interface ResourceLogs {\n\tresource?: Resource;\n\tscopeLogs?: ScopeLogs[];\n\tschemaUrl?: string;\n}\n\nexport interface ScopeLogs {\n\tscope?: InstrumentationScope;\n\tlogRecords?: LogRecord[];\n\tschemaUrl?: string;\n}\n\nexport interface LogRecord {\n\ttimeUnixNano?: string;\n\tobservedTimeUnixNano: string;\n\tseverityNumber?: SeverityNumber;\n\tseverityText?: string;\n\tbody?: AnyValue;\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n\tflags?: number;\n\ttraceId?: string;\n\tspanId?: string;\n}\n\nexport enum SeverityNumber {\n\tSEVERITY_NUMBER_UNSPECIFIED = 0,\n\tSEVERITY_NUMBER_TRACE = 1,\n\tSEVERITY_NUMBER_TRACE2 = 2,\n\tSEVERITY_NUMBER_TRACE3 = 3,\n\tSEVERITY_NUMBER_TRACE4 = 4,\n\tSEVERITY_NUMBER_DEBUG = 5,\n\tSEVERITY_NUMBER_DEBUG2 = 6,\n\tSEVERITY_NUMBER_DEBUG3 = 7,\n\tSEVERITY_NUMBER_DEBUG4 = 8,\n\tSEVERITY_NUMBER_INFO = 9,\n\tSEVERITY_NUMBER_INFO2 = 10,\n\tSEVERITY_NUMBER_INFO3 = 11,\n\tSEVERITY_NUMBER_INFO4 = 12,\n\tSEVERITY_NUMBER_WARN = 13,\n\tSEVERITY_NUMBER_WARN2 = 14,\n\tSEVERITY_NUMBER_WARN3 = 15,\n\tSEVERITY_NUMBER_WARN4 = 16,\n\tSEVERITY_NUMBER_ERROR = 17,\n\tSEVERITY_NUMBER_ERROR2 = 18,\n\tSEVERITY_NUMBER_ERROR3 = 19,\n\tSEVERITY_NUMBER_ERROR4 = 20,\n\tSEVERITY_NUMBER_FATAL = 21,\n\tSEVERITY_NUMBER_FATAL2 = 22,\n\tSEVERITY_NUMBER_FATAL3 = 23,\n\tSEVERITY_NUMBER_FATAL4 = 24,\n}\n\n// ============================================\n// Metrics Types\n// ============================================\n\n/**\n * Root message for metrics export\n */\nexport interface ExportMetricsServiceRequest {\n\tresourceMetrics?: ResourceMetrics[];\n}\n\nexport interface ResourceMetrics {\n\tresource?: Resource;\n\tscopeMetrics?: ScopeMetrics[];\n\tschemaUrl?: string;\n}\n\nexport interface ScopeMetrics {\n\tscope?: InstrumentationScope;\n\tmetrics?: Metric[];\n\tschemaUrl?: string;\n}\n\nexport interface Metric {\n\tname: string;\n\tdescription?: string;\n\tunit?: string;\n\tmetadata?: KeyValue[];\n\tgauge?: Gauge;\n\tsum?: Sum;\n\thistogram?: Histogram;\n\texponentialHistogram?: ExponentialHistogram;\n\tsummary?: Summary;\n}\n\nexport interface Gauge {\n\tdataPoints: NumberDataPoint[];\n}\n\nexport interface Sum {\n\tdataPoints: NumberDataPoint[];\n\taggregationTemporality: AggregationTemporality;\n\tisMonotonic?: boolean;\n}\n\nexport interface Histogram {\n\tdataPoints: HistogramDataPoint[];\n\taggregationTemporality: AggregationTemporality;\n}\n\nexport interface ExponentialHistogram {\n\tdataPoints: ExponentialHistogramDataPoint[];\n\taggregationTemporality: AggregationTemporality;\n}\n\nexport interface Summary {\n\tdataPoints: SummaryDataPoint[];\n}\n\nexport enum AggregationTemporality {\n\tAGGREGATION_TEMPORALITY_UNSPECIFIED = 0,\n\tAGGREGATION_TEMPORALITY_DELTA = 1,\n\tAGGREGATION_TEMPORALITY_CUMULATIVE = 2,\n}\n\nexport interface NumberDataPoint {\n\tattributes?: KeyValue[];\n\tstartTimeUnixNano?: string;\n\ttimeUnixNano: string;\n\tasDouble?: number;\n\tasInt?: string;\n\texemplars?: Exemplar[];\n\tflags?: number;\n}\n\nexport interface HistogramDataPoint {\n\tattributes?: KeyValue[];\n\tstartTimeUnixNano?: string;\n\ttimeUnixNano: string;\n\tcount: string;\n\tsum?: number;\n\tbucketCounts?: string[];\n\texplicitBounds?: number[];\n\texemplars?: Exemplar[];\n\tflags?: number;\n\tmin?: number;\n\tmax?: number;\n}\n\nexport interface ExponentialHistogramDataPoint {\n\tattributes?: KeyValue[];\n\tstartTimeUnixNano?: string;\n\ttimeUnixNano: string;\n\tcount: string;\n\tsum?: number;\n\tscale?: number;\n\tzeroCount?: string;\n\tpositive?: Buckets;\n\tnegative?: Buckets;\n\tflags?: number;\n\texemplars?: Exemplar[];\n\tmin?: number;\n\tmax?: number;\n\tzeroThreshold?: number;\n}\n\nexport interface Buckets {\n\toffset?: number;\n\tbucketCounts?: string[];\n}\n\nexport interface SummaryDataPoint {\n\tattributes?: KeyValue[];\n\tstartTimeUnixNano?: string;\n\ttimeUnixNano: string;\n\tcount: string;\n\tsum?: number;\n\tquantileValues?: ValueAtQuantile[];\n\tflags?: number;\n}\n\nexport interface ValueAtQuantile {\n\tquantile: number;\n\tvalue: number;\n}\n\nexport interface Exemplar {\n\tfilteredAttributes?: KeyValue[];\n\ttimeUnixNano: string;\n\tasDouble?: number;\n\tasInt?: string;\n\tspanId?: string;\n\ttraceId?: string;\n}\n\n// ============================================\n// Response Types\n// ============================================\n\nexport interface ExportTraceServiceResponse {\n\tpartialSuccess?: ExportTracePartialSuccess;\n}\n\nexport interface ExportTracePartialSuccess {\n\trejectedSpans?: string;\n\terrorMessage?: string;\n}\n\nexport interface ExportLogsServiceResponse {\n\tpartialSuccess?: ExportLogsPartialSuccess;\n}\n\nexport interface ExportLogsPartialSuccess {\n\trejectedLogRecords?: string;\n\terrorMessage?: string;\n}\n\nexport interface ExportMetricsServiceResponse {\n\tpartialSuccess?: ExportMetricsPartialSuccess;\n}\n\nexport interface ExportMetricsPartialSuccess {\n\trejectedDataPoints?: string;\n\terrorMessage?: string;\n}\n"],"mappings":";;AAmGA,IAAY,WAAL,yBAAA,UAAA;CACN,SAAA,SAAA,2BAAA,KAAA;CACA,SAAA,SAAA,wBAAA,KAAA;CACA,SAAA,SAAA,sBAAA,KAAA;CACA,SAAA,SAAA,sBAAA,KAAA;CACA,SAAA,SAAA,wBAAA,KAAA;CACA,SAAA,SAAA,wBAAA,KAAA;;AACD,EAAA,CAAA,CAAA;AAuBA,IAAY,iBAAL,yBAAA,gBAAA;CACN,eAAA,eAAA,uBAAA,KAAA;CACA,eAAA,eAAA,oBAAA,KAAA;CACA,eAAA,eAAA,uBAAA,KAAA;;AACD,EAAA,CAAA,CAAA;AAsCA,IAAY,iBAAL,yBAAA,gBAAA;CACN,eAAA,eAAA,iCAAA,KAAA;CACA,eAAA,eAAA,2BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,2BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,0BAAA,KAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,0BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;;AACD,EAAA,CAAA,CAAA;AA6DA,IAAY,yBAAL,yBAAA,wBAAA;CACN,uBAAA,uBAAA,yCAAA,KAAA;CACA,uBAAA,uBAAA,mCAAA,KAAA;CACA,uBAAA,uBAAA,wCAAA,KAAA;;AACD,EAAA,CAAA,CAAA"}
|
package/dist/otlp/types.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.mjs","names":[],"sources":["../../src/otlp/types.ts"],"sourcesContent":["/**\n * OTLP JSON types based on OpenTelemetry Protocol specification.\n * These types represent the JSON encoding of OTLP protobuf messages.\n * @see https://opentelemetry.io/docs/specs/otlp/\n */\n\n// ============================================\n// Common Types\n// ============================================\n\n/**\n * Key-value pair for attributes\n */\nexport interface KeyValue {\n\tkey: string;\n\tvalue: AnyValue;\n}\n\n/**\n * Any value type (string, bool, int, double, array, kvlist, bytes)\n */\nexport interface AnyValue {\n\tstringValue?: string;\n\tboolValue?: boolean;\n\tintValue?: string; // int64 as string\n\tdoubleValue?: number;\n\tarrayValue?: ArrayValue;\n\tkvlistValue?: KeyValueList;\n\tbytesValue?: string; // base64 encoded\n}\n\nexport interface ArrayValue {\n\tvalues: AnyValue[];\n}\n\nexport interface KeyValueList {\n\tvalues: KeyValue[];\n}\n\n/**\n * Resource represents the entity producing telemetry\n */\nexport interface Resource {\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n}\n\n/**\n * InstrumentationScope represents the instrumentation library\n */\nexport interface InstrumentationScope {\n\tname: string;\n\tversion?: string;\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n}\n\n// ============================================\n// Trace Types\n// ============================================\n\n/**\n * Root message for trace export\n */\nexport interface ExportTraceServiceRequest {\n\tresourceSpans?: ResourceSpans[];\n}\n\nexport interface ResourceSpans {\n\tresource?: Resource;\n\tscopeSpans?: ScopeSpans[];\n\tschemaUrl?: string;\n}\n\nexport interface ScopeSpans {\n\tscope?: InstrumentationScope;\n\tspans?: Span[];\n\tschemaUrl?: string;\n}\n\nexport interface Span {\n\ttraceId: string; // hex encoded 16 bytes\n\tspanId: string; // hex encoded 8 bytes\n\ttraceState?: string;\n\tparentSpanId?: string; // hex encoded 8 bytes\n\tflags?: number;\n\tname: string;\n\tkind?: SpanKind;\n\tstartTimeUnixNano: string; // uint64 as string\n\tendTimeUnixNano: string; // uint64 as string\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n\tevents?: SpanEvent[];\n\tdroppedEventsCount?: number;\n\tlinks?: SpanLink[];\n\tdroppedLinksCount?: number;\n\tstatus?: SpanStatus;\n}\n\nexport enum SpanKind {\n\tSPAN_KIND_UNSPECIFIED = 0,\n\tSPAN_KIND_INTERNAL = 1,\n\tSPAN_KIND_SERVER = 2,\n\tSPAN_KIND_CLIENT = 3,\n\tSPAN_KIND_PRODUCER = 4,\n\tSPAN_KIND_CONSUMER = 5,\n}\n\nexport interface SpanEvent {\n\ttimeUnixNano: string;\n\tname: string;\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n}\n\nexport interface SpanLink {\n\ttraceId: string;\n\tspanId: string;\n\ttraceState?: string;\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n\tflags?: number;\n}\n\nexport interface SpanStatus {\n\tmessage?: string;\n\tcode?: SpanStatusCode;\n}\n\nexport enum SpanStatusCode {\n\tSTATUS_CODE_UNSET = 0,\n\tSTATUS_CODE_OK = 1,\n\tSTATUS_CODE_ERROR = 2,\n}\n\n// ============================================\n// Log Types\n// ============================================\n\n/**\n * Root message for log export\n */\nexport interface ExportLogsServiceRequest {\n\tresourceLogs?: ResourceLogs[];\n}\n\nexport interface ResourceLogs {\n\tresource?: Resource;\n\tscopeLogs?: ScopeLogs[];\n\tschemaUrl?: string;\n}\n\nexport interface ScopeLogs {\n\tscope?: InstrumentationScope;\n\tlogRecords?: LogRecord[];\n\tschemaUrl?: string;\n}\n\nexport interface LogRecord {\n\ttimeUnixNano?: string;\n\tobservedTimeUnixNano: string;\n\tseverityNumber?: SeverityNumber;\n\tseverityText?: string;\n\tbody?: AnyValue;\n\tattributes?: KeyValue[];\n\tdroppedAttributesCount?: number;\n\tflags?: number;\n\ttraceId?: string;\n\tspanId?: string;\n}\n\nexport enum SeverityNumber {\n\tSEVERITY_NUMBER_UNSPECIFIED = 0,\n\tSEVERITY_NUMBER_TRACE = 1,\n\tSEVERITY_NUMBER_TRACE2 = 2,\n\tSEVERITY_NUMBER_TRACE3 = 3,\n\tSEVERITY_NUMBER_TRACE4 = 4,\n\tSEVERITY_NUMBER_DEBUG = 5,\n\tSEVERITY_NUMBER_DEBUG2 = 6,\n\tSEVERITY_NUMBER_DEBUG3 = 7,\n\tSEVERITY_NUMBER_DEBUG4 = 8,\n\tSEVERITY_NUMBER_INFO = 9,\n\tSEVERITY_NUMBER_INFO2 = 10,\n\tSEVERITY_NUMBER_INFO3 = 11,\n\tSEVERITY_NUMBER_INFO4 = 12,\n\tSEVERITY_NUMBER_WARN = 13,\n\tSEVERITY_NUMBER_WARN2 = 14,\n\tSEVERITY_NUMBER_WARN3 = 15,\n\tSEVERITY_NUMBER_WARN4 = 16,\n\tSEVERITY_NUMBER_ERROR = 17,\n\tSEVERITY_NUMBER_ERROR2 = 18,\n\tSEVERITY_NUMBER_ERROR3 = 19,\n\tSEVERITY_NUMBER_ERROR4 = 20,\n\tSEVERITY_NUMBER_FATAL = 21,\n\tSEVERITY_NUMBER_FATAL2 = 22,\n\tSEVERITY_NUMBER_FATAL3 = 23,\n\tSEVERITY_NUMBER_FATAL4 = 24,\n}\n\n// ============================================\n// Metrics Types\n// ============================================\n\n/**\n * Root message for metrics export\n */\nexport interface ExportMetricsServiceRequest {\n\tresourceMetrics?: ResourceMetrics[];\n}\n\nexport interface ResourceMetrics {\n\tresource?: Resource;\n\tscopeMetrics?: ScopeMetrics[];\n\tschemaUrl?: string;\n}\n\nexport interface ScopeMetrics {\n\tscope?: InstrumentationScope;\n\tmetrics?: Metric[];\n\tschemaUrl?: string;\n}\n\nexport interface Metric {\n\tname: string;\n\tdescription?: string;\n\tunit?: string;\n\tmetadata?: KeyValue[];\n\tgauge?: Gauge;\n\tsum?: Sum;\n\thistogram?: Histogram;\n\texponentialHistogram?: ExponentialHistogram;\n\tsummary?: Summary;\n}\n\nexport interface Gauge {\n\tdataPoints: NumberDataPoint[];\n}\n\nexport interface Sum {\n\tdataPoints: NumberDataPoint[];\n\taggregationTemporality: AggregationTemporality;\n\tisMonotonic?: boolean;\n}\n\nexport interface Histogram {\n\tdataPoints: HistogramDataPoint[];\n\taggregationTemporality: AggregationTemporality;\n}\n\nexport interface ExponentialHistogram {\n\tdataPoints: ExponentialHistogramDataPoint[];\n\taggregationTemporality: AggregationTemporality;\n}\n\nexport interface Summary {\n\tdataPoints: SummaryDataPoint[];\n}\n\nexport enum AggregationTemporality {\n\tAGGREGATION_TEMPORALITY_UNSPECIFIED = 0,\n\tAGGREGATION_TEMPORALITY_DELTA = 1,\n\tAGGREGATION_TEMPORALITY_CUMULATIVE = 2,\n}\n\nexport interface NumberDataPoint {\n\tattributes?: KeyValue[];\n\tstartTimeUnixNano?: string;\n\ttimeUnixNano: string;\n\tasDouble?: number;\n\tasInt?: string;\n\texemplars?: Exemplar[];\n\tflags?: number;\n}\n\nexport interface HistogramDataPoint {\n\tattributes?: KeyValue[];\n\tstartTimeUnixNano?: string;\n\ttimeUnixNano: string;\n\tcount: string;\n\tsum?: number;\n\tbucketCounts?: string[];\n\texplicitBounds?: number[];\n\texemplars?: Exemplar[];\n\tflags?: number;\n\tmin?: number;\n\tmax?: number;\n}\n\nexport interface ExponentialHistogramDataPoint {\n\tattributes?: KeyValue[];\n\tstartTimeUnixNano?: string;\n\ttimeUnixNano: string;\n\tcount: string;\n\tsum?: number;\n\tscale?: number;\n\tzeroCount?: string;\n\tpositive?: Buckets;\n\tnegative?: Buckets;\n\tflags?: number;\n\texemplars?: Exemplar[];\n\tmin?: number;\n\tmax?: number;\n\tzeroThreshold?: number;\n}\n\nexport interface Buckets {\n\toffset?: number;\n\tbucketCounts?: string[];\n}\n\nexport interface SummaryDataPoint {\n\tattributes?: KeyValue[];\n\tstartTimeUnixNano?: string;\n\ttimeUnixNano: string;\n\tcount: string;\n\tsum?: number;\n\tquantileValues?: ValueAtQuantile[];\n\tflags?: number;\n}\n\nexport interface ValueAtQuantile {\n\tquantile: number;\n\tvalue: number;\n}\n\nexport interface Exemplar {\n\tfilteredAttributes?: KeyValue[];\n\ttimeUnixNano: string;\n\tasDouble?: number;\n\tasInt?: string;\n\tspanId?: string;\n\ttraceId?: string;\n}\n\n// ============================================\n// Response Types\n// ============================================\n\nexport interface ExportTraceServiceResponse {\n\tpartialSuccess?: ExportTracePartialSuccess;\n}\n\nexport interface ExportTracePartialSuccess {\n\trejectedSpans?: string;\n\terrorMessage?: string;\n}\n\nexport interface ExportLogsServiceResponse {\n\tpartialSuccess?: ExportLogsPartialSuccess;\n}\n\nexport interface ExportLogsPartialSuccess {\n\trejectedLogRecords?: string;\n\terrorMessage?: string;\n}\n\nexport interface ExportMetricsServiceResponse {\n\tpartialSuccess?: ExportMetricsPartialSuccess;\n}\n\nexport interface ExportMetricsPartialSuccess {\n\trejectedDataPoints?: string;\n\terrorMessage?: string;\n}\n"],"mappings":";AAmGA,IAAY,WAAL,yBAAA,UAAA;CACN,SAAA,SAAA,2BAAA,KAAA;CACA,SAAA,SAAA,wBAAA,KAAA;CACA,SAAA,SAAA,sBAAA,KAAA;CACA,SAAA,SAAA,sBAAA,KAAA;CACA,SAAA,SAAA,wBAAA,KAAA;CACA,SAAA,SAAA,wBAAA,KAAA;;AACD,EAAA,CAAA,CAAA;AAuBA,IAAY,iBAAL,yBAAA,gBAAA;CACN,eAAA,eAAA,uBAAA,KAAA;CACA,eAAA,eAAA,oBAAA,KAAA;CACA,eAAA,eAAA,uBAAA,KAAA;;AACD,EAAA,CAAA,CAAA;AAsCA,IAAY,iBAAL,yBAAA,gBAAA;CACN,eAAA,eAAA,iCAAA,KAAA;CACA,eAAA,eAAA,2BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,2BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,4BAAA,KAAA;CACA,eAAA,eAAA,0BAAA,KAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,0BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;CACA,eAAA,eAAA,2BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;CACA,eAAA,eAAA,4BAAA,MAAA;;AACD,EAAA,CAAA,CAAA;AA6DA,IAAY,yBAAL,yBAAA,wBAAA;CACN,uBAAA,uBAAA,yCAAA,KAAA;CACA,uBAAA,uBAAA,mCAAA,KAAA;CACA,uBAAA,uBAAA,wCAAA,KAAA;;AACD,EAAA,CAAA,CAAA"}
|
package/dist/redact.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"redact.cjs","names":["BASE_REDACT_PATHS","pinoRedact"],"sources":["../src/redact.ts"],"sourcesContent":["import { DEFAULT_REDACT_PATHS as BASE_REDACT_PATHS } from '@geekmidas/logger/redact';\nimport pinoRedact from '@pinojs/redact';\nimport type { TelescopeRedactOptions } from './types';\n\n/**\n * Telescope-specific redaction paths for HTTP request/response data.\n * These extend the base paths from @geekmidas/logger.\n */\nconst TELESCOPE_SPECIFIC_PATHS: string[] = [\n\t// Response headers (telescope-specific)\n\t'responseHeaders.set-cookie',\n\t'responseHeaders.Set-Cookie',\n\n\t// Request body fields\n\t'body.password',\n\t'body.token',\n\t'body.accessToken',\n\t'body.refreshToken',\n\t'body.apiKey',\n\t'body.secret',\n\t'body.creditCard',\n\t'body.cardNumber',\n\t'body.cvv',\n\t'body.ssn',\n\n\t// Nested body patterns (wildcards)\n\t'body.*.password',\n\t'body.*.token',\n\t'body.*.secret',\n\t'body.*.apiKey',\n\n\t// Response body fields\n\t'responseBody.password',\n\t'responseBody.token',\n\t'responseBody.accessToken',\n\t'responseBody.refreshToken',\n\t'responseBody.secret',\n\t'responseBody.*.password',\n\t'responseBody.*.token',\n\t'responseBody.*.secret',\n\n\t// Query parameters\n\t'query.token',\n\t'query.api_key',\n\t'query.apiKey',\n\t'query.access_token',\n\t'query.secret',\n\n\t// Log context patterns\n\t'context.password',\n\t'context.token',\n\t'context.secret',\n\t'context.apiKey',\n\t'context.*.password',\n\t'context.*.token',\n\t'context.*.secret',\n];\n\n/**\n * Combined default paths for Telescope redaction.\n * Includes base paths from @geekmidas/logger plus telescope-specific HTTP paths.\n */\nexport const DEFAULT_REDACT_PATHS: string[] = [\n\t...BASE_REDACT_PATHS,\n\t...TELESCOPE_SPECIFIC_PATHS,\n];\n\n/**\n * Type for the redactor function returned by @pinojs/redact\n */\nexport type Redactor = <T>(obj: T) => T;\n\n/**\n * Creates a redactor function based on the provided options.\n *\n * @param options - Redaction configuration\n * @returns A redactor function, or undefined if redaction is disabled\n *\n * @example\n * const redactor = createRedactor(true);\n * const safe = redactor({ headers: { authorization: 'Bearer secret' } });\n * // safe.headers.authorization === '[REDACTED]'\n */\nexport function createRedactor(\n\toptions: TelescopeRedactOptions | undefined,\n): Redactor | undefined {\n\tif (options === undefined || options === false) {\n\t\treturn undefined;\n\t}\n\n\tlet paths: string[];\n\tlet censor: string = '[REDACTED]';\n\n\tif (options === true) {\n\t\t// Use defaults only\n\t\tpaths = DEFAULT_REDACT_PATHS;\n\t} else if (Array.isArray(options)) {\n\t\t// Merge custom paths with defaults\n\t\tpaths = [...DEFAULT_REDACT_PATHS, ...options];\n\t} else {\n\t\t// Object configuration\n\t\tpaths = [...DEFAULT_REDACT_PATHS, ...options.paths];\n\t\tif (options.censor !== undefined) {\n\t\t\tcensor = options.censor;\n\t\t}\n\t}\n\n\t// Create the redactor with serialize: false to return objects\n\tconst redact = pinoRedact({\n\t\tpaths,\n\t\tcensor,\n\t\tserialize: false,\n\t});\n\n\treturn redact as Redactor;\n}\n"],"mappings":";;;;;;;;;;AAQA,MAAM,2BAAqC;CAE1C;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;;;;;AAMA,MAAa,uBAAiC,CAC7C,GAAGA,yBAAAA,sBACH,GAAG,wBACJ;;;;;;;;;;;;AAkBA,SAAgB,eACf,SACuB;CACvB,IAAI,YAAY,KAAA,KAAa,YAAY,OACxC;CAGD,IAAI;CACJ,IAAI,SAAiB;CAErB,IAAI,YAAY,MAEf,QAAQ;MACF,IAAI,MAAM,QAAQ,OAAO,GAE/B,QAAQ,CAAC,GAAG,sBAAsB,GAAG,OAAO;MACtC;EAEN,QAAQ,CAAC,GAAG,sBAAsB,GAAG,QAAQ,KAAK;EAClD,IAAI,QAAQ,WAAW,KAAA,GACtB,SAAS,QAAQ;CAEnB;CASA,QAAA,GANeC,eAAAA,QAAAA,CAAW;EACzB;EACA;EACA,WAAW;CACZ,CAEY;AACb"}
|
package/dist/redact.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"redact.mjs","names":["BASE_REDACT_PATHS"],"sources":["../src/redact.ts"],"sourcesContent":["import { DEFAULT_REDACT_PATHS as BASE_REDACT_PATHS } from '@geekmidas/logger/redact';\nimport pinoRedact from '@pinojs/redact';\nimport type { TelescopeRedactOptions } from './types';\n\n/**\n * Telescope-specific redaction paths for HTTP request/response data.\n * These extend the base paths from @geekmidas/logger.\n */\nconst TELESCOPE_SPECIFIC_PATHS: string[] = [\n\t// Response headers (telescope-specific)\n\t'responseHeaders.set-cookie',\n\t'responseHeaders.Set-Cookie',\n\n\t// Request body fields\n\t'body.password',\n\t'body.token',\n\t'body.accessToken',\n\t'body.refreshToken',\n\t'body.apiKey',\n\t'body.secret',\n\t'body.creditCard',\n\t'body.cardNumber',\n\t'body.cvv',\n\t'body.ssn',\n\n\t// Nested body patterns (wildcards)\n\t'body.*.password',\n\t'body.*.token',\n\t'body.*.secret',\n\t'body.*.apiKey',\n\n\t// Response body fields\n\t'responseBody.password',\n\t'responseBody.token',\n\t'responseBody.accessToken',\n\t'responseBody.refreshToken',\n\t'responseBody.secret',\n\t'responseBody.*.password',\n\t'responseBody.*.token',\n\t'responseBody.*.secret',\n\n\t// Query parameters\n\t'query.token',\n\t'query.api_key',\n\t'query.apiKey',\n\t'query.access_token',\n\t'query.secret',\n\n\t// Log context patterns\n\t'context.password',\n\t'context.token',\n\t'context.secret',\n\t'context.apiKey',\n\t'context.*.password',\n\t'context.*.token',\n\t'context.*.secret',\n];\n\n/**\n * Combined default paths for Telescope redaction.\n * Includes base paths from @geekmidas/logger plus telescope-specific HTTP paths.\n */\nexport const DEFAULT_REDACT_PATHS: string[] = [\n\t...BASE_REDACT_PATHS,\n\t...TELESCOPE_SPECIFIC_PATHS,\n];\n\n/**\n * Type for the redactor function returned by @pinojs/redact\n */\nexport type Redactor = <T>(obj: T) => T;\n\n/**\n * Creates a redactor function based on the provided options.\n *\n * @param options - Redaction configuration\n * @returns A redactor function, or undefined if redaction is disabled\n *\n * @example\n * const redactor = createRedactor(true);\n * const safe = redactor({ headers: { authorization: 'Bearer secret' } });\n * // safe.headers.authorization === '[REDACTED]'\n */\nexport function createRedactor(\n\toptions: TelescopeRedactOptions | undefined,\n): Redactor | undefined {\n\tif (options === undefined || options === false) {\n\t\treturn undefined;\n\t}\n\n\tlet paths: string[];\n\tlet censor: string = '[REDACTED]';\n\n\tif (options === true) {\n\t\t// Use defaults only\n\t\tpaths = DEFAULT_REDACT_PATHS;\n\t} else if (Array.isArray(options)) {\n\t\t// Merge custom paths with defaults\n\t\tpaths = [...DEFAULT_REDACT_PATHS, ...options];\n\t} else {\n\t\t// Object configuration\n\t\tpaths = [...DEFAULT_REDACT_PATHS, ...options.paths];\n\t\tif (options.censor !== undefined) {\n\t\t\tcensor = options.censor;\n\t\t}\n\t}\n\n\t// Create the redactor with serialize: false to return objects\n\tconst redact = pinoRedact({\n\t\tpaths,\n\t\tcensor,\n\t\tserialize: false,\n\t});\n\n\treturn redact as Redactor;\n}\n"],"mappings":";;;;;;;AAQA,MAAM,2BAAqC;CAE1C;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;;;;;AAMA,MAAa,uBAAiC,CAC7C,GAAGA,wBACH,GAAG,wBACJ;;;;;;;;;;;;AAkBA,SAAgB,eACf,SACuB;CACvB,IAAI,YAAY,KAAA,KAAa,YAAY,OACxC;CAGD,IAAI;CACJ,IAAI,SAAiB;CAErB,IAAI,YAAY,MAEf,QAAQ;MACF,IAAI,MAAM,QAAQ,OAAO,GAE/B,QAAQ,CAAC,GAAG,sBAAsB,GAAG,OAAO;MACtC;EAEN,QAAQ,CAAC,GAAG,sBAAsB,GAAG,QAAQ,KAAK;EAClD,IAAI,QAAQ,WAAW,KAAA,GACtB,SAAS,QAAQ;CAEnB;CASA,OANe,WAAW;EACzB;EACA;EACA,WAAW;CACZ,CAEY;AACb"}
|