@spinajs/telemetry 2.0.482

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 (214) hide show
  1. package/README.md +482 -0
  2. package/lib/cjs/InMemoryPerfSink.d.ts +51 -0
  3. package/lib/cjs/InMemoryPerfSink.d.ts.map +1 -0
  4. package/lib/cjs/InMemoryPerfSink.js +100 -0
  5. package/lib/cjs/InMemoryPerfSink.js.map +1 -0
  6. package/lib/cjs/PromMetricSink.d.ts +26 -0
  7. package/lib/cjs/PromMetricSink.d.ts.map +1 -0
  8. package/lib/cjs/PromMetricSink.js +68 -0
  9. package/lib/cjs/PromMetricSink.js.map +1 -0
  10. package/lib/cjs/bootstrap.d.ts +13 -0
  11. package/lib/cjs/bootstrap.d.ts.map +1 -0
  12. package/lib/cjs/bootstrap.js +57 -0
  13. package/lib/cjs/bootstrap.js.map +1 -0
  14. package/lib/cjs/config/telemetry.d.ts +63 -0
  15. package/lib/cjs/config/telemetry.d.ts.map +1 -0
  16. package/lib/cjs/config/telemetry.js +78 -0
  17. package/lib/cjs/config/telemetry.js.map +1 -0
  18. package/lib/cjs/controllers/Metrics.d.ts +26 -0
  19. package/lib/cjs/controllers/Metrics.d.ts.map +1 -0
  20. package/lib/cjs/controllers/Metrics.js +63 -0
  21. package/lib/cjs/controllers/Metrics.js.map +1 -0
  22. package/lib/cjs/controllers/Telemetry.d.ts +92 -0
  23. package/lib/cjs/controllers/Telemetry.d.ts.map +1 -0
  24. package/lib/cjs/controllers/Telemetry.js +226 -0
  25. package/lib/cjs/controllers/Telemetry.js.map +1 -0
  26. package/lib/cjs/dto/index.d.ts +21 -0
  27. package/lib/cjs/dto/index.d.ts.map +1 -0
  28. package/lib/cjs/dto/index.js +64 -0
  29. package/lib/cjs/dto/index.js.map +1 -0
  30. package/lib/cjs/endpoints.d.ts +32 -0
  31. package/lib/cjs/endpoints.d.ts.map +1 -0
  32. package/lib/cjs/endpoints.js +38 -0
  33. package/lib/cjs/endpoints.js.map +1 -0
  34. package/lib/cjs/health.d.ts +55 -0
  35. package/lib/cjs/health.d.ts.map +1 -0
  36. package/lib/cjs/health.js +111 -0
  37. package/lib/cjs/health.js.map +1 -0
  38. package/lib/cjs/index.d.ts +16 -0
  39. package/lib/cjs/index.d.ts.map +1 -0
  40. package/lib/cjs/index.js +32 -0
  41. package/lib/cjs/index.js.map +1 -0
  42. package/lib/cjs/metrics.d.ts +16 -0
  43. package/lib/cjs/metrics.d.ts.map +1 -0
  44. package/lib/cjs/metrics.js +32 -0
  45. package/lib/cjs/metrics.js.map +1 -0
  46. package/lib/cjs/middleware.d.ts +81 -0
  47. package/lib/cjs/middleware.d.ts.map +1 -0
  48. package/lib/cjs/middleware.js +210 -0
  49. package/lib/cjs/middleware.js.map +1 -0
  50. package/lib/cjs/package.json +1 -0
  51. package/lib/cjs/policies/PublicPolicy.d.ts +16 -0
  52. package/lib/cjs/policies/PublicPolicy.d.ts.map +1 -0
  53. package/lib/cjs/policies/PublicPolicy.js +34 -0
  54. package/lib/cjs/policies/PublicPolicy.js.map +1 -0
  55. package/lib/cjs/policies/TelemetryTokenPolicy.d.ts +19 -0
  56. package/lib/cjs/policies/TelemetryTokenPolicy.d.ts.map +1 -0
  57. package/lib/cjs/policies/TelemetryTokenPolicy.js +65 -0
  58. package/lib/cjs/policies/TelemetryTokenPolicy.js.map +1 -0
  59. package/lib/cjs/requestStats.d.ts +81 -0
  60. package/lib/cjs/requestStats.d.ts.map +1 -0
  61. package/lib/cjs/requestStats.js +134 -0
  62. package/lib/cjs/requestStats.js.map +1 -0
  63. package/lib/cjs/responses.d.ts +23 -0
  64. package/lib/cjs/responses.d.ts.map +1 -0
  65. package/lib/cjs/responses.js +35 -0
  66. package/lib/cjs/responses.js.map +1 -0
  67. package/lib/cjs/routeStats.d.ts +43 -0
  68. package/lib/cjs/routeStats.d.ts.map +1 -0
  69. package/lib/cjs/routeStats.js +59 -0
  70. package/lib/cjs/routeStats.js.map +1 -0
  71. package/lib/cjs/schemas/HealthResponse.schema.d.ts +30 -0
  72. package/lib/cjs/schemas/HealthResponse.schema.d.ts.map +1 -0
  73. package/lib/cjs/schemas/HealthResponse.schema.js +15 -0
  74. package/lib/cjs/schemas/HealthResponse.schema.js.map +1 -0
  75. package/lib/cjs/schemas/PerfResponse.schema.d.ts +56 -0
  76. package/lib/cjs/schemas/PerfResponse.schema.d.ts.map +1 -0
  77. package/lib/cjs/schemas/PerfResponse.schema.js +36 -0
  78. package/lib/cjs/schemas/PerfResponse.schema.js.map +1 -0
  79. package/lib/cjs/schemas/ReadyResponse.schema.d.ts +36 -0
  80. package/lib/cjs/schemas/ReadyResponse.schema.d.ts.map +1 -0
  81. package/lib/cjs/schemas/ReadyResponse.schema.js +23 -0
  82. package/lib/cjs/schemas/ReadyResponse.schema.js.map +1 -0
  83. package/lib/cjs/schemas/RequestStatsSnapshot.schema.d.ts +79 -0
  84. package/lib/cjs/schemas/RequestStatsSnapshot.schema.d.ts.map +1 -0
  85. package/lib/cjs/schemas/RequestStatsSnapshot.schema.js +30 -0
  86. package/lib/cjs/schemas/RequestStatsSnapshot.schema.js.map +1 -0
  87. package/lib/cjs/schemas/RoutesResponse.schema.d.ts +100 -0
  88. package/lib/cjs/schemas/RoutesResponse.schema.d.ts.map +1 -0
  89. package/lib/cjs/schemas/RoutesResponse.schema.js +25 -0
  90. package/lib/cjs/schemas/RoutesResponse.schema.js.map +1 -0
  91. package/lib/cjs/schemas/StatsResponse.schema.d.ts +158 -0
  92. package/lib/cjs/schemas/StatsResponse.schema.d.ts.map +1 -0
  93. package/lib/cjs/schemas/StatsResponse.schema.js +19 -0
  94. package/lib/cjs/schemas/StatsResponse.schema.js.map +1 -0
  95. package/lib/cjs/schemas/TimelineResponse.schema.d.ts +109 -0
  96. package/lib/cjs/schemas/TimelineResponse.schema.d.ts.map +1 -0
  97. package/lib/cjs/schemas/TimelineResponse.schema.js +28 -0
  98. package/lib/cjs/schemas/TimelineResponse.schema.js.map +1 -0
  99. package/lib/cjs/store.d.ts +58 -0
  100. package/lib/cjs/store.d.ts.map +1 -0
  101. package/lib/cjs/store.js +108 -0
  102. package/lib/cjs/store.js.map +1 -0
  103. package/lib/cjs/timeline.d.ts +48 -0
  104. package/lib/cjs/timeline.d.ts.map +1 -0
  105. package/lib/cjs/timeline.js +70 -0
  106. package/lib/cjs/timeline.js.map +1 -0
  107. package/lib/mjs/InMemoryPerfSink.d.ts +51 -0
  108. package/lib/mjs/InMemoryPerfSink.d.ts.map +1 -0
  109. package/lib/mjs/InMemoryPerfSink.js +97 -0
  110. package/lib/mjs/InMemoryPerfSink.js.map +1 -0
  111. package/lib/mjs/PromMetricSink.d.ts +26 -0
  112. package/lib/mjs/PromMetricSink.d.ts.map +1 -0
  113. package/lib/mjs/PromMetricSink.js +65 -0
  114. package/lib/mjs/PromMetricSink.js.map +1 -0
  115. package/lib/mjs/bootstrap.d.ts +13 -0
  116. package/lib/mjs/bootstrap.d.ts.map +1 -0
  117. package/lib/mjs/bootstrap.js +54 -0
  118. package/lib/mjs/bootstrap.js.map +1 -0
  119. package/lib/mjs/config/telemetry.d.ts +63 -0
  120. package/lib/mjs/config/telemetry.d.ts.map +1 -0
  121. package/lib/mjs/config/telemetry.js +76 -0
  122. package/lib/mjs/config/telemetry.js.map +1 -0
  123. package/lib/mjs/controllers/Metrics.d.ts +26 -0
  124. package/lib/mjs/controllers/Metrics.d.ts.map +1 -0
  125. package/lib/mjs/controllers/Metrics.js +60 -0
  126. package/lib/mjs/controllers/Metrics.js.map +1 -0
  127. package/lib/mjs/controllers/Telemetry.d.ts +92 -0
  128. package/lib/mjs/controllers/Telemetry.d.ts.map +1 -0
  129. package/lib/mjs/controllers/Telemetry.js +223 -0
  130. package/lib/mjs/controllers/Telemetry.js.map +1 -0
  131. package/lib/mjs/dto/index.d.ts +21 -0
  132. package/lib/mjs/dto/index.d.ts.map +1 -0
  133. package/lib/mjs/dto/index.js +58 -0
  134. package/lib/mjs/dto/index.js.map +1 -0
  135. package/lib/mjs/endpoints.d.ts +32 -0
  136. package/lib/mjs/endpoints.d.ts.map +1 -0
  137. package/lib/mjs/endpoints.js +34 -0
  138. package/lib/mjs/endpoints.js.map +1 -0
  139. package/lib/mjs/health.d.ts +55 -0
  140. package/lib/mjs/health.d.ts.map +1 -0
  141. package/lib/mjs/health.js +107 -0
  142. package/lib/mjs/health.js.map +1 -0
  143. package/lib/mjs/index.d.ts +16 -0
  144. package/lib/mjs/index.d.ts.map +1 -0
  145. package/lib/mjs/index.js +16 -0
  146. package/lib/mjs/index.js.map +1 -0
  147. package/lib/mjs/metrics.d.ts +16 -0
  148. package/lib/mjs/metrics.d.ts.map +1 -0
  149. package/lib/mjs/metrics.js +16 -0
  150. package/lib/mjs/metrics.js.map +1 -0
  151. package/lib/mjs/middleware.d.ts +81 -0
  152. package/lib/mjs/middleware.d.ts.map +1 -0
  153. package/lib/mjs/middleware.js +207 -0
  154. package/lib/mjs/middleware.js.map +1 -0
  155. package/lib/mjs/package.json +1 -0
  156. package/lib/mjs/policies/PublicPolicy.d.ts +16 -0
  157. package/lib/mjs/policies/PublicPolicy.d.ts.map +1 -0
  158. package/lib/mjs/policies/PublicPolicy.js +31 -0
  159. package/lib/mjs/policies/PublicPolicy.js.map +1 -0
  160. package/lib/mjs/policies/TelemetryTokenPolicy.d.ts +19 -0
  161. package/lib/mjs/policies/TelemetryTokenPolicy.d.ts.map +1 -0
  162. package/lib/mjs/policies/TelemetryTokenPolicy.js +62 -0
  163. package/lib/mjs/policies/TelemetryTokenPolicy.js.map +1 -0
  164. package/lib/mjs/requestStats.d.ts +81 -0
  165. package/lib/mjs/requestStats.d.ts.map +1 -0
  166. package/lib/mjs/requestStats.js +130 -0
  167. package/lib/mjs/requestStats.js.map +1 -0
  168. package/lib/mjs/responses.d.ts +23 -0
  169. package/lib/mjs/responses.d.ts.map +1 -0
  170. package/lib/mjs/responses.js +30 -0
  171. package/lib/mjs/responses.js.map +1 -0
  172. package/lib/mjs/routeStats.d.ts +43 -0
  173. package/lib/mjs/routeStats.d.ts.map +1 -0
  174. package/lib/mjs/routeStats.js +55 -0
  175. package/lib/mjs/routeStats.js.map +1 -0
  176. package/lib/mjs/schemas/HealthResponse.schema.d.ts +30 -0
  177. package/lib/mjs/schemas/HealthResponse.schema.d.ts.map +1 -0
  178. package/lib/mjs/schemas/HealthResponse.schema.js +13 -0
  179. package/lib/mjs/schemas/HealthResponse.schema.js.map +1 -0
  180. package/lib/mjs/schemas/PerfResponse.schema.d.ts +56 -0
  181. package/lib/mjs/schemas/PerfResponse.schema.d.ts.map +1 -0
  182. package/lib/mjs/schemas/PerfResponse.schema.js +34 -0
  183. package/lib/mjs/schemas/PerfResponse.schema.js.map +1 -0
  184. package/lib/mjs/schemas/ReadyResponse.schema.d.ts +36 -0
  185. package/lib/mjs/schemas/ReadyResponse.schema.d.ts.map +1 -0
  186. package/lib/mjs/schemas/ReadyResponse.schema.js +21 -0
  187. package/lib/mjs/schemas/ReadyResponse.schema.js.map +1 -0
  188. package/lib/mjs/schemas/RequestStatsSnapshot.schema.d.ts +79 -0
  189. package/lib/mjs/schemas/RequestStatsSnapshot.schema.d.ts.map +1 -0
  190. package/lib/mjs/schemas/RequestStatsSnapshot.schema.js +28 -0
  191. package/lib/mjs/schemas/RequestStatsSnapshot.schema.js.map +1 -0
  192. package/lib/mjs/schemas/RoutesResponse.schema.d.ts +100 -0
  193. package/lib/mjs/schemas/RoutesResponse.schema.d.ts.map +1 -0
  194. package/lib/mjs/schemas/RoutesResponse.schema.js +20 -0
  195. package/lib/mjs/schemas/RoutesResponse.schema.js.map +1 -0
  196. package/lib/mjs/schemas/StatsResponse.schema.d.ts +158 -0
  197. package/lib/mjs/schemas/StatsResponse.schema.d.ts.map +1 -0
  198. package/lib/mjs/schemas/StatsResponse.schema.js +14 -0
  199. package/lib/mjs/schemas/StatsResponse.schema.js.map +1 -0
  200. package/lib/mjs/schemas/TimelineResponse.schema.d.ts +109 -0
  201. package/lib/mjs/schemas/TimelineResponse.schema.d.ts.map +1 -0
  202. package/lib/mjs/schemas/TimelineResponse.schema.js +23 -0
  203. package/lib/mjs/schemas/TimelineResponse.schema.js.map +1 -0
  204. package/lib/mjs/store.d.ts +58 -0
  205. package/lib/mjs/store.d.ts.map +1 -0
  206. package/lib/mjs/store.js +105 -0
  207. package/lib/mjs/store.js.map +1 -0
  208. package/lib/mjs/timeline.d.ts +48 -0
  209. package/lib/mjs/timeline.d.ts.map +1 -0
  210. package/lib/mjs/timeline.js +66 -0
  211. package/lib/mjs/timeline.js.map +1 -0
  212. package/lib/tsconfig.cjs.tsbuildinfo +1 -0
  213. package/lib/tsconfig.mjs.tsbuildinfo +1 -0
  214. package/package.json +69 -0
