@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.
Files changed (480) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/README.md +18 -28
  3. package/dist/InMemoryMetricsStorage-BbKCL3YL.d.mts +47 -0
  4. package/dist/InMemoryMetricsStorage-BbKCL3YL.d.mts.map +1 -0
  5. package/dist/InMemoryMetricsStorage-C4drxT7G.mjs +247 -0
  6. package/dist/InMemoryMetricsStorage-C4drxT7G.mjs.map +1 -0
  7. package/dist/InMemoryMetricsStorage-D0njWUSi.cjs +252 -0
  8. package/dist/InMemoryMetricsStorage-D0njWUSi.cjs.map +1 -0
  9. package/dist/InMemoryMetricsStorage-TvPdZjL0.d.cts +47 -0
  10. package/dist/InMemoryMetricsStorage-TvPdZjL0.d.cts.map +1 -0
  11. package/dist/{MetricsAggregator-BJdIvfEv.d.mts → MetricsAggregator-4SqelGcG.d.cts} +6 -3
  12. package/dist/MetricsAggregator-4SqelGcG.d.cts.map +1 -0
  13. package/dist/MetricsAggregator-B7lUICdH.cjs +363 -0
  14. package/dist/MetricsAggregator-B7lUICdH.cjs.map +1 -0
  15. package/dist/{MetricsAggregator-CnC3oT5q.d.cts → MetricsAggregator-DZrW8ls6.d.mts} +6 -3
  16. package/dist/MetricsAggregator-DZrW8ls6.d.mts.map +1 -0
  17. package/dist/MetricsAggregator-S3DQWNas.mjs +357 -0
  18. package/dist/MetricsAggregator-S3DQWNas.mjs.map +1 -0
  19. package/dist/MetricsStorage-B86e4131.d.cts +60 -0
  20. package/dist/MetricsStorage-B86e4131.d.cts.map +1 -0
  21. package/dist/MetricsStorage-BWyP2_12.d.mts +60 -0
  22. package/dist/MetricsStorage-BWyP2_12.d.mts.map +1 -0
  23. package/dist/MetricsStorage-BypQXWiv.mjs +0 -0
  24. package/dist/MetricsStorage-Or8pVCe4.cjs +0 -0
  25. package/dist/Telescope-Cs3fv8jt.cjs +395 -0
  26. package/dist/Telescope-Cs3fv8jt.cjs.map +1 -0
  27. package/dist/{Telescope-BVfDvVvY.d.mts → Telescope-D4nmwDRA.d.cts} +7 -4
  28. package/dist/Telescope-D4nmwDRA.d.cts.map +1 -0
  29. package/dist/Telescope-Dh5av3FC.mjs +389 -0
  30. package/dist/Telescope-Dh5av3FC.mjs.map +1 -0
  31. package/dist/{Telescope-DeqSHfuB.d.cts → Telescope-Dl6VSfxd.d.mts} +7 -4
  32. package/dist/Telescope-Dl6VSfxd.d.mts.map +1 -0
  33. package/dist/Telescope.cjs +4 -385
  34. package/dist/Telescope.d.cts +3 -1
  35. package/dist/Telescope.d.mts +3 -1
  36. package/dist/Telescope.mjs +4 -384
  37. package/dist/adapters/index.d.cts +2 -2
  38. package/dist/adapters/index.d.mts +2 -2
  39. package/dist/adapters/index.mjs +0 -1
  40. package/dist/adapters/lambda.cjs +10 -9
  41. package/dist/adapters/lambda.cjs.map +1 -1
  42. package/dist/adapters/lambda.d.cts +13 -9
  43. package/dist/adapters/lambda.d.cts.map +1 -1
  44. package/dist/adapters/lambda.d.mts +13 -9
  45. package/dist/adapters/lambda.d.mts.map +1 -1
  46. package/dist/adapters/lambda.mjs +4 -3
  47. package/dist/adapters/lambda.mjs.map +1 -1
  48. package/dist/adapters/middy.cjs +4 -236
  49. package/dist/adapters/middy.d.cts +5 -60
  50. package/dist/adapters/middy.d.mts +5 -60
  51. package/dist/adapters/middy.mjs +3 -234
  52. package/dist/adapters/types.d.cts +2 -162
  53. package/dist/adapters/types.d.mts +2 -162
  54. package/dist/adapters/types.mjs +0 -1
  55. package/dist/{rolldown-runtime-VH7oDXx4.cjs → chunk-CUT6urMc.cjs} +10 -8
  56. package/dist/core--quSp5Qr.d.mts +78 -0
  57. package/dist/core--quSp5Qr.d.mts.map +1 -0
  58. package/dist/core-B4Jpia5H.d.cts +78 -0
  59. package/dist/core-B4Jpia5H.d.cts.map +1 -0
  60. package/dist/core-CtVHRJGv.cjs +199 -0
  61. package/dist/core-CtVHRJGv.cjs.map +1 -0
  62. package/dist/core-D6hJ6exL.mjs +139 -0
  63. package/dist/core-D6hJ6exL.mjs.map +1 -0
  64. package/dist/core.cjs +22 -22
  65. package/dist/core.d.cts +4 -4
  66. package/dist/core.d.mts +4 -4
  67. package/dist/core.mjs +4 -3
  68. package/dist/hono--uKQ7Jgi.d.mts +71 -0
  69. package/dist/hono--uKQ7Jgi.d.mts.map +1 -0
  70. package/dist/hono-C4EgpbKQ.cjs +160 -0
  71. package/dist/hono-C4EgpbKQ.cjs.map +1 -0
  72. package/dist/hono-CemCKU87.d.cts +71 -0
  73. package/dist/hono-CemCKU87.d.cts.map +1 -0
  74. package/dist/hono-DxhvnVbF.mjs +136 -0
  75. package/dist/hono-DxhvnVbF.mjs.map +1 -0
  76. package/dist/http-BiNtg85L.d.mts +107 -0
  77. package/dist/http-BiNtg85L.d.mts.map +1 -0
  78. package/dist/http-DQzgLczm.mjs +159 -0
  79. package/dist/http-DQzgLczm.mjs.map +1 -0
  80. package/dist/http-D_Z8sYXZ.cjs +219 -0
  81. package/dist/http-D_Z8sYXZ.cjs.map +1 -0
  82. package/dist/http-Dvca6fC3.d.cts +107 -0
  83. package/dist/http-Dvca6fC3.d.cts.map +1 -0
  84. package/dist/index-BL32-cvv.d.cts +1 -0
  85. package/dist/index-CsuikFeJ.d.mts +1 -0
  86. package/dist/index.cjs +9 -8
  87. package/dist/index.d.cts +6 -5
  88. package/dist/index.d.mts +6 -5
  89. package/dist/index.mjs +7 -5
  90. package/dist/instrumentation/core.cjs +11 -147
  91. package/dist/instrumentation/core.d.cts +3 -74
  92. package/dist/instrumentation/core.d.mts +3 -74
  93. package/dist/instrumentation/core.mjs +2 -137
  94. package/dist/instrumentation/hono.cjs +6 -174
  95. package/dist/instrumentation/hono.d.cts +2 -86
  96. package/dist/instrumentation/hono.d.mts +2 -86
  97. package/dist/instrumentation/hono.mjs +3 -170
  98. package/dist/instrumentation/http.cjs +11 -189
  99. package/dist/instrumentation/http.d.cts +2 -119
  100. package/dist/instrumentation/http.d.mts +2 -119
  101. package/dist/instrumentation/http.mjs +2 -178
  102. package/dist/instrumentation/index.cjs +47 -56
  103. package/dist/instrumentation/index.d.cts +9 -11
  104. package/dist/instrumentation/index.d.mts +9 -11
  105. package/dist/instrumentation/index.mjs +9 -10
  106. package/dist/instrumentation/middleware.cjs +6 -164
  107. package/dist/instrumentation/middleware.d.cts +2 -83
  108. package/dist/instrumentation/middleware.d.mts +2 -83
  109. package/dist/instrumentation/middleware.mjs +3 -160
  110. package/dist/instrumentation/otel.cjs +3 -137
  111. package/dist/instrumentation/otel.d.cts +2 -97
  112. package/dist/instrumentation/otel.d.mts +2 -97
  113. package/dist/instrumentation/otel.mjs +3 -136
  114. package/dist/instrumentation/setup.cjs +4 -142
  115. package/dist/instrumentation/setup.d.cts +3 -139
  116. package/dist/instrumentation/setup.d.mts +3 -139
  117. package/dist/instrumentation/setup.mjs +3 -139
  118. package/dist/instrumentation/tracing.cjs +10 -114
  119. package/dist/instrumentation/tracing.d.cts +2 -49
  120. package/dist/instrumentation/tracing.d.mts +2 -49
  121. package/dist/instrumentation/tracing.mjs +2 -105
  122. package/dist/logger/console.cjs +12 -18
  123. package/dist/logger/console.cjs.map +1 -1
  124. package/dist/logger/console.d.cts +10 -7
  125. package/dist/logger/console.d.cts.map +1 -1
  126. package/dist/logger/console.d.mts +10 -7
  127. package/dist/logger/console.d.mts.map +1 -1
  128. package/dist/logger/console.mjs +11 -17
  129. package/dist/logger/console.mjs.map +1 -1
  130. package/dist/logger/pino.cjs +5 -6
  131. package/dist/logger/pino.cjs.map +1 -1
  132. package/dist/logger/pino.d.cts +10 -6
  133. package/dist/logger/pino.d.cts.map +1 -1
  134. package/dist/logger/pino.d.mts +10 -6
  135. package/dist/logger/pino.d.mts.map +1 -1
  136. package/dist/logger/pino.mjs +3 -2
  137. package/dist/logger/pino.mjs.map +1 -1
  138. package/dist/memory--BK4iWiv.d.cts +40 -0
  139. package/dist/memory--BK4iWiv.d.cts.map +1 -0
  140. package/dist/memory-6S9H-IF5.mjs +123 -0
  141. package/dist/memory-6S9H-IF5.mjs.map +1 -0
  142. package/dist/memory-B0d_n1g5.cjs +129 -0
  143. package/dist/memory-B0d_n1g5.cjs.map +1 -0
  144. package/dist/memory-DCirEVFW.d.mts +40 -0
  145. package/dist/memory-DCirEVFW.d.mts.map +1 -0
  146. package/dist/metrics/MetricsAggregator.cjs +2 -354
  147. package/dist/metrics/MetricsAggregator.d.cts +2 -1
  148. package/dist/metrics/MetricsAggregator.d.mts +2 -1
  149. package/dist/metrics/MetricsAggregator.mjs +2 -353
  150. package/dist/metrics/index.cjs +4 -3
  151. package/dist/metrics/index.d.cts +4 -2
  152. package/dist/metrics/index.d.mts +4 -2
  153. package/dist/metrics/index.mjs +4 -2
  154. package/dist/metrics/storage/InMemoryMetricsStorage.cjs +3 -240
  155. package/dist/metrics/storage/InMemoryMetricsStorage.d.cts +4 -43
  156. package/dist/metrics/storage/InMemoryMetricsStorage.d.mts +4 -43
  157. package/dist/metrics/storage/InMemoryMetricsStorage.mjs +3 -239
  158. package/dist/metrics/storage/MetricsStorage.cjs +1 -0
  159. package/dist/metrics/storage/MetricsStorage.d.cts +3 -56
  160. package/dist/metrics/storage/MetricsStorage.d.mts +3 -56
  161. package/dist/metrics/storage/MetricsStorage.mjs +1 -1
  162. package/dist/metrics/storage/index.cjs +6 -6
  163. package/dist/metrics/storage/index.d.cts +3 -3
  164. package/dist/metrics/storage/index.d.mts +3 -3
  165. package/dist/metrics/storage/index.mjs +5 -4
  166. package/dist/metrics/storage/types.cjs +2 -34
  167. package/dist/metrics/storage/types.d.cts +2 -207
  168. package/dist/metrics/storage/types.d.mts +2 -207
  169. package/dist/metrics/storage/types.mjs +2 -33
  170. package/dist/metrics-D5YT-Rnq.mjs +0 -0
  171. package/dist/metrics-fhD3l3C3.cjs +0 -0
  172. package/dist/middleware-B2jFUukM.cjs +184 -0
  173. package/dist/middleware-B2jFUukM.cjs.map +1 -0
  174. package/dist/middleware-BTDncHwm.mjs +160 -0
  175. package/dist/middleware-BTDncHwm.mjs.map +1 -0
  176. package/dist/middleware-CA84nsNN.d.cts +74 -0
  177. package/dist/middleware-CA84nsNN.d.cts.map +1 -0
  178. package/dist/middleware-DAceVpfw.d.mts +74 -0
  179. package/dist/middleware-DAceVpfw.d.mts.map +1 -0
  180. package/dist/middy-B6Btl8XE.d.mts +64 -0
  181. package/dist/middy-B6Btl8XE.d.mts.map +1 -0
  182. package/dist/middy-BTR3cyvk.mjs +236 -0
  183. package/dist/middy-BTR3cyvk.mjs.map +1 -0
  184. package/dist/middy-Bq0defVg.d.cts +64 -0
  185. package/dist/middy-Bq0defVg.d.cts.map +1 -0
  186. package/dist/middy-y5Zp27eG.cjs +247 -0
  187. package/dist/middy-y5Zp27eG.cjs.map +1 -0
  188. package/dist/otel-1bJPb2Z7.d.mts +101 -0
  189. package/dist/otel-1bJPb2Z7.d.mts.map +1 -0
  190. package/dist/otel-C1HqHA2O.cjs +136 -0
  191. package/dist/otel-C1HqHA2O.cjs.map +1 -0
  192. package/dist/otel-SBVoVEHr.d.cts +101 -0
  193. package/dist/otel-SBVoVEHr.d.cts.map +1 -0
  194. package/dist/otel-wulj5B-X.mjs +130 -0
  195. package/dist/otel-wulj5B-X.mjs.map +1 -0
  196. package/dist/otlp/hono.cjs +15 -9
  197. package/dist/otlp/hono.cjs.map +1 -1
  198. package/dist/otlp/hono.d.cts +13 -3
  199. package/dist/otlp/hono.d.cts.map +1 -1
  200. package/dist/otlp/hono.d.mts +13 -3
  201. package/dist/otlp/hono.d.mts.map +1 -1
  202. package/dist/otlp/hono.mjs +11 -5
  203. package/dist/otlp/hono.mjs.map +1 -1
  204. package/dist/otlp/index.cjs +11 -11
  205. package/dist/otlp/index.d.cts +7 -4
  206. package/dist/otlp/index.d.mts +7 -4
  207. package/dist/otlp/index.mjs +5 -4
  208. package/dist/otlp/receiver.cjs +4 -88
  209. package/dist/otlp/receiver.d.cts +7 -59
  210. package/dist/otlp/receiver.d.mts +7 -59
  211. package/dist/otlp/receiver.mjs +4 -87
  212. package/dist/otlp/transformer.cjs +5 -214
  213. package/dist/otlp/transformer.d.cts +3 -1
  214. package/dist/otlp/transformer.d.mts +3 -1
  215. package/dist/otlp/transformer.mjs +3 -211
  216. package/dist/otlp/types.cjs +5 -57
  217. package/dist/otlp/types.d.cts +1 -1
  218. package/dist/otlp/types.d.mts +1 -1
  219. package/dist/otlp/types.mjs +2 -53
  220. package/dist/receiver-Cj1lbAOO.cjs +94 -0
  221. package/dist/receiver-Cj1lbAOO.cjs.map +1 -0
  222. package/dist/receiver-CxVd_9CB.mjs +89 -0
  223. package/dist/receiver-CxVd_9CB.mjs.map +1 -0
  224. package/dist/receiver-DLICx5uU.d.cts +63 -0
  225. package/dist/receiver-DLICx5uU.d.cts.map +1 -0
  226. package/dist/receiver-UeZT-H8u.d.mts +63 -0
  227. package/dist/receiver-UeZT-H8u.d.mts.map +1 -0
  228. package/dist/redact-BzkITCNW.mjs +83 -0
  229. package/dist/redact-BzkITCNW.mjs.map +1 -0
  230. package/dist/redact-DVaSSPZT.cjs +95 -0
  231. package/dist/redact-DVaSSPZT.cjs.map +1 -0
  232. package/dist/redact.cjs +3 -84
  233. package/dist/redact.d.cts +8 -4
  234. package/dist/redact.d.cts.map +1 -1
  235. package/dist/redact.d.mts +8 -4
  236. package/dist/redact.d.mts.map +1 -1
  237. package/dist/redact.mjs +2 -80
  238. package/dist/server/hono.cjs +54 -33
  239. package/dist/server/hono.cjs.map +1 -1
  240. package/dist/server/hono.d.cts +14 -19
  241. package/dist/server/hono.d.cts.map +1 -1
  242. package/dist/server/hono.d.mts +14 -19
  243. package/dist/server/hono.d.mts.map +1 -1
  244. package/dist/server/hono.mjs +52 -31
  245. package/dist/server/hono.mjs.map +1 -1
  246. package/dist/setup-B9jM77Qk.mjs +98 -0
  247. package/dist/setup-B9jM77Qk.mjs.map +1 -0
  248. package/dist/setup-Bkxm4g6b.d.mts +87 -0
  249. package/dist/setup-Bkxm4g6b.d.mts.map +1 -0
  250. package/dist/setup-CYpff5B9.cjs +110 -0
  251. package/dist/setup-CYpff5B9.cjs.map +1 -0
  252. package/dist/setup-D58N1f9O.d.cts +87 -0
  253. package/dist/setup-D58N1f9O.d.cts.map +1 -0
  254. package/dist/storage/kysely.cjs +70 -82
  255. package/dist/storage/kysely.cjs.map +1 -1
  256. package/dist/storage/kysely.d.cts +20 -36
  257. package/dist/storage/kysely.d.cts.map +1 -1
  258. package/dist/storage/kysely.d.mts +20 -36
  259. package/dist/storage/kysely.d.mts.map +1 -1
  260. package/dist/storage/kysely.mjs +69 -81
  261. package/dist/storage/kysely.mjs.map +1 -1
  262. package/dist/storage/memory.cjs +2 -122
  263. package/dist/storage/memory.d.cts +3 -36
  264. package/dist/storage/memory.d.mts +3 -36
  265. package/dist/storage/memory.mjs +2 -121
  266. package/dist/tracing-BX8uY2nR.d.cts +53 -0
  267. package/dist/tracing-BX8uY2nR.d.cts.map +1 -0
  268. package/dist/tracing-Bt1zWRlb.cjs +167 -0
  269. package/dist/tracing-Bt1zWRlb.cjs.map +1 -0
  270. package/dist/tracing-Cijm_5NI.mjs +113 -0
  271. package/dist/tracing-Cijm_5NI.mjs.map +1 -0
  272. package/dist/tracing-PnECEbEu.d.mts +53 -0
  273. package/dist/tracing-PnECEbEu.d.mts.map +1 -0
  274. package/dist/transformer-BXQPhzql.mjs +215 -0
  275. package/dist/transformer-BXQPhzql.mjs.map +1 -0
  276. package/dist/transformer-CLGZ0EQc.cjs +232 -0
  277. package/dist/transformer-CLGZ0EQc.cjs.map +1 -0
  278. package/dist/{transformer-BtqjAs0b.d.cts → transformer-CTGsaVfV.d.mts} +8 -4
  279. package/dist/transformer-CTGsaVfV.d.mts.map +1 -0
  280. package/dist/{transformer-DI6t8-YA.d.mts → transformer-ICEbxpFf.d.cts} +8 -4
  281. package/dist/transformer-ICEbxpFf.d.cts.map +1 -0
  282. package/dist/{types-BVujq4zd.d.mts → types-B1EIa_cQ.d.mts} +4 -3
  283. package/dist/types-B1EIa_cQ.d.mts.map +1 -0
  284. package/dist/types-BRzW1NM8.d.cts +166 -0
  285. package/dist/types-BRzW1NM8.d.cts.map +1 -0
  286. package/dist/types-BS3Rx8Sk.d.cts +209 -0
  287. package/dist/types-BS3Rx8Sk.d.cts.map +1 -0
  288. package/dist/types-Bwm_jNU7.mjs +54 -0
  289. package/dist/types-Bwm_jNU7.mjs.map +1 -0
  290. package/dist/types-BzQ78Efw.d.mts +166 -0
  291. package/dist/types-BzQ78Efw.d.mts.map +1 -0
  292. package/dist/types-CbNGXnJE.d.mts +209 -0
  293. package/dist/types-CbNGXnJE.d.mts.map +1 -0
  294. package/dist/{types-DVETVdpa.d.cts → types-CmOB7CLO.d.cts} +7 -6
  295. package/dist/types-CmOB7CLO.d.cts.map +1 -0
  296. package/dist/{types-DVETVdpa.d.mts → types-DBc0q5KD.d.mts} +7 -6
  297. package/dist/types-DBc0q5KD.d.mts.map +1 -0
  298. package/dist/types-Dsh-DIO_.cjs +78 -0
  299. package/dist/types-Dsh-DIO_.cjs.map +1 -0
  300. package/dist/types-ZW-nfWf6.cjs +40 -0
  301. package/dist/types-ZW-nfWf6.cjs.map +1 -0
  302. package/dist/{types-BVujq4zd.d.cts → types-l7Rlb5Mg.d.cts} +4 -3
  303. package/dist/types-l7Rlb5Mg.d.cts.map +1 -0
  304. package/dist/types-ojhnLdwz.mjs +34 -0
  305. package/dist/types-ojhnLdwz.mjs.map +1 -0
  306. package/dist/types.d.cts +1 -1
  307. package/dist/types.d.mts +1 -1
  308. package/dist/types.mjs +0 -1
  309. package/dist/ui-assets-BEXqOQLe.cjs +48 -0
  310. package/dist/ui-assets-BEXqOQLe.cjs.map +1 -0
  311. package/dist/ui-assets-BhTDUsrM.mjs +30 -0
  312. package/dist/ui-assets-BhTDUsrM.mjs.map +1 -0
  313. package/dist/ui-assets.cjs +5 -0
  314. package/dist/ui-assets.d.cts +13 -0
  315. package/dist/ui-assets.d.cts.map +1 -0
  316. package/dist/ui-assets.d.mts +13 -0
  317. package/dist/ui-assets.d.mts.map +1 -0
  318. package/dist/ui-assets.mjs +3 -0
  319. package/package.json +46 -46
  320. package/src/Telescope.ts +561 -0
  321. package/src/__tests__/Telescope.spec.ts +438 -0
  322. package/src/__tests__/pino-transport.spec.ts +115 -0
  323. package/src/__tests__/redact.spec.ts +336 -0
  324. package/src/adapters/__tests__/lambda.spec.ts +318 -0
  325. package/src/adapters/__tests__/middy.spec.ts +741 -0
  326. package/src/adapters/index.ts +22 -0
  327. package/src/adapters/lambda.ts +432 -0
  328. package/src/adapters/middy.ts +402 -0
  329. package/src/adapters/types.ts +181 -0
  330. package/src/core.ts +51 -0
  331. package/src/index.ts +34 -0
  332. package/src/instrumentation/__tests__/core.spec.ts +248 -0
  333. package/src/instrumentation/__tests__/hono.spec.ts +348 -0
  334. package/src/instrumentation/__tests__/middleware.spec.ts +528 -0
  335. package/src/instrumentation/__tests__/otel.spec.ts +291 -0
  336. package/src/instrumentation/__tests__/tracing.spec.ts +208 -0
  337. package/src/instrumentation/core.ts +228 -0
  338. package/src/instrumentation/hono.ts +270 -0
  339. package/src/instrumentation/http.ts +306 -0
  340. package/src/instrumentation/index.ts +90 -0
  341. package/src/instrumentation/middleware.ts +297 -0
  342. package/src/instrumentation/otel.ts +271 -0
  343. package/src/instrumentation/setup.ts +246 -0
  344. package/src/instrumentation/tracing.ts +145 -0
  345. package/src/logger/__tests__/console.spec.ts +366 -0
  346. package/src/logger/__tests__/pino.spec.ts +217 -0
  347. package/src/logger/console.ts +230 -0
  348. package/src/logger/pino.ts +201 -0
  349. package/src/metrics/MetricsAggregator.ts +555 -0
  350. package/src/metrics/__tests__/MetricsAggregator.spec.ts +298 -0
  351. package/src/metrics/index.ts +2 -0
  352. package/src/metrics/storage/InMemoryMetricsStorage.ts +380 -0
  353. package/src/metrics/storage/MetricsStorage.ts +74 -0
  354. package/src/metrics/storage/index.ts +3 -0
  355. package/src/metrics/storage/types.ts +243 -0
  356. package/src/otlp/__tests__/receiver.spec.ts +367 -0
  357. package/src/otlp/__tests__/transformer.spec.ts +455 -0
  358. package/src/otlp/hono.ts +120 -0
  359. package/src/otlp/index.ts +22 -0
  360. package/src/otlp/receiver.ts +162 -0
  361. package/src/otlp/transformer.ts +367 -0
  362. package/src/otlp/types.ts +364 -0
  363. package/src/redact.ts +116 -0
  364. package/src/server/__tests__/hono.spec.ts +814 -0
  365. package/src/server/hono.ts +442 -0
  366. package/src/storage/__tests__/kysely.spec.ts +715 -0
  367. package/src/storage/__tests__/memory.spec.ts +694 -0
  368. package/src/storage/kysely.ts +599 -0
  369. package/src/storage/memory.ts +204 -0
  370. package/src/types.ts +447 -0
  371. package/src/ui-assets.ts +40 -0
  372. package/tsconfig.json +9 -0
  373. package/ui/CHANGELOG.md +7 -0
  374. package/ui/index.html +12 -0
  375. package/ui/node_modules/.bin/tsc +21 -0
  376. package/ui/node_modules/.bin/tsserver +21 -0
  377. package/ui/node_modules/.bin/vite +21 -0
  378. package/ui/package.json +24 -0
  379. package/ui/src/App.tsx +595 -0
  380. package/ui/src/api.ts +88 -0
  381. package/ui/src/components/ExceptionDetail.tsx +100 -0
  382. package/ui/src/components/FilterBar.tsx +162 -0
  383. package/ui/src/components/LogDetail.tsx +91 -0
  384. package/ui/src/components/RequestDetail.tsx +143 -0
  385. package/ui/src/main.tsx +10 -0
  386. package/ui/src/styles.css +11 -0
  387. package/ui/src/types.ts +63 -0
  388. package/ui/src/vite-env.d.ts +1 -0
  389. package/ui/src/vite-plugin-gkm-config.ts +54 -0
  390. package/ui/tsconfig.json +20 -0
  391. package/ui/tsconfig.tsbuildinfo +1 -0
  392. package/ui/vite.config.ts +13 -0
  393. package/dist/MetricsAggregator-BJdIvfEv.d.mts.map +0 -1
  394. package/dist/MetricsAggregator-CnC3oT5q.d.cts.map +0 -1
  395. package/dist/Telescope-BVfDvVvY.d.mts.map +0 -1
  396. package/dist/Telescope-DeqSHfuB.d.cts.map +0 -1
  397. package/dist/Telescope.cjs.map +0 -1
  398. package/dist/Telescope.mjs.map +0 -1
  399. package/dist/adapters/middy.cjs.map +0 -1
  400. package/dist/adapters/middy.d.cts.map +0 -1
  401. package/dist/adapters/middy.d.mts.map +0 -1
  402. package/dist/adapters/middy.mjs.map +0 -1
  403. package/dist/adapters/types.d.cts.map +0 -1
  404. package/dist/adapters/types.d.mts.map +0 -1
  405. package/dist/instrumentation/core.cjs.map +0 -1
  406. package/dist/instrumentation/core.d.cts.map +0 -1
  407. package/dist/instrumentation/core.d.mts.map +0 -1
  408. package/dist/instrumentation/core.mjs.map +0 -1
  409. package/dist/instrumentation/hono.cjs.map +0 -1
  410. package/dist/instrumentation/hono.d.cts.map +0 -1
  411. package/dist/instrumentation/hono.d.mts.map +0 -1
  412. package/dist/instrumentation/hono.mjs.map +0 -1
  413. package/dist/instrumentation/http.cjs.map +0 -1
  414. package/dist/instrumentation/http.d.cts.map +0 -1
  415. package/dist/instrumentation/http.d.mts.map +0 -1
  416. package/dist/instrumentation/http.mjs.map +0 -1
  417. package/dist/instrumentation/middleware.cjs.map +0 -1
  418. package/dist/instrumentation/middleware.d.cts.map +0 -1
  419. package/dist/instrumentation/middleware.d.mts.map +0 -1
  420. package/dist/instrumentation/middleware.mjs.map +0 -1
  421. package/dist/instrumentation/otel.cjs.map +0 -1
  422. package/dist/instrumentation/otel.d.cts.map +0 -1
  423. package/dist/instrumentation/otel.d.mts.map +0 -1
  424. package/dist/instrumentation/otel.mjs.map +0 -1
  425. package/dist/instrumentation/sampler.cjs +0 -54
  426. package/dist/instrumentation/sampler.cjs.map +0 -1
  427. package/dist/instrumentation/sampler.d.cts +0 -38
  428. package/dist/instrumentation/sampler.d.cts.map +0 -1
  429. package/dist/instrumentation/sampler.d.mts +0 -38
  430. package/dist/instrumentation/sampler.d.mts.map +0 -1
  431. package/dist/instrumentation/sampler.mjs +0 -52
  432. package/dist/instrumentation/sampler.mjs.map +0 -1
  433. package/dist/instrumentation/setup.cjs.map +0 -1
  434. package/dist/instrumentation/setup.d.cts.map +0 -1
  435. package/dist/instrumentation/setup.d.mts.map +0 -1
  436. package/dist/instrumentation/setup.mjs.map +0 -1
  437. package/dist/instrumentation/tracing.cjs.map +0 -1
  438. package/dist/instrumentation/tracing.d.cts.map +0 -1
  439. package/dist/instrumentation/tracing.d.mts.map +0 -1
  440. package/dist/instrumentation/tracing.mjs.map +0 -1
  441. package/dist/instrumentation/trust.cjs +0 -107
  442. package/dist/instrumentation/trust.cjs.map +0 -1
  443. package/dist/instrumentation/trust.d.cts +0 -57
  444. package/dist/instrumentation/trust.d.cts.map +0 -1
  445. package/dist/instrumentation/trust.d.mts +0 -57
  446. package/dist/instrumentation/trust.d.mts.map +0 -1
  447. package/dist/instrumentation/trust.mjs +0 -104
  448. package/dist/instrumentation/trust.mjs.map +0 -1
  449. package/dist/metrics/MetricsAggregator.cjs.map +0 -1
  450. package/dist/metrics/MetricsAggregator.mjs.map +0 -1
  451. package/dist/metrics/storage/InMemoryMetricsStorage.cjs.map +0 -1
  452. package/dist/metrics/storage/InMemoryMetricsStorage.d.cts.map +0 -1
  453. package/dist/metrics/storage/InMemoryMetricsStorage.d.mts.map +0 -1
  454. package/dist/metrics/storage/InMemoryMetricsStorage.mjs.map +0 -1
  455. package/dist/metrics/storage/MetricsStorage.d.cts.map +0 -1
  456. package/dist/metrics/storage/MetricsStorage.d.mts.map +0 -1
  457. package/dist/metrics/storage/types.cjs.map +0 -1
  458. package/dist/metrics/storage/types.d.cts.map +0 -1
  459. package/dist/metrics/storage/types.d.mts.map +0 -1
  460. package/dist/metrics/storage/types.mjs.map +0 -1
  461. package/dist/otlp/receiver.cjs.map +0 -1
  462. package/dist/otlp/receiver.d.cts.map +0 -1
  463. package/dist/otlp/receiver.d.mts.map +0 -1
  464. package/dist/otlp/receiver.mjs.map +0 -1
  465. package/dist/otlp/transformer.cjs.map +0 -1
  466. package/dist/otlp/transformer.mjs.map +0 -1
  467. package/dist/otlp/types.cjs.map +0 -1
  468. package/dist/otlp/types.mjs.map +0 -1
  469. package/dist/redact.cjs.map +0 -1
  470. package/dist/redact.mjs.map +0 -1
  471. package/dist/storage/memory.cjs.map +0 -1
  472. package/dist/storage/memory.d.cts.map +0 -1
  473. package/dist/storage/memory.d.mts.map +0 -1
  474. package/dist/storage/memory.mjs.map +0 -1
  475. package/dist/transformer-BtqjAs0b.d.cts.map +0 -1
  476. package/dist/transformer-DI6t8-YA.d.mts.map +0 -1
  477. package/dist/types-BVujq4zd.d.cts.map +0 -1
  478. package/dist/types-BVujq4zd.d.mts.map +0 -1
  479. package/dist/types-DVETVdpa.d.cts.map +0 -1
  480. package/dist/types-DVETVdpa.d.mts.map +0 -1