@@ -0,0 +1,48 @@
1
+ import { IRequestStatsSnapshot } from './requestStats.js';
2
+ /**
3
+ * Serializable snapshot of a {@link Timeline}: a map of bucket-key -> stats.
4
+ */
5
+ export type ITimelineSnapshot = Record<string, IRequestStatsSnapshot>;
6
+ /**
7
+ * Port of swagger-stats' `swsTimeline` — a rolling ring of `length` buckets,
8
+ * each spanning `bucketMs`, keyed by `floor(timestamp / bucketMs)`. Each bucket
9
+ * holds its own {@link RequestStats}.
10
+ *
11
+ * Deterministic: every method takes the current timestamp so tests can drive
12
+ * it without touching the real clock.
13
+ */
14
+ export declare class Timeline {
15
+ /**
16
+ * Number of buckets retained in the ring.
17
+ */
18
+ readonly length: number;
19
+ /**
20
+ * Bucket width in milliseconds.
21
+ */
22
+ readonly bucketMs: number;
23
+ /**
24
+ * Apdex threshold ( ms ) propagated to each bucket's RequestStats.
25
+ */
26
+ readonly apdexThreshold: number;
27
+ private buckets;
28
+ constructor(length?: number, bucketMs?: number, apdexThreshold?: number);
29
+ /**
30
+ * The bucket key for a timestamp.
31
+ */
32
+ keyFor(timestamp: number): number;
33
+ private ensureBucket;
34
+ /**
35
+ * Open the bucket for `now` and expire buckets older than `length` buckets.
36
+ */
37
+ tick(now?: number): void;
38
+ /**
39
+ * Route a completed response into the bucket for its timestamp ( ticking to
40
+ * open the current bucket + expire old ones first ).
41
+ */
42
+ record(statusCode: number, durationMs: number, timestamp?: number): void;
43
+ /**
44
+ * A plain-object snapshot of every live bucket, keyed by bucket key.
45
+ */
46
+ toJSON(): ITimelineSnapshot;
47
+ }
48
+ //# sourceMappingURL=timeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../../src/timeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAgB,MAAM,mBAAmB,CAAC;AAExE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;AAKtE;;;;;;;GAOG;AACH,qBAAa,QAAQ;IACnB;;OAEG;IACH,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B;;OAEG;IACH,SAAgB,QAAQ,EAAE,MAAM,CAAC;IAEjC;;OAEG;IACH,SAAgB,cAAc,EAAE,MAAM,CAAC;IAEvC,OAAO,CAAC,OAAO,CAAmC;gBAEtC,MAAM,GAAE,MAAuB,EAAE,QAAQ,GAAE,MAA0B,EAAE,cAAc,CAAC,EAAE,MAAM;IAM1G;;OAEG;IACI,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAIxC,OAAO,CAAC,YAAY;IASpB;;OAEG;IACI,IAAI,CAAC,GAAG,GAAE,MAAmB,GAAG,IAAI;IAU3C;;;OAGG;IACI,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,GAAE,MAAmB,GAAG,IAAI;IAO3F;;OAEG;IACI,MAAM,IAAI,iBAAiB;CAOnC"}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Timeline = void 0;
4
+ const requestStats_js_1 = require("./requestStats.js");
5
+ const DEFAULT_LENGTH = 60;
6
+ const DEFAULT_BUCKET_MS = 60_000;
7
+ /**
8
+ * Port of swagger-stats' `swsTimeline` — a rolling ring of `length` buckets,
9
+ * each spanning `bucketMs`, keyed by `floor(timestamp / bucketMs)`. Each bucket
10
+ * holds its own {@link RequestStats}.
11
+ *
12
+ * Deterministic: every method takes the current timestamp so tests can drive
13
+ * it without touching the real clock.
14
+ */
15
+ class Timeline {
16
+ constructor(length = DEFAULT_LENGTH, bucketMs = DEFAULT_BUCKET_MS, apdexThreshold) {
17
+ this.buckets = new Map();
18
+ this.length = length;
19
+ this.bucketMs = bucketMs;
20
+ this.apdexThreshold = apdexThreshold ?? new requestStats_js_1.RequestStats().apdexThreshold;
21
+ }
22
+ /**
23
+ * The bucket key for a timestamp.
24
+ */
25
+ keyFor(timestamp) {
26
+ return Math.floor(timestamp / this.bucketMs);
27
+ }
28
+ ensureBucket(key) {
29
+ let bucket = this.buckets.get(key);
30
+ if (!bucket) {
31
+ bucket = new requestStats_js_1.RequestStats(this.apdexThreshold);
32
+ this.buckets.set(key, bucket);
33
+ }
34
+ return bucket;
35
+ }
36
+ /**
37
+ * Open the bucket for `now` and expire buckets older than `length` buckets.
38
+ */
39
+ tick(now = Date.now()) {
40
+ const current = this.keyFor(now);
41
+ this.ensureBucket(current);
42
+ const oldest = current - this.length + 1;
43
+ for (const key of [...this.buckets.keys()]) {
44
+ if (key < oldest)
45
+ this.buckets.delete(key);
46
+ }
47
+ }
48
+ /**
49
+ * Route a completed response into the bucket for its timestamp ( ticking to
50
+ * open the current bucket + expire old ones first ).
51
+ */
52
+ record(statusCode, durationMs, timestamp = Date.now()) {
53
+ this.tick(timestamp);
54
+ const bucket = this.ensureBucket(this.keyFor(timestamp));
55
+ bucket.countRequest();
56
+ bucket.countResponse(statusCode, durationMs);
57
+ }
58
+ /**
59
+ * A plain-object snapshot of every live bucket, keyed by bucket key.
60
+ */
61
+ toJSON() {
62
+ const out = {};
63
+ for (const [key, stats] of this.buckets) {
64
+ out[String(key)] = stats.toJSON();
65
+ }
66
+ return out;
67
+ }
68
+ }
69
+ exports.Timeline = Timeline;
70
+ //# sourceMappingURL=timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../src/timeline.ts"],"names":[],"mappings":";;;AAAA,uDAAwE;AAOxE,MAAM,cAAc,GAAG,EAAE,CAAC;AAC1B,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEjC;;;;;;;GAOG;AACH,MAAa,QAAQ;IAkBnB,YAAY,SAAiB,cAAc,EAAE,WAAmB,iBAAiB,EAAE,cAAuB;QAFlG,YAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;QAGhD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,cAAc,GAAG,cAAc,IAAI,IAAI,8BAAY,EAAE,CAAC,cAAc,CAAC;IAC5E,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,SAAiB;QAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAEO,YAAY,CAAC,GAAW;QAC9B,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG,IAAI,8BAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAC/C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACI,IAAI,CAAC,MAAc,IAAI,CAAC,GAAG,EAAE;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAE3B,MAAM,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACzC,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC3C,IAAI,GAAG,GAAG,MAAM;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,UAAkB,EAAE,UAAkB,EAAE,YAAoB,IAAI,CAAC,GAAG,EAAE;QAClF,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QACzD,MAAM,CAAC,YAAY,EAAE,CAAC;QACtB,MAAM,CAAC,aAAa,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAC/C,CAAC;IAED;;OAEG;IACI,MAAM;QACX,MAAM,GAAG,GAAsB,EAAE,CAAC;QAClC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACpC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AA1ED,4BA0EC"}
@@ -0,0 +1,51 @@
1
+ import { PerfSink, IPerfMetric } from '@spinajs/log';
2
+ /** One aggregated span row. */
3
+ export interface IPerfSpanEntry {
4
+ name: string;
5
+ count: number;
6
+ totalMs: number;
7
+ avgMs: number;
8
+ maxMs: number;
9
+ }
10
+ /** One aggregated counter / value row. */
11
+ export interface IPerfEventEntry {
12
+ name: string;
13
+ count: number;
14
+ total: number;
15
+ }
16
+ /** Serializable snapshot served by `GET /telemetry/perf`. */
17
+ export interface IPerfSnapshot {
18
+ /** True once the name cap was hit and new names stopped being tracked. */
19
+ truncated: boolean;
20
+ spans: IPerfSpanEntry[];
21
+ events: IPerfEventEntry[];
22
+ }
23
+ /**
24
+ * A {@link PerfSink} that keeps a bounded, JSON-readable aggregate of every
25
+ * measurement, backing `GET /telemetry/perf`.
26
+ *
27
+ * This exists alongside `PromMetricSink` rather than replacing it: prom
28
+ * histograms are the right shape for Prometheus but their bucket counts cannot
29
+ * be read back as a mean or a max, which is what a JSON snapshot needs.
30
+ *
31
+ * Per-request rollups are intentionally NOT implemented here — `onScopeEnd`
32
+ * totals share the span names, so folding them in would double-count against
33
+ * the same rows. The per-request view lives in `perf_scope_total_ms` on the
34
+ * prometheus side.
35
+ */
36
+ export declare class InMemoryPerfSink extends PerfSink {
37
+ protected Enabled: boolean;
38
+ protected MaxNames: number;
39
+ private spans;
40
+ private events;
41
+ private truncated;
42
+ collect(metric: IPerfMetric): void;
43
+ toJSON(): IPerfSnapshot;
44
+ /**
45
+ * Whether a NEW name may be tracked. Spans and events share one budget so the
46
+ * total retained-name count is what `maxNames` bounds.
47
+ */
48
+ private track;
49
+ private create;
50
+ }
51
+ //# sourceMappingURL=InMemoryPerfSink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InMemoryPerfSink.d.ts","sourceRoot":"","sources":["../../src/InMemoryPerfSink.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAErD,+BAA+B;AAC/B,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,6DAA6D;AAC7D,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED;;;;;;;;;;;;GAYG;AACH,qBAEa,gBAAiB,SAAQ,QAAQ;IAE5C,SAAS,CAAC,OAAO,EAAG,OAAO,CAAC;IAG5B,SAAS,CAAC,QAAQ,EAAG,MAAM,CAAC;IAE5B,OAAO,CAAC,KAAK,CAAwE;IACrF,OAAO,CAAC,MAAM,CAAuD;IACrE,OAAO,CAAC,SAAS,CAAS;IAEnB,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAsBlC,MAAM,IAAI,aAAa;IAgB9B;;;OAGG;IACH,OAAO,CAAC,KAAK;IAQb,OAAO,CAAC,MAAM;CAIf"}
@@ -0,0 +1,97 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Singleton, Injectable } from '@spinajs/di';
11
+ import { Config } from '@spinajs/configuration';
12
+ import { PerfSink } from '@spinajs/log';
13
+ /**
14
+ * A {@link PerfSink} that keeps a bounded, JSON-readable aggregate of every
15
+ * measurement, backing `GET /telemetry/perf`.
16
+ *
17
+ * This exists alongside `PromMetricSink` rather than replacing it: prom
18
+ * histograms are the right shape for Prometheus but their bucket counts cannot
19
+ * be read back as a mean or a max, which is what a JSON snapshot needs.
20
+ *
21
+ * Per-request rollups are intentionally NOT implemented here — `onScopeEnd`
22
+ * totals share the span names, so folding them in would double-count against
23
+ * the same rows. The per-request view lives in `perf_scope_total_ms` on the
24
+ * prometheus side.
25
+ */
26
+ let InMemoryPerfSink = class InMemoryPerfSink extends PerfSink {
27
+ constructor() {
28
+ super(...arguments);
29
+ this.spans = new Map();
30
+ this.events = new Map();
31
+ this.truncated = false;
32
+ }
33
+ collect(metric) {
34
+ if (this.Enabled === false)
35
+ return;
36
+ if (!metric || typeof metric.name !== 'string')
37
+ return;
38
+ if (metric.kind === 'span') {
39
+ const entry = this.spans.get(metric.name) ?? (this.track(metric.name) ? this.create(this.spans, metric.name, { count: 0, totalMs: 0, maxMs: 0 }) : undefined);
40
+ if (!entry)
41
+ return;
42
+ const durationMs = metric.durationMs ?? 0;
43
+ entry.count += 1;
44
+ entry.totalMs += durationMs;
45
+ if (durationMs > entry.maxMs)
46
+ entry.maxMs = durationMs;
47
+ return;
48
+ }
49
+ const entry = this.events.get(metric.name) ?? (this.track(metric.name) ? this.create(this.events, metric.name, { count: 0, total: 0 }) : undefined);
50
+ if (!entry)
51
+ return;
52
+ entry.count += 1;
53
+ entry.total += metric.value ?? 1;
54
+ }
55
+ toJSON() {
56
+ const spans = [];
57
+ for (const [name, e] of this.spans) {
58
+ spans.push({ name, count: e.count, totalMs: e.totalMs, avgMs: e.count > 0 ? e.totalMs / e.count : 0, maxMs: e.maxMs });
59
+ }
60
+ spans.sort((a, b) => b.totalMs - a.totalMs);
61
+ const events = [];
62
+ for (const [name, e] of this.events) {
63
+ events.push({ name, count: e.count, total: e.total });
64
+ }
65
+ events.sort((a, b) => b.total - a.total);
66
+ return { truncated: this.truncated, spans, events };
67
+ }
68
+ /**
69
+ * Whether a NEW name may be tracked. Spans and events share one budget so the
70
+ * total retained-name count is what `maxNames` bounds.
71
+ */
72
+ track(_name) {
73
+ if (this.spans.size + this.events.size >= (this.MaxNames ?? 200)) {
74
+ this.truncated = true;
75
+ return false;
76
+ }
77
+ return true;
78
+ }
79
+ create(map, name, initial) {
80
+ map.set(name, initial);
81
+ return initial;
82
+ }
83
+ };
84
+ __decorate([
85
+ Config('telemetry.perf.enabled', { defaultValue: true }),
86
+ __metadata("design:type", Boolean)
87
+ ], InMemoryPerfSink.prototype, "Enabled", void 0);
88
+ __decorate([
89
+ Config('telemetry.perf.maxNames', { defaultValue: 200 }),
90
+ __metadata("design:type", Number)
91
+ ], InMemoryPerfSink.prototype, "MaxNames", void 0);
92
+ InMemoryPerfSink = __decorate([
93
+ Singleton(),
94
+ Injectable(PerfSink)
95
+ ], InMemoryPerfSink);
96
+ export { InMemoryPerfSink };
97
+ //# sourceMappingURL=InMemoryPerfSink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InMemoryPerfSink.js","sourceRoot":"","sources":["../../src/InMemoryPerfSink.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { PerfSink, IPerfMetric, IPerfRollup } from "@spinajs/log";
2
+ import { Counter, Histogram } from "prom-client";
3
+ import { Metrics } from "./metrics.js";
4
+ /** Duration histogram buckets ( ms ), mirroring the http telemetry middleware. */
5
+ export declare const PERF_DURATION_BUCKETS_MS: number[];
6
+ /**
7
+ * {@link PerfSink} that forwards perf measurements to the shared prom-client
8
+ * {@link Metrics} registry — the prom side of the dual-sink. Span durations go
9
+ * to `perf_span_duration_ms{name}`; counter/value events increment
10
+ * `perf_events_total{name}`; per-request scope totals go to their own
11
+ * `perf_scope_total_ms{name}` histogram so they don't conflate with the
12
+ * per-span distribution. Labels are restricted to `name` ( plus the metric's
13
+ * own low-cardinality labels are folded into the name label space via a single
14
+ * `name` label to stay bounded ).
15
+ */
16
+ export declare class PromMetricSink extends PerfSink {
17
+ protected metrics: Metrics;
18
+ protected duration: Histogram<string>;
19
+ protected events: Counter<string>;
20
+ protected scopeTotal: Histogram<string>;
21
+ private defined;
22
+ private ensure;
23
+ collect(metric: IPerfMetric): void;
24
+ onScopeEnd(rollup: IPerfRollup): void;
25
+ }
26
+ //# sourceMappingURL=PromMetricSink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromMetricSink.d.ts","sourceRoot":"","sources":["../../src/PromMetricSink.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,OAAO,EAAa,MAAM,cAAc,CAAC;AAElD,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,UAA6D,CAAC;AAEnG;;;;;;;;;GASG;AACH,qBAEa,cAAe,SAAQ,QAAQ;IAC1C,SAAS,CAAC,OAAO,EAAG,OAAO,CAAC;IAC5B,SAAS,CAAC,QAAQ,EAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IACvC,SAAS,CAAC,MAAM,EAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,SAAS,CAAC,UAAU,EAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IACzC,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO,CAAC,MAAM;IAcP,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IASlC,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;CAQ7C"}
@@ -0,0 +1,65 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Singleton, Injectable, DI } from "@spinajs/di";
8
+ import { PerfSink } from "@spinajs/log";
9
+ import { Metrics } from "./metrics.js";
10
+ /** Duration histogram buckets ( ms ), mirroring the http telemetry middleware. */
11
+ export const PERF_DURATION_BUCKETS_MS = [1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000];
12
+ /**
13
+ * {@link PerfSink} that forwards perf measurements to the shared prom-client
14
+ * {@link Metrics} registry — the prom side of the dual-sink. Span durations go
15
+ * to `perf_span_duration_ms{name}`; counter/value events increment
16
+ * `perf_events_total{name}`; per-request scope totals go to their own
17
+ * `perf_scope_total_ms{name}` histogram so they don't conflate with the
18
+ * per-span distribution. Labels are restricted to `name` ( plus the metric's
19
+ * own low-cardinality labels are folded into the name label space via a single
20
+ * `name` label to stay bounded ).
21
+ */
22
+ let PromMetricSink = class PromMetricSink extends PerfSink {
23
+ constructor() {
24
+ super(...arguments);
25
+ this.defined = false;
26
+ }
27
+ ensure() {
28
+ if (this.defined)
29
+ return;
30
+ this.metrics = DI.get(Metrics) ?? DI.resolve(Metrics);
31
+ const map = this.metrics.defineMetrics("perf", [
32
+ { name: "span_duration_ms", help: "Perf span duration in ms", type: "histogram", labelNames: ["name"], buckets: PERF_DURATION_BUCKETS_MS },
33
+ { name: "events_total", help: "Perf counter/value events", type: "counter", labelNames: ["name"] },
34
+ { name: "scope_total_ms", help: "Perf per-request scope total duration in ms", type: "histogram", labelNames: ["name"], buckets: PERF_DURATION_BUCKETS_MS },
35
+ ]);
36
+ this.duration = map["span_duration_ms"];
37
+ this.events = map["events_total"];
38
+ this.scopeTotal = map["scope_total_ms"];
39
+ this.defined = true;
40
+ }
41
+ collect(metric) {
42
+ this.ensure();
43
+ if (metric.kind === "span") {
44
+ this.duration.observe({ name: metric.name }, metric.durationMs ?? 0);
45
+ }
46
+ else {
47
+ this.events.inc({ name: metric.name }, metric.value ?? 1);
48
+ }
49
+ }
50
+ onScopeEnd(rollup) {
51
+ this.ensure();
52
+ for (const [name, e] of Object.entries(rollup.byName)) {
53
+ // per-request totals: record the aggregate duration once per request, into
54
+ // its own histogram so it doesn't conflate with the per-span distribution.
55
+ if (e.totalMs > 0)
56
+ this.scopeTotal.observe({ name }, e.totalMs);
57
+ }
58
+ }
59
+ };
60
+ PromMetricSink = __decorate([
61
+ Singleton(),
62
+ Injectable(PerfSink)
63
+ ], PromMetricSink);
64
+ export { PromMetricSink };
65
+ //# sourceMappingURL=PromMetricSink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromMetricSink.js","sourceRoot":"","sources":["../../src/PromMetricSink.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,QAAQ,EAA4B,MAAM,cAAc,CAAC;AAElE,OAAO,EAAE,OAAO,EAAa,MAAM,cAAc,CAAC;AAElD,kFAAkF;AAClF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAEnG;;;;;;;;;GASG;AAGI,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,QAAQ;IAArC;;QAKG,YAAO,GAAG,KAAK,CAAC;IAiC1B,CAAC;IA/BS,MAAM;QACZ,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,GAAG,GAAc,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE;YACxD,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,0BAA0B,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,wBAAwB,EAAE;YAC1I,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,MAAM,CAAC,EAAE;YAClG,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,6CAA6C,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,wBAAwB,EAAE;SAC5J,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,kBAAkB,CAAsB,CAAC;QAC7D,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,cAAc,CAAoB,CAAC;QACrD,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC,gBAAgB,CAAsB,CAAC;QAC7D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAEM,OAAO,CAAC,MAAmB;QAChC,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC;QACvE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAEM,UAAU,CAAC,MAAmB;QACnC,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YACtD,2EAA2E;YAC3E,2EAA2E;YAC3E,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC;gBAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;CACF,CAAA;AAtCY,cAAc;IAF1B,SAAS,EAAE;IACX,UAAU,CAAC,QAAQ,CAAC;GACR,cAAc,CAsC1B"}
@@ -0,0 +1,13 @@
1
+ import { Bootstrapper } from '@spinajs/di';
2
+ /**
3
+ * Wires the telemetry collection layer at startup:
4
+ *
5
+ * - registers prom-client's default process metrics against the PRIVATE
6
+ * registry ( never the global default one ), when configured,
7
+ * - builds the perf sinks and refreshes the Perf facade's sink list, so the
8
+ * perf bridge is live in apps that use telemetry WITHOUT @spinajs/http.
9
+ */
10
+ export declare class TelemetryBootstrapper extends Bootstrapper {
11
+ bootstrap(): void;
12
+ }
13
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,YAAY,EAAM,MAAM,aAAa,CAAC;AAM3D;;;;;;;GAOG;AACH,qBACa,qBAAsB,SAAQ,YAAY;IAC9C,SAAS,IAAI,IAAI;CAiCzB"}
@@ -0,0 +1,54 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Injectable, Bootstrapper, DI } from '@spinajs/di';
8
+ import { Configuration } from '@spinajs/configuration';
9
+ import { Perf, PerfSink } from '@spinajs/log';
10
+ import { Metrics } from './metrics.js';
11
+ /**
12
+ * Wires the telemetry collection layer at startup:
13
+ *
14
+ * - registers prom-client's default process metrics against the PRIVATE
15
+ * registry ( never the global default one ), when configured,
16
+ * - builds the perf sinks and refreshes the Perf facade's sink list, so the
17
+ * perf bridge is live in apps that use telemetry WITHOUT @spinajs/http.
18
+ */
19
+ let TelemetryBootstrapper = class TelemetryBootstrapper extends Bootstrapper {
20
+ bootstrap() {
21
+ const cfg = DI.get(Configuration);
22
+ const metrics = DI.get(Metrics) ?? DI.resolve(Metrics);
23
+ if (cfg?.get('telemetry.collectDefaultMetrics', true)) {
24
+ metrics.collectDefault();
25
+ }
26
+ // Build the sinks through the ARRAY, never with a direct
27
+ // `DI.resolve( PromMetricSink )`. A direct resolve caches the instance under
28
+ // its own type name only; the later `Array.ofType( PerfSink )` — which is
29
+ // what the Perf facade uses — then hits that cache entry on its fast path,
30
+ // returns it WITHOUT adding it to the `PerfSink` list, and the facade stays
31
+ // blind to that sink. Resolving the array first creates them together.
32
+ const sinks = DI.resolve(Array.ofType(PerfSink));
33
+ // The array cache does not double as a per-type cache, so publish each
34
+ // instance under its own type name too. Without this a later
35
+ // `@Autoinject( InMemoryPerfSink )` ( the telemetry controller does exactly
36
+ // that ) would build a SECOND, permanently empty sink.
37
+ //
38
+ // `override` MUST be true: without it `asValue` APPENDS to an existing cache
39
+ // entry instead of replacing it, while the resolve fast path keeps handing
40
+ // out the entry it already had. So anything that resolved a sink directly
41
+ // BEFORE this bootstrapper ran — an earlier-ordered consumer bootstrapper,
42
+ // or an app still calling `DI.resolve( PromMetricSink )` — would pin
43
+ // `@Autoinject` to that earlier, permanently empty instance.
44
+ for (const sink of sinks) {
45
+ DI.register(sink).asValue(sink.constructor.name, true);
46
+ }
47
+ Perf.refreshSinks();
48
+ }
49
+ };
50
+ TelemetryBootstrapper = __decorate([
51
+ Injectable(Bootstrapper)
52
+ ], TelemetryBootstrapper);
53
+ export { TelemetryBootstrapper };
54
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/bootstrap.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;;;;;;GAOG;AAEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,YAAY;IAC9C,SAAS;QACd,MAAM,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAEvD,IAAI,GAAG,EAAE,GAAG,CAAU,iCAAiC,EAAE,IAAI,CAAC,EAAE,CAAC;YAC/D,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,CAAC;QAED,yDAAyD;QACzD,6EAA6E;QAC7E,0EAA0E;QAC1E,2EAA2E;QAC3E,4EAA4E;QAC5E,uEAAuE;QACvE,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAEjD,uEAAuE;QACvE,6DAA6D;QAC7D,4EAA4E;QAC5E,uDAAuD;QACvD,EAAE;QACF,6EAA6E;QAC7E,2EAA2E;QAC3E,0EAA0E;QAC1E,2EAA2E;QAC3E,qEAAqE;QACrE,6DAA6D;QAC7D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACzD,CAAC;QAED,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;CACF,CAAA;AAlCY,qBAAqB;IADjC,UAAU,CAAC,YAAY,CAAC;GACZ,qBAAqB,CAkCjC"}
@@ -0,0 +1,63 @@
1
+ declare const config: {
2
+ system: {
3
+ dirs: {
4
+ controllers: string[];
5
+ };
6
+ };
7
+ telemetry: {
8
+ auth: {
9
+ token: string;
10
+ /**
11
+ * Policy class name per endpoint. Each route resolves its policy by
12
+ * reading the config key below, so access can be tightened or loosened
13
+ * per endpoint without touching code.
14
+ */
15
+ policies: {
16
+ metrics: string;
17
+ stats: string;
18
+ timeline: string;
19
+ routes: string;
20
+ perf: string;
21
+ health: string;
22
+ ready: string;
23
+ };
24
+ };
25
+ /**
26
+ * Register prom-client's process / heap / cpu / event-loop metrics against
27
+ * the private registry at bootstrap.
28
+ */
29
+ collectDefaultMetrics: boolean;
30
+ /** Metric name prefix for the http telemetry metrics. */
31
+ prefix: string;
32
+ /** Duration histogram buckets in ms. */
33
+ buckets: number[];
34
+ /** Apdex satisfied threshold in ms; tolerated is 4x this. */
35
+ apdexThresholdMs: number;
36
+ timeline: {
37
+ /** Number of buckets retained in the ring. */
38
+ length: number;
39
+ /** Bucket width in ms. */
40
+ bucketMs: number;
41
+ };
42
+ routes: {
43
+ enabled: boolean;
44
+ /** Cap on distinct method+route keys held in memory. */
45
+ maxEntries: number;
46
+ };
47
+ perf: {
48
+ enabled: boolean;
49
+ /** Cap on distinct perf measurement names held in memory. */
50
+ maxNames: number;
51
+ };
52
+ health: {
53
+ /** Per-check timeout in ms. A timed-out check counts as down. */
54
+ timeoutMs: number;
55
+ /** When true a degraded overall status returns 503 rather than 200. */
56
+ failOnDegraded: boolean;
57
+ /** Reported by /telemetry/health. Omitted from the response when unset. */
58
+ version: string | undefined;
59
+ };
60
+ };
61
+ };
62
+ export default config;
63
+ //# sourceMappingURL=telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../../src/config/telemetry.ts"],"names":[],"mappings":"AAcA,QAAA,MAAM,MAAM;;;;;;;;;YAYN;;;;eAIG;;;;;;;;;;;QAcL;;;WAGG;;QAGH,yDAAyD;;QAGzD,wCAAwC;;QAGxC,6DAA6D;;;YAI3D,8CAA8C;;YAE9C,0BAA0B;;;;;YAM1B,wDAAwD;;;;;YAMxD,6DAA6D;;;;YAK7D,iEAAiE;;YAEjE,uEAAuE;;YAEvE,2EAA2E;qBACrD,MAAM,GAAG,SAAS;;;CAG7C,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { join, normalize, resolve } from 'path';
2
+ function dir(path) {
3
+ const inCommonJs = typeof module !== 'undefined';
4
+ return resolve(normalize(join(process.env.WORKSPACE_ROOT_PATH ?? process.cwd(), 'node_modules', '@spinajs', 'telemetry', 'lib', inCommonJs ? 'cjs' : 'mjs', path)));
5
+ }
6
+ /**
7
+ * Duration histogram bucket boundaries ( ms ) for http request timing. Kept in
8
+ * sync with DURATION_BUCKETS_MS in middleware.ts, which is the compile-time
9
+ * default when no configuration is present.
10
+ */
11
+ const DURATION_BUCKETS_MS = [5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000];
12
+ const config = {
13
+ system: {
14
+ dirs: {
15
+ controllers: [dir('controllers')],
16
+ },
17
+ },
18
+ telemetry: {
19
+ auth: {
20
+ // set this in your project
21
+ token: '',
22
+ /**
23
+ * Policy class name per endpoint. Each route resolves its policy by
24
+ * reading the config key below, so access can be tightened or loosened
25
+ * per endpoint without touching code.
26
+ */
27
+ policies: {
28
+ metrics: 'TelemetryTokenPolicy',
29
+ stats: 'TelemetryTokenPolicy',
30
+ timeline: 'TelemetryTokenPolicy',
31
+ routes: 'TelemetryTokenPolicy',
32
+ perf: 'TelemetryTokenPolicy',
33
+ // probe endpoints must be reachable without credentials
34
+ health: 'PublicPolicy',
35
+ ready: 'PublicPolicy',
36
+ },
37
+ },
38
+ /**
39
+ * Register prom-client's process / heap / cpu / event-loop metrics against
40
+ * the private registry at bootstrap.
41
+ */
42
+ collectDefaultMetrics: true,
43
+ /** Metric name prefix for the http telemetry metrics. */
44
+ prefix: 'http',
45
+ /** Duration histogram buckets in ms. */
46
+ buckets: DURATION_BUCKETS_MS,
47
+ /** Apdex satisfied threshold in ms; tolerated is 4x this. */
48
+ apdexThresholdMs: 25,
49
+ timeline: {
50
+ /** Number of buckets retained in the ring. */
51
+ length: 60,
52
+ /** Bucket width in ms. */
53
+ bucketMs: 60_000,
54
+ },
55
+ routes: {
56
+ enabled: true,
57
+ /** Cap on distinct method+route keys held in memory. */
58
+ maxEntries: 500,
59
+ },
60
+ perf: {
61
+ enabled: true,
62
+ /** Cap on distinct perf measurement names held in memory. */
63
+ maxNames: 200,
64
+ },
65
+ health: {
66
+ /** Per-check timeout in ms. A timed-out check counts as down. */
67
+ timeoutMs: 2000,
68
+ /** When true a degraded overall status returns 503 rather than 200. */
69
+ failOnDegraded: false,
70
+ /** Reported by /telemetry/health. Omitted from the response when unset. */
71
+ version: undefined,
72
+ },
73
+ },
74
+ };
75
+ export default config;
76
+ //# sourceMappingURL=telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../../src/config/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEhD,SAAS,GAAG,CAAC,IAAY;IACvB,MAAM,UAAU,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC;IACjD,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AACtK,CAAC;AAED;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAEpF,MAAM,MAAM,GAAG;IACb,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,WAAW,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;SAClC;KACF;IAED,SAAS,EAAE;QACT,IAAI,EAAE;YACJ,2BAA2B;YAC3B,KAAK,EAAE,EAAE;YAET;;;;eAIG;YACH,QAAQ,EAAE;gBACR,OAAO,EAAE,sBAAsB;gBAC/B,KAAK,EAAE,sBAAsB;gBAC7B,QAAQ,EAAE,sBAAsB;gBAChC,MAAM,EAAE,sBAAsB;gBAC9B,IAAI,EAAE,sBAAsB;gBAE5B,wDAAwD;gBACxD,MAAM,EAAE,cAAc;gBACtB,KAAK,EAAE,cAAc;aACtB;SACF;QAED;;;WAGG;QACH,qBAAqB,EAAE,IAAI;QAE3B,yDAAyD;QACzD,MAAM,EAAE,MAAM;QAEd,wCAAwC;QACxC,OAAO,EAAE,mBAAmB;QAE5B,6DAA6D;QAC7D,gBAAgB,EAAE,EAAE;QAEpB,QAAQ,EAAE;YACR,8CAA8C;YAC9C,MAAM,EAAE,EAAE;YACV,0BAA0B;YAC1B,QAAQ,EAAE,MAAM;SACjB;QAED,MAAM,EAAE;YACN,OAAO,EAAE,IAAI;YACb,wDAAwD;YACxD,UAAU,EAAE,GAAG;SAChB;QAED,IAAI,EAAE;YACJ,OAAO,EAAE,IAAI;YACb,6DAA6D;YAC7D,QAAQ,EAAE,GAAG;SACd;QAED,MAAM,EAAE;YACN,iEAAiE;YACjE,SAAS,EAAE,IAAI;YACf,uEAAuE;YACvE,cAAc,EAAE,KAAK;YACrB,2EAA2E;YAC3E,OAAO,EAAE,SAA+B;SACzC;KACF;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { BaseController } from '@spinajs/http';
2
+ import { Metrics } from './../metrics.js';
3
+ import { PrometheusResponse } from './../responses.js';
4
+ import './../policies/TelemetryTokenPolicy.js';
5
+ import './../policies/PublicPolicy.js';
6
+ /**
7
+ * Prometheus scrape endpoint.
8
+ *
9
+ * Deliberately kept at the bare `/metrics` path rather than under the
10
+ * `/telemetry` prefix used by the JSON api — this is the path existing
11
+ * `scrape_configs` already point at.
12
+ */
13
+ export declare class MetricsController extends BaseController {
14
+ protected MetricsService: Metrics;
15
+ /**
16
+ * Prometheus exposition text for every metric on the registry: the `http_*`
17
+ * request metrics, the `perf_*` bridge metrics, any application metrics
18
+ * declared through `Metrics.defineMetrics`, and — when
19
+ * `telemetry.collectDefaultMetrics` is on — the `process_*` / `nodejs_*` set.
20
+ *
21
+ * @response 200 {string} Prometheus exposition text ( text/plain )
22
+ * @response 403 Access token missing or invalid
23
+ */
24
+ getMetrics(): Promise<PrometheusResponse>;
25
+ }
26
+ //# sourceMappingURL=Metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Metrics.d.ts","sourceRoot":"","sources":["../../../src/controllers/Metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,cAAc,EAAe,MAAM,eAAe,CAAC;AAGtE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAUvD,OAAO,uCAAuC,CAAC;AAC/C,OAAO,+BAA+B,CAAC;AAEvC;;;;;;GAMG;AACH,qBACa,iBAAkB,SAAQ,cAAc;IAEnD,SAAS,CAAC,cAAc,EAAE,OAAO,CAAC;IAElC;;;;;;;;OAQG;IAGU,UAAU;CAGxB"}