@@ -0,0 +1,298 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import type { RequestEntry } from '../../types';
3
+ import { MetricsAggregator } from '../MetricsAggregator';
4
+
5
+ function createRequest(overrides: Partial<RequestEntry> = {}): RequestEntry {
6
+ return {
7
+ id: `req-${Math.random().toString(36).slice(2)}`,
8
+ method: 'GET',
9
+ path: '/api/test',
10
+ url: 'http://localhost/api/test',
11
+ headers: {},
12
+ query: {},
13
+ status: 200,
14
+ responseHeaders: {},
15
+ duration: 50,
16
+ timestamp: new Date(),
17
+ ...overrides,
18
+ };
19
+ }
20
+
21
+ describe('MetricsAggregator', () => {
22
+ let aggregator: MetricsAggregator;
23
+
24
+ beforeEach(() => {
25
+ aggregator = new MetricsAggregator();
26
+ });
27
+
28
+ describe('record', () => {
29
+ it('should record a request', () => {
30
+ const request = createRequest();
31
+ aggregator.record(request);
32
+
33
+ const metrics = aggregator.getMetrics();
34
+ expect(metrics.totalRequests).toBe(1);
35
+ });
36
+
37
+ it('should aggregate multiple requests', () => {
38
+ aggregator.record(createRequest({ duration: 100 }));
39
+ aggregator.record(createRequest({ duration: 200 }));
40
+ aggregator.record(createRequest({ duration: 300 }));
41
+
42
+ const metrics = aggregator.getMetrics();
43
+ expect(metrics.totalRequests).toBe(3);
44
+ expect(metrics.avgDuration).toBe(200);
45
+ });
46
+
47
+ it('should track error requests', () => {
48
+ aggregator.record(createRequest({ status: 200 }));
49
+ aggregator.record(createRequest({ status: 404 }));
50
+ aggregator.record(createRequest({ status: 500 }));
51
+ aggregator.record(createRequest({ status: 200 }));
52
+
53
+ const metrics = aggregator.getMetrics();
54
+ expect(metrics.totalRequests).toBe(4);
55
+ expect(metrics.errorRate).toBe(50); // 2 out of 4
56
+ expect(metrics.successRate).toBe(50);
57
+ });
58
+ });
59
+
60
+ describe('getMetrics', () => {
61
+ it('should return empty metrics when no requests', () => {
62
+ const metrics = aggregator.getMetrics();
63
+
64
+ expect(metrics.totalRequests).toBe(0);
65
+ expect(metrics.avgDuration).toBe(0);
66
+ expect(metrics.p50Duration).toBe(0);
67
+ expect(metrics.p95Duration).toBe(0);
68
+ expect(metrics.p99Duration).toBe(0);
69
+ expect(metrics.errorRate).toBe(0);
70
+ expect(metrics.successRate).toBe(100);
71
+ expect(metrics.requestsPerSecond).toBe(0);
72
+ expect(metrics.timeSeries).toEqual([]);
73
+ });
74
+
75
+ it('should calculate percentiles correctly', () => {
76
+ // Add 100 requests with durations 1-100ms
77
+ for (let i = 1; i <= 100; i++) {
78
+ aggregator.record(createRequest({ duration: i }));
79
+ }
80
+
81
+ const metrics = aggregator.getMetrics();
82
+
83
+ // p50 should be around 50 (median of 1-100 is 50.5)
84
+ expect(metrics.p50Duration).toBeGreaterThanOrEqual(49);
85
+ expect(metrics.p50Duration).toBeLessThanOrEqual(52);
86
+ // p95 should be around 95
87
+ expect(metrics.p95Duration).toBeGreaterThanOrEqual(94);
88
+ expect(metrics.p95Duration).toBeLessThanOrEqual(96);
89
+ // p99 should be around 99
90
+ expect(metrics.p99Duration).toBeGreaterThanOrEqual(98);
91
+ expect(metrics.p99Duration).toBeLessThanOrEqual(100);
92
+ });
93
+
94
+ it('should calculate requests per second', () => {
95
+ // Record 10 requests
96
+ for (let i = 0; i < 10; i++) {
97
+ aggregator.record(createRequest());
98
+ }
99
+
100
+ // Use default range (last hour) - just verify it calculates something reasonable
101
+ const metrics = aggregator.getMetrics();
102
+
103
+ expect(metrics.totalRequests).toBe(10);
104
+ // With 10 requests in the default 1 hour range, rps should be small but positive
105
+ expect(metrics.requestsPerSecond).toBeGreaterThan(0);
106
+ });
107
+
108
+ it('should generate time series data', () => {
109
+ const now = new Date();
110
+ const bucketSize = 60000; // 1 minute
111
+
112
+ // Record requests in different buckets
113
+ aggregator.record(
114
+ createRequest({
115
+ timestamp: new Date(now.getTime() - 2 * bucketSize),
116
+ }),
117
+ );
118
+ aggregator.record(
119
+ createRequest({
120
+ timestamp: new Date(now.getTime() - bucketSize),
121
+ }),
122
+ );
123
+ aggregator.record(createRequest({ timestamp: now }));
124
+
125
+ const metrics = aggregator.getMetrics({
126
+ range: {
127
+ start: new Date(now.getTime() - 3 * bucketSize),
128
+ end: now,
129
+ },
130
+ });
131
+
132
+ expect(metrics.timeSeries.length).toBeGreaterThan(0);
133
+ });
134
+ });
135
+
136
+ describe('getEndpointMetrics', () => {
137
+ it('should track metrics per endpoint', () => {
138
+ aggregator.record(createRequest({ method: 'GET', path: '/users' }));
139
+ aggregator.record(createRequest({ method: 'GET', path: '/users' }));
140
+ aggregator.record(createRequest({ method: 'POST', path: '/users' }));
141
+ aggregator.record(createRequest({ method: 'GET', path: '/posts' }));
142
+
143
+ const endpoints = aggregator.getEndpointMetrics();
144
+
145
+ expect(endpoints.length).toBe(3);
146
+
147
+ const getUsersEndpoint = endpoints.find(
148
+ (e) => e.method === 'GET' && e.path === '/users',
149
+ );
150
+ expect(getUsersEndpoint?.count).toBe(2);
151
+
152
+ const postUsersEndpoint = endpoints.find(
153
+ (e) => e.method === 'POST' && e.path === '/users',
154
+ );
155
+ expect(postUsersEndpoint?.count).toBe(1);
156
+ });
157
+
158
+ it('should sort by request count descending', () => {
159
+ aggregator.record(createRequest({ path: '/a' }));
160
+ aggregator.record(createRequest({ path: '/b' }));
161
+ aggregator.record(createRequest({ path: '/b' }));
162
+ aggregator.record(createRequest({ path: '/c' }));
163
+ aggregator.record(createRequest({ path: '/c' }));
164
+ aggregator.record(createRequest({ path: '/c' }));
165
+
166
+ const endpoints = aggregator.getEndpointMetrics();
167
+
168
+ expect(endpoints[0].path).toBe('/c');
169
+ expect(endpoints[0].count).toBe(3);
170
+ expect(endpoints[1].path).toBe('/b');
171
+ expect(endpoints[1].count).toBe(2);
172
+ expect(endpoints[2].path).toBe('/a');
173
+ expect(endpoints[2].count).toBe(1);
174
+ });
175
+
176
+ it('should respect limit option', () => {
177
+ for (let i = 0; i < 10; i++) {
178
+ aggregator.record(createRequest({ path: `/path-${i}` }));
179
+ }
180
+
181
+ const endpoints = aggregator.getEndpointMetrics({ limit: 5 });
182
+ expect(endpoints.length).toBe(5);
183
+ });
184
+
185
+ it('should calculate endpoint error rates', () => {
186
+ aggregator.record(createRequest({ path: '/error', status: 500 }));
187
+ aggregator.record(createRequest({ path: '/error', status: 500 }));
188
+ aggregator.record(createRequest({ path: '/error', status: 200 }));
189
+ aggregator.record(createRequest({ path: '/error', status: 200 }));
190
+
191
+ const endpoints = aggregator.getEndpointMetrics();
192
+ const errorEndpoint = endpoints.find((e) => e.path === '/error');
193
+
194
+ expect(errorEndpoint?.errorRate).toBe(50);
195
+ });
196
+ });
197
+
198
+ describe('getStatusDistribution', () => {
199
+ it('should count status codes by category', () => {
200
+ aggregator.record(createRequest({ status: 200 }));
201
+ aggregator.record(createRequest({ status: 201 }));
202
+ aggregator.record(createRequest({ status: 301 }));
203
+ aggregator.record(createRequest({ status: 400 }));
204
+ aggregator.record(createRequest({ status: 404 }));
205
+ aggregator.record(createRequest({ status: 500 }));
206
+
207
+ const dist = aggregator.getStatusDistribution();
208
+
209
+ expect(dist['2xx']).toBe(2);
210
+ expect(dist['3xx']).toBe(1);
211
+ expect(dist['4xx']).toBe(2);
212
+ expect(dist['5xx']).toBe(1);
213
+ });
214
+
215
+ it('should return zeros when no requests', () => {
216
+ const dist = aggregator.getStatusDistribution();
217
+
218
+ expect(dist['2xx']).toBe(0);
219
+ expect(dist['3xx']).toBe(0);
220
+ expect(dist['4xx']).toBe(0);
221
+ expect(dist['5xx']).toBe(0);
222
+ });
223
+ });
224
+
225
+ describe('reset', () => {
226
+ it('should clear all metrics', () => {
227
+ aggregator.record(createRequest());
228
+ aggregator.record(createRequest());
229
+ aggregator.record(createRequest());
230
+
231
+ expect(aggregator.getMetrics().totalRequests).toBe(3);
232
+
233
+ aggregator.reset();
234
+
235
+ expect(aggregator.getMetrics().totalRequests).toBe(0);
236
+ expect(aggregator.getEndpointMetrics().length).toBe(0);
237
+ });
238
+ });
239
+
240
+ describe('bucket pruning', () => {
241
+ it('should prune old buckets when maxBuckets exceeded', () => {
242
+ const aggregator = new MetricsAggregator({
243
+ bucketSize: 1000, // 1 second buckets
244
+ maxBuckets: 5,
245
+ });
246
+
247
+ // Add requests across 10 different seconds
248
+ const baseTime = Date.now();
249
+ for (let i = 0; i < 10; i++) {
250
+ aggregator.record(
251
+ createRequest({
252
+ timestamp: new Date(baseTime + i * 1000),
253
+ }),
254
+ );
255
+ }
256
+
257
+ // Query should only return data from the last 5 buckets
258
+ const metrics = aggregator.getMetrics({
259
+ range: {
260
+ start: new Date(baseTime),
261
+ end: new Date(baseTime + 10000),
262
+ },
263
+ });
264
+
265
+ // Should have at most 5 buckets worth of data
266
+ expect(metrics.totalRequests).toBeLessThanOrEqual(5);
267
+ });
268
+ });
269
+
270
+ describe('custom bucket size', () => {
271
+ it('should use custom bucket size', () => {
272
+ const aggregator = new MetricsAggregator({
273
+ bucketSize: 5000, // 5 second buckets
274
+ });
275
+
276
+ // Use a fixed timestamp to ensure all requests fall in the same bucket
277
+ const baseTime = Math.floor(Date.now() / 5000) * 5000; // Align to bucket boundary
278
+ const timestamp = new Date(baseTime);
279
+
280
+ // Add 3 requests within the same 5-second bucket
281
+ aggregator.record(createRequest({ timestamp }));
282
+ aggregator.record(createRequest({ timestamp }));
283
+ aggregator.record(createRequest({ timestamp }));
284
+
285
+ const metrics = aggregator.getMetrics({
286
+ range: {
287
+ start: new Date(baseTime - 1000),
288
+ end: new Date(baseTime + 6000),
289
+ },
290
+ bucketSize: 5000,
291
+ });
292
+
293
+ // Should have at least 1 time series point with 3 requests total
294
+ expect(metrics.totalRequests).toBe(3);
295
+ expect(metrics.timeSeries.length).toBeGreaterThanOrEqual(1);
296
+ });
297
+ });
298
+ });
@@ -0,0 +1,2 @@
1
+ export type { MetricsAggregatorOptions } from './MetricsAggregator';
2
+ export { MetricsAggregator } from './MetricsAggregator';
@@ -0,0 +1,380 @@
1
+ import type { MetricsStorage } from './MetricsStorage';
2
+ import {
3
+ type AggregationInterval,
4
+ DEFAULT_METRICS_CONFIG,
5
+ type MetricBucket,
6
+ type MetricLabels,
7
+ type MetricPoint,
8
+ type MetricQuery,
9
+ type MetricResult,
10
+ type MetricsStorageConfig,
11
+ type PartitionInfo,
12
+ type RollupOptions,
13
+ } from './types';
14
+
15
+ /**
16
+ * In-memory metrics storage for development and testing.
17
+ *
18
+ * Features:
19
+ * - Buffered writes with configurable flush interval
20
+ * - Time-bucketed aggregation
21
+ * - Basic percentile calculation (reservoir sampling)
22
+ * - Automatic pruning based on retention
23
+ *
24
+ * Not suitable for production - use a proper time-series database.
25
+ */
26
+ export class InMemoryMetricsStorage implements MetricsStorage {
27
+ private config: MetricsStorageConfig;
28
+ private buffer: MetricPoint[] = [];
29
+ private buckets: Map<string, MetricBucket> = new Map();
30
+ private samples: Map<string, number[]> = new Map(); // For percentile calculations
31
+ private flushTimer: ReturnType<typeof setInterval> | null = null;
32
+
33
+ constructor(config: Partial<MetricsStorageConfig> = {}) {
34
+ this.config = { ...DEFAULT_METRICS_CONFIG, ...config };
35
+
36
+ if (this.config.flushInterval > 0) {
37
+ this.flushTimer = setInterval(() => {
38
+ this.flush().catch(console.error);
39
+ }, this.config.flushInterval);
40
+ }
41
+ }
42
+
43
+ async write(points: MetricPoint[]): Promise<void> {
44
+ this.buffer.push(...points);
45
+
46
+ if (this.buffer.length >= this.config.maxBatchSize) {
47
+ await this.flush();
48
+ }
49
+ }
50
+
51
+ async flush(): Promise<void> {
52
+ if (this.buffer.length === 0) return;
53
+
54
+ const points = this.buffer.splice(0);
55
+
56
+ for (const point of points) {
57
+ this.aggregatePoint(point);
58
+ }
59
+
60
+ // Prune if auto-rollup is enabled
61
+ if (this.config.autoRollup) {
62
+ await this.prune();
63
+ }
64
+ }
65
+
66
+ private aggregatePoint(point: MetricPoint): void {
67
+ const bucketTime = this.getBucketTime(point.timestamp, '1m');
68
+ const key = this.getBucketKey(point, bucketTime);
69
+
70
+ const existing = this.buckets.get(key);
71
+
72
+ if (existing) {
73
+ existing.count += 1;
74
+ existing.sum += point.value;
75
+ existing.min = Math.min(existing.min, point.value);
76
+ existing.max = Math.max(existing.max, point.value);
77
+ } else {
78
+ this.buckets.set(key, {
79
+ bucket: bucketTime,
80
+ projectId: point.projectId,
81
+ service: point.service,
82
+ environment: point.environment,
83
+ name: point.name,
84
+ labelsHash: this.hashLabels(point.labels),
85
+ labels: { ...point.labels },
86
+ count: 1,
87
+ sum: point.value,
88
+ min: point.value,
89
+ max: point.value,
90
+ });
91
+ }
92
+
93
+ // Store samples for percentile calculations (reservoir sampling)
94
+ const sampleKey = `${point.projectId}:${point.name}:${bucketTime.getTime()}`;
95
+ const samples = this.samples.get(sampleKey) ?? [];
96
+ if (samples.length < 1000) {
97
+ samples.push(point.value);
98
+ } else {
99
+ // Reservoir sampling
100
+ const idx = Math.floor(Math.random() * (samples.length + 1));
101
+ if (idx < samples.length) {
102
+ samples[idx] = point.value;
103
+ }
104
+ }
105
+ this.samples.set(sampleKey, samples);
106
+ }
107
+
108
+ async query(query: MetricQuery): Promise<MetricResult[]> {
109
+ await this.flush();
110
+
111
+ const results = new Map<string, MetricResult>();
112
+ const startTime = query.range.start.getTime();
113
+ const endTime = query.range.end.getTime();
114
+ const interval = query.interval ?? '1m';
115
+ const intervalMs = this.getIntervalMs(interval);
116
+
117
+ for (const [, bucket] of this.buckets) {
118
+ if (bucket.projectId !== query.projectId) continue;
119
+ if (query.service && bucket.service !== query.service) continue;
120
+ if (query.environment && bucket.environment !== query.environment)
121
+ continue;
122
+ if (query.name && !this.matchesPattern(bucket.name, query.name)) continue;
123
+ if (query.labels && !this.matchesLabels(bucket.labels, query.labels))
124
+ continue;
125
+
126
+ const bucketTime = bucket.bucket.getTime();
127
+ if (bucketTime < startTime || bucketTime > endTime) continue;
128
+
129
+ // Group by metric name + labels
130
+ const groupKey = query.groupBy
131
+ ? this.getGroupKey(bucket, query.groupBy)
132
+ : bucket.name;
133
+
134
+ let result = results.get(groupKey);
135
+ if (!result) {
136
+ result = {
137
+ name: bucket.name,
138
+ labels: query.groupBy
139
+ ? this.filterLabels(bucket.labels, query.groupBy)
140
+ : bucket.labels,
141
+ timeSeries: [],
142
+ stats: {
143
+ count: 0,
144
+ sum: 0,
145
+ avg: 0,
146
+ min: Infinity,
147
+ max: -Infinity,
148
+ p50: 0,
149
+ p95: 0,
150
+ p99: 0,
151
+ },
152
+ };
153
+ results.set(groupKey, result);
154
+ }
155
+
156
+ // Aggregate into time series
157
+ const tsIndex = Math.floor((bucketTime - startTime) / intervalMs);
158
+ while (result.timeSeries.length <= tsIndex) {
159
+ result.timeSeries.push({
160
+ timestamp: new Date(
161
+ startTime + result.timeSeries.length * intervalMs,
162
+ ),
163
+ count: 0,
164
+ sum: 0,
165
+ avg: 0,
166
+ min: Infinity,
167
+ max: -Infinity,
168
+ });
169
+ }
170
+
171
+ const tsPoint = result.timeSeries[tsIndex];
172
+ if (tsPoint) {
173
+ tsPoint.count += bucket.count;
174
+ tsPoint.sum += bucket.sum;
175
+ tsPoint.min = Math.min(tsPoint.min, bucket.min);
176
+ tsPoint.max = Math.max(tsPoint.max, bucket.max);
177
+ tsPoint.avg = tsPoint.sum / tsPoint.count;
178
+ }
179
+
180
+ // Update overall stats
181
+ result.stats.count += bucket.count;
182
+ result.stats.sum += bucket.sum;
183
+ result.stats.min = Math.min(result.stats.min, bucket.min);
184
+ result.stats.max = Math.max(result.stats.max, bucket.max);
185
+ }
186
+
187
+ // Calculate percentiles and finalize
188
+ for (const result of results.values()) {
189
+ if (result.stats.count > 0) {
190
+ result.stats.avg = result.stats.sum / result.stats.count;
191
+
192
+ // Gather all samples for this result
193
+ const allSamples: number[] = [];
194
+ for (const [key, samples] of this.samples) {
195
+ if (key.startsWith(`${query.projectId}:${result.name}:`)) {
196
+ allSamples.push(...samples);
197
+ }
198
+ }
199
+
200
+ if (allSamples.length > 0) {
201
+ allSamples.sort((a, b) => a - b);
202
+ result.stats.p50 = this.percentile(allSamples, 50);
203
+ result.stats.p95 = this.percentile(allSamples, 95);
204
+ result.stats.p99 = this.percentile(allSamples, 99);
205
+ }
206
+ }
207
+
208
+ // Fix infinity values
209
+ if (result.stats.min === Infinity) result.stats.min = 0;
210
+ if (result.stats.max === -Infinity) result.stats.max = 0;
211
+
212
+ for (const point of result.timeSeries) {
213
+ if (point.min === Infinity) point.min = 0;
214
+ if (point.max === -Infinity) point.max = 0;
215
+ }
216
+ }
217
+
218
+ const resultArray = Array.from(results.values());
219
+
220
+ if (query.limit) {
221
+ return resultArray.slice(0, query.limit);
222
+ }
223
+
224
+ return resultArray;
225
+ }
226
+
227
+ async getBucket(
228
+ projectId: string,
229
+ name: string,
230
+ bucket: Date,
231
+ ): Promise<MetricBucket | null> {
232
+ await this.flush();
233
+
234
+ for (const [, b] of this.buckets) {
235
+ if (
236
+ b.projectId === projectId &&
237
+ b.name === name &&
238
+ b.bucket.getTime() === bucket.getTime()
239
+ ) {
240
+ return b;
241
+ }
242
+ }
243
+
244
+ return null;
245
+ }
246
+
247
+ async rollup(_options: RollupOptions): Promise<number> {
248
+ // In-memory storage doesn't need rollup - data is already aggregated
249
+ return 0;
250
+ }
251
+
252
+ async prune(): Promise<number> {
253
+ const now = Date.now();
254
+ let deleted = 0;
255
+
256
+ // Use the shortest retention from tiers
257
+ const retentionMs = Math.min(
258
+ ...this.config.tiers
259
+ .filter((t) => t.retention > 0)
260
+ .map((t) => t.retention),
261
+ );
262
+
263
+ if (retentionMs === Infinity) return 0;
264
+
265
+ const cutoff = now - retentionMs;
266
+
267
+ for (const [key, bucket] of this.buckets) {
268
+ if (bucket.bucket.getTime() < cutoff) {
269
+ this.buckets.delete(key);
270
+ deleted++;
271
+ }
272
+ }
273
+
274
+ // Also prune samples
275
+ for (const [key] of this.samples) {
276
+ const timestamp = parseInt(key.split(':').pop() ?? '0', 10);
277
+ if (timestamp < cutoff) {
278
+ this.samples.delete(key);
279
+ }
280
+ }
281
+
282
+ return deleted;
283
+ }
284
+
285
+ async listPartitions(_tier?: string): Promise<PartitionInfo[]> {
286
+ // In-memory storage doesn't use partitions
287
+ return [];
288
+ }
289
+
290
+ getConfig(): MetricsStorageConfig {
291
+ return this.config;
292
+ }
293
+
294
+ async close(): Promise<void> {
295
+ if (this.flushTimer) {
296
+ clearInterval(this.flushTimer);
297
+ this.flushTimer = null;
298
+ }
299
+ await this.flush();
300
+ this.buckets.clear();
301
+ this.samples.clear();
302
+ }
303
+
304
+ // Helper methods
305
+
306
+ private getBucketTime(timestamp: Date, interval: AggregationInterval): Date {
307
+ const ms = this.getIntervalMs(interval);
308
+ return new Date(Math.floor(timestamp.getTime() / ms) * ms);
309
+ }
310
+
311
+ private getBucketKey(point: MetricPoint, bucketTime: Date): string {
312
+ return [
313
+ point.projectId,
314
+ point.service,
315
+ point.environment,
316
+ point.name,
317
+ this.hashLabels(point.labels),
318
+ bucketTime.getTime(),
319
+ ].join(':');
320
+ }
321
+
322
+ private hashLabels(labels: MetricLabels): string {
323
+ const sorted = Object.keys(labels)
324
+ .sort()
325
+ .map((k) => `${k}=${labels[k]}`)
326
+ .join(',');
327
+ return sorted || '_empty_';
328
+ }
329
+
330
+ private getIntervalMs(interval: AggregationInterval): number {
331
+ const map: Record<AggregationInterval, number> = {
332
+ '1m': 60_000,
333
+ '5m': 300_000,
334
+ '15m': 900_000,
335
+ '1h': 3_600_000,
336
+ '6h': 21_600_000,
337
+ '1d': 86_400_000,
338
+ };
339
+ return map[interval];
340
+ }
341
+
342
+ private matchesPattern(name: string, pattern: string): boolean {
343
+ if (!pattern.includes('*')) return name === pattern;
344
+ const regex = new RegExp(
345
+ `^${pattern.replace(/\./g, '\\.').replace(/\*/g, '.*')}$`,
346
+ );
347
+ return regex.test(name);
348
+ }
349
+
350
+ private matchesLabels(labels: MetricLabels, filter: MetricLabels): boolean {
351
+ for (const [key, value] of Object.entries(filter)) {
352
+ if (labels[key] !== value) return false;
353
+ }
354
+ return true;
355
+ }
356
+
357
+ private getGroupKey(bucket: MetricBucket, groupBy: string[]): string {
358
+ const parts = [bucket.name];
359
+ for (const key of groupBy) {
360
+ parts.push(`${key}=${bucket.labels[key] ?? ''}`);
361
+ }
362
+ return parts.join(':');
363
+ }
364
+
365
+ private filterLabels(labels: MetricLabels, keys: string[]): MetricLabels {
366
+ const result: MetricLabels = {};
367
+ for (const key of keys) {
368
+ if (labels[key] !== undefined) {
369
+ result[key] = labels[key];
370
+ }
371
+ }
372
+ return result;
373
+ }
374
+
375
+ private percentile(sorted: number[], p: number): number {
376
+ if (sorted.length === 0) return 0;
377
+ const index = Math.ceil((p / 100) * sorted.length) - 1;
378
+ return sorted[Math.max(0, index)] ?? 0;
379
+ }
380
+ }