apm-optima 1.0.4 → 2.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 (177) hide show
  1. package/README.md +54 -23
  2. package/dashboard-out/404/index.html +1 -1
  3. package/dashboard-out/404.html +1 -1
  4. package/dashboard-out/__next.__PAGE__.txt +4 -4
  5. package/dashboard-out/__next._full.txt +17 -17
  6. package/dashboard-out/__next._head.txt +4 -4
  7. package/dashboard-out/__next._index.txt +10 -10
  8. package/dashboard-out/__next._tree.txt +2 -2
  9. package/dashboard-out/_next/static/chunks/{2xjcsu4pgp14_.js → 062oipeclh9bq.js} +1 -1
  10. package/dashboard-out/_next/static/chunks/0ncbimuip0-o7.css +3 -0
  11. package/dashboard-out/_next/static/chunks/0xtgenoch3q77.js +1 -0
  12. package/dashboard-out/_next/static/chunks/1xln1-s87x5yp.js +27 -0
  13. package/dashboard-out/_not-found/__next._full.txt +15 -15
  14. package/dashboard-out/_not-found/__next._head.txt +4 -4
  15. package/dashboard-out/_not-found/__next._index.txt +10 -10
  16. package/dashboard-out/_not-found/__next._not-found.__PAGE__.txt +2 -2
  17. package/dashboard-out/_not-found/__next._not-found.txt +3 -3
  18. package/dashboard-out/_not-found/__next._tree.txt +2 -2
  19. package/dashboard-out/_not-found/index.html +1 -1
  20. package/dashboard-out/_not-found/index.txt +15 -15
  21. package/dashboard-out/index.html +1 -1
  22. package/dashboard-out/index.txt +17 -17
  23. package/dist/adapters/session-export.handler.d.ts +4 -0
  24. package/dist/adapters/session-export.handler.js +29 -0
  25. package/dist/adapters/socket.options.d.ts +3 -0
  26. package/dist/adapters/socket.options.js +16 -0
  27. package/dist/config/config.manager.d.ts +80 -3
  28. package/dist/config/config.manager.js +269 -89
  29. package/dist/config/config.types.d.ts +89 -13
  30. package/dist/core/delivery/buckets-request.d.ts +2 -0
  31. package/dist/core/delivery/buckets-request.js +18 -0
  32. package/dist/core/delivery/index.d.ts +1 -0
  33. package/dist/core/delivery/index.js +1 -0
  34. package/dist/core/delivery/metrics.publisher.d.ts +23 -10
  35. package/dist/core/delivery/metrics.publisher.js +22 -22
  36. package/dist/core/delivery/websocket.events.d.ts +14 -3
  37. package/dist/core/delivery/websocket.events.js +13 -2
  38. package/dist/core/domain/correlation.types.d.ts +37 -0
  39. package/dist/core/domain/correlation.types.js +2 -0
  40. package/dist/core/domain/dashboard.types.d.ts +16 -69
  41. package/dist/core/domain/dashboard.types.js +29 -0
  42. package/dist/core/domain/endpoints.types.d.ts +3 -0
  43. package/dist/core/domain/event.types.d.ts +14 -0
  44. package/dist/core/domain/event.types.js +2 -0
  45. package/dist/core/domain/incident.types.d.ts +50 -0
  46. package/dist/core/domain/incident.types.js +2 -0
  47. package/dist/core/domain/index.d.ts +5 -0
  48. package/dist/core/domain/index.js +5 -0
  49. package/dist/core/domain/live-bucket.types.d.ts +86 -0
  50. package/dist/core/domain/live-bucket.types.js +2 -0
  51. package/dist/core/domain/metrics.types.d.ts +41 -11
  52. package/dist/core/domain/session.types.d.ts +93 -0
  53. package/dist/core/domain/session.types.js +2 -0
  54. package/dist/core/domain/telemetry.types.d.ts +1 -0
  55. package/dist/core/organizers/event.manager.d.ts +19 -0
  56. package/dist/core/organizers/event.manager.js +73 -0
  57. package/dist/core/organizers/index.d.ts +2 -0
  58. package/dist/core/organizers/index.js +18 -0
  59. package/dist/core/organizers/interval.manager.d.ts +18 -0
  60. package/dist/core/organizers/interval.manager.js +54 -0
  61. package/dist/core/storage/index.d.ts +1 -0
  62. package/dist/core/storage/index.js +1 -0
  63. package/dist/core/storage/local.repository.d.ts +12 -12
  64. package/dist/core/storage/local.repository.js +38 -38
  65. package/dist/core/storage/persistence/persistence-writer.d.ts +48 -0
  66. package/dist/core/storage/persistence/persistence-writer.js +191 -0
  67. package/dist/core/storage/persistence/segment-index.d.ts +27 -0
  68. package/dist/core/storage/persistence/segment-index.js +206 -0
  69. package/dist/core/storage/persistence/session-registry.d.ts +28 -0
  70. package/dist/core/storage/persistence/session-registry.js +127 -0
  71. package/dist/core/storage/persistence/session-summary.d.ts +3 -0
  72. package/dist/core/storage/persistence/session-summary.js +112 -0
  73. package/dist/core/storage/persistence.layer.d.ts +69 -0
  74. package/dist/core/storage/persistence.layer.js +404 -0
  75. package/dist/core/storage/runtime/anomaly-detector.d.ts +11 -0
  76. package/dist/core/storage/runtime/anomaly-detector.js +42 -0
  77. package/dist/core/storage/stores/analytics.store.d.ts +5 -5
  78. package/dist/core/storage/stores/analytics.store.js +39 -12
  79. package/dist/core/storage/stores/bucket-metric.d.ts +85 -0
  80. package/dist/core/storage/stores/bucket-metric.js +168 -0
  81. package/dist/core/storage/stores/bucket-view.d.ts +44 -0
  82. package/dist/core/storage/stores/bucket-view.js +63 -0
  83. package/dist/core/storage/stores/bucket.store.d.ts +39 -36
  84. package/dist/core/storage/stores/bucket.store.js +112 -60
  85. package/dist/core/storage/stores/dashboard.store.d.ts +11 -4
  86. package/dist/core/storage/stores/dashboard.store.js +179 -47
  87. package/dist/core/storage/stores/endpoint.store.d.ts +1 -0
  88. package/dist/core/storage/stores/endpoint.store.js +21 -5
  89. package/dist/core/storage/stores/index.d.ts +0 -7
  90. package/dist/core/storage/stores/index.js +0 -7
  91. package/dist/core/storage/stores/metrics.store.d.ts +1 -1
  92. package/dist/core/storage/stores/metrics.store.js +1 -0
  93. package/dist/core/storage/stores/runtime.store.d.ts +77 -0
  94. package/dist/core/storage/stores/runtime.store.js +222 -0
  95. package/dist/core/storage/utility/common.d.ts +1 -0
  96. package/dist/core/storage/utility/common.js +11 -0
  97. package/dist/core/storage/utility/file-buffer.d.ts +31 -0
  98. package/dist/core/storage/utility/file-buffer.js +238 -0
  99. package/dist/core/storage/utility/histogram.d.ts +1 -2
  100. package/dist/core/storage/utility/histogram.js +1 -2
  101. package/dist/core/storage/utility/index.d.ts +2 -0
  102. package/dist/core/storage/utility/index.js +2 -0
  103. package/dist/core/storage/utility/persistence-files.d.ts +3 -0
  104. package/dist/core/storage/utility/persistence-files.js +34 -0
  105. package/dist/core/storage/utility/persistence-writer.d.ts +39 -0
  106. package/dist/core/storage/utility/persistence-writer.js +183 -0
  107. package/dist/core/storage/utility/session-export.d.ts +3 -0
  108. package/dist/core/storage/utility/session-export.js +31 -0
  109. package/dist/core/storage/utility/session-registry.d.ts +21 -0
  110. package/dist/core/storage/utility/session-registry.js +91 -0
  111. package/dist/core/storage/utility/session-window.d.ts +8 -0
  112. package/dist/core/storage/utility/session-window.js +43 -0
  113. package/dist/core/telemetry/analytics.service.d.ts +18 -0
  114. package/dist/core/telemetry/analytics.service.js +100 -0
  115. package/dist/core/telemetry/collector.service.d.ts +17 -15
  116. package/dist/core/telemetry/collector.service.js +23 -80
  117. package/dist/core/telemetry/correlation.service.d.ts +57 -9
  118. package/dist/core/telemetry/correlation.service.js +246 -54
  119. package/dist/core/telemetry/dashboard-live.service.d.ts +10 -0
  120. package/dist/core/telemetry/dashboard-live.service.js +110 -0
  121. package/dist/core/telemetry/dashboard.service.d.ts +20 -0
  122. package/dist/core/telemetry/dashboard.service.js +140 -0
  123. package/dist/core/telemetry/incident.service.d.ts +71 -0
  124. package/dist/core/telemetry/incident.service.js +239 -0
  125. package/dist/core/telemetry/logger.d.ts +4 -0
  126. package/dist/core/telemetry/logger.js +5 -2
  127. package/dist/core/telemetry/runtime.service.d.ts +14 -0
  128. package/dist/core/telemetry/runtime.service.js +56 -0
  129. package/dist/core/telemetry/telemetry-query.service.d.ts +82 -0
  130. package/dist/core/telemetry/telemetry-query.service.js +231 -0
  131. package/dist/core/telemetry/telemetry.service.d.ts +10 -4
  132. package/dist/core/telemetry/telemetry.service.js +60 -10
  133. package/dist/core/telemetry/utility/correlation-analysis.d.ts +9 -0
  134. package/dist/core/telemetry/utility/correlation-analysis.js +143 -0
  135. package/dist/core/telemetry/utility/correlation-finding.d.ts +70 -0
  136. package/dist/core/telemetry/utility/correlation-finding.js +41 -0
  137. package/dist/core/telemetry/utility/correlation-input.d.ts +59 -0
  138. package/dist/core/telemetry/utility/correlation-input.js +139 -0
  139. package/dist/core/telemetry/utility/correlation-replay.d.ts +24 -0
  140. package/dist/core/telemetry/utility/correlation-replay.js +46 -0
  141. package/dist/core/utility/correlation.analysis.d.ts +9 -0
  142. package/dist/core/utility/correlation.analysis.js +144 -0
  143. package/dist/core/utility/statistics.d.ts +65 -0
  144. package/dist/core/utility/statistics.js +141 -0
  145. package/dist/express/index.d.ts +1 -1
  146. package/dist/express/index.js +7 -5
  147. package/dist/express/metrics-websocket.adapter.d.ts +8 -2
  148. package/dist/express/metrics-websocket.adapter.js +52 -17
  149. package/dist/express/metrics.adapter.d.ts +1 -0
  150. package/dist/express/metrics.adapter.js +8 -1
  151. package/dist/express/metrics.bootstrap.d.ts +6 -1
  152. package/dist/express/metrics.bootstrap.js +48 -22
  153. package/dist/express/metrics.dashboard.d.ts +2 -1
  154. package/dist/express/metrics.dashboard.js +4 -1
  155. package/dist/express/metrics.middleware.d.ts +2 -1
  156. package/dist/express/metrics.middleware.js +23 -20
  157. package/dist/nest/metrics-websocket.adapter.d.ts +19 -3
  158. package/dist/nest/metrics-websocket.adapter.js +101 -21
  159. package/dist/nest/metrics.adapter.d.ts +4 -1
  160. package/dist/nest/metrics.adapter.js +24 -1
  161. package/dist/nest/metrics.bootstrap.service.d.ts +7 -3
  162. package/dist/nest/metrics.bootstrap.service.js +56 -21
  163. package/dist/nest/metrics.interceptor.d.ts +3 -3
  164. package/dist/nest/metrics.interceptor.js +11 -8
  165. package/dist/nest/metrics.module.d.ts +3 -0
  166. package/dist/nest/metrics.module.js +27 -9
  167. package/dist/runtime/index.d.ts +32 -0
  168. package/dist/runtime/index.js +104 -0
  169. package/dist/simulation/simulation.d.ts +5 -16
  170. package/dist/simulation/simulation.js +5 -8
  171. package/package.json +2 -1
  172. package/dashboard-out/_next/static/chunks/20t9qbodfrw_z.js +0 -3
  173. package/dashboard-out/_next/static/chunks/23soo6qkun-yv.js +0 -1
  174. package/dashboard-out/_next/static/chunks/3xoopocxi2vi8.css +0 -3
  175. /package/dashboard-out/_next/static/{u8vU2V6fhASeGVCpWU3eW → 17egwqgk36_DSRF55LJZG}/_buildManifest.js +0 -0
  176. /package/dashboard-out/_next/static/{u8vU2V6fhASeGVCpWU3eW → 17egwqgk36_DSRF55LJZG}/_clientMiddlewareManifest.js +0 -0
  177. /package/dashboard-out/_next/static/{u8vU2V6fhASeGVCpWU3eW → 17egwqgk36_DSRF55LJZG}/_ssgManifest.js +0 -0
@@ -1,78 +1,210 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DashboardStore = void 0;
4
+ const bucket_metric_1 = require("./bucket-metric");
5
+ const DASHBOARD_HISTORY_LENGTH = 60;
6
+ const MAX_IMPACT_ENDPOINTS = 10;
7
+ const MAX_ALERTS = 5;
8
+ const IMPACT_P95_THRESHOLD_MS = 500;
4
9
  class DashboardStore {
5
10
  buckets;
6
11
  health;
7
- endpoints;
8
12
  alerts;
9
- constructor(buckets, health, endpoints, alerts) {
13
+ constructor(buckets, health, alerts) {
10
14
  this.buckets = buckets;
11
15
  this.health = health;
12
- this.endpoints = endpoints;
13
16
  this.alerts = alerts;
14
17
  }
15
- get() {
16
- const history = this.buckets.getHistory();
17
- const latest = history[history.length - 1];
18
- const health = this.health.get();
19
- return {
20
- current: {
21
- rps: latest?.rps.count ?? 0,
22
- latency: latest?.latency.average ?? 0,
23
- errorRate: latest?.error.rate ?? 0,
18
+ metrics(bucket) {
19
+ return (0, bucket_metric_1.deriveMetrics)(bucket.requests, bucket.durationMs);
20
+ }
21
+ buildCurrent(latest, health) {
22
+ if (!latest) {
23
+ return {
24
+ rps: 0,
25
+ latency: 0,
26
+ errorRate: 0,
24
27
  eventLoopLag: health.eventLoop.lag,
25
28
  heapUsage: health.memory.heapUsage,
26
29
  heapSize: health.memory.heapSize
30
+ };
31
+ }
32
+ const metrics = this.metrics(latest);
33
+ return {
34
+ rps: Math.round(metrics.rps),
35
+ latency: metrics.averageLatency,
36
+ errorRate: metrics.errorRate,
37
+ eventLoopLag: health.eventLoop.lag,
38
+ heapUsage: health.memory.heapUsage,
39
+ heapSize: health.memory.heapSize
40
+ };
41
+ }
42
+ buildHistory(history) {
43
+ return {
44
+ rps: this.fillRest(history.map(bucket => Math.round(this.metrics(bucket).rps)), DASHBOARD_HISTORY_LENGTH, 0),
45
+ latency: this.fillRest(history.map(bucket => this.metrics(bucket).averageLatency), DASHBOARD_HISTORY_LENGTH, 0),
46
+ errorRate: this.fillRest(history.map(bucket => this.metrics(bucket).errorRate), DASHBOARD_HISTORY_LENGTH, 0),
47
+ eventLoopLag: this.fillRest(history.map(() => this.health.get().eventLoop.lag), DASHBOARD_HISTORY_LENGTH, 0),
48
+ heapUsage: this.fillRest(history.map(() => this.health.get().memory.heapUsage), DASHBOARD_HISTORY_LENGTH, 0),
49
+ heapSize: this.fillRest(history.map(() => this.health.get().memory.heapSize), DASHBOARD_HISTORY_LENGTH, 0),
50
+ rssMemory: this.fillRest(history.map(() => this.health.get().memory.rssMemory), DASHBOARD_HISTORY_LENGTH, 0),
51
+ totalHeap: this.fillRest(history.map(() => this.health.get().memory.heapSize), DASHBOARD_HISTORY_LENGTH, 0),
52
+ p95: this.fillRest(history.map(bucket => this.metrics(bucket).p95), DASHBOARD_HISTORY_LENGTH, 0),
53
+ p99: this.fillRest(history.map(bucket => this.metrics(bucket).p99), DASHBOARD_HISTORY_LENGTH, 0),
54
+ };
55
+ }
56
+ buildHistoryTick(latest) {
57
+ if (!latest) {
58
+ return {
59
+ rps: 0,
60
+ latency: 0,
61
+ errorRate: 0,
62
+ eventLoopLag: this.health.get().eventLoop.lag,
63
+ heapUsage: this.health.get().memory.heapUsage,
64
+ heapSize: this.health.get().memory.heapSize,
65
+ rssMemory: this.health.get().memory.rssMemory,
66
+ totalHeap: this.health.get().memory.heapSize
67
+ };
68
+ }
69
+ const metrics = this.metrics(latest);
70
+ return {
71
+ rps: metrics.rps,
72
+ latency: metrics.averageLatency,
73
+ errorRate: metrics.errorRate,
74
+ eventLoopLag: this.health.get().eventLoop.lag,
75
+ heapUsage: this.health.get().memory.heapUsage,
76
+ heapSize: this.health.get().memory.heapSize,
77
+ rssMemory: this.health.get().memory.rssMemory,
78
+ totalHeap: this.health.get().memory.heapSize
79
+ };
80
+ }
81
+ //! FIX RUNTIME MISSING FROM BUCKETS
82
+ buildCharts(history) {
83
+ const metrics = history.map(bucket => this.metrics(bucket));
84
+ return {
85
+ throughput: {
86
+ rps: this.fillRest(metrics.map(value => value.rps), DASHBOARD_HISTORY_LENGTH, 0),
87
+ errorClient: this.fillRest(metrics.map(value => value.clientErrorCount), DASHBOARD_HISTORY_LENGTH, 0),
88
+ errorServer: this.fillRest(metrics.map(value => value.serverErrorCount), DASHBOARD_HISTORY_LENGTH, 0),
89
+ totalCount: this.getTotalRequestCount(history)
27
90
  },
28
- history: {
29
- rps: history.map(bucket => bucket.rps.count),
30
- latency: history.map(bucket => bucket.latency.average),
31
- errorRate: history.map(bucket => bucket.error.rate),
32
- eventLoopLag: history.map(bucket => bucket.health.eventLoop.lag),
33
- heapUsage: history.map(bucket => bucket.health.memory.heapUsage),
34
- heapSize: history.map(bucket => bucket.health.memory.heapSize),
35
- rssMemory: history.map(bucket => bucket.health.memory.rssMemory),
36
- totalHeap: history.map(bucket => bucket.health.memory.heapSize),
37
- p95: history.map(bucket => bucket.latency.p95),
38
- p99: history.map(bucket => bucket.latency.p99)
91
+ percentiles: {
92
+ p50: this.fillRest(metrics.map(value => value.p50), DASHBOARD_HISTORY_LENGTH, 0),
93
+ p95: this.fillRest(metrics.map(value => value.p95), DASHBOARD_HISTORY_LENGTH, 0),
94
+ p99: this.fillRest(metrics.map(value => value.p99), DASHBOARD_HISTORY_LENGTH, 0),
95
+ totalCount: this.getTotalRequestCount(history)
39
96
  },
40
- charts: {
97
+ runtimePerformance: {
98
+ heapUsage: this.fillRest(metrics.map(value => this.health.get().memory.heapUsage), DASHBOARD_HISTORY_LENGTH, 0),
99
+ heapSize: this.fillRest(metrics.map(value => this.health.get().memory.heapSize), DASHBOARD_HISTORY_LENGTH, 0),
100
+ lag: this.fillRest(metrics.map(value => this.health.get().eventLoop.lag), DASHBOARD_HISTORY_LENGTH, 0),
101
+ totalCount: this.getTotalRequestCount(history)
102
+ }
103
+ };
104
+ }
105
+ buildChartsTick(latest) {
106
+ if (!latest) {
107
+ return {
41
108
  throughput: {
42
- rps: history.map(bucket => bucket.rps.count),
43
- errorClient: history.map(bucket => bucket.error.clientCount),
44
- errorServer: history.map(bucket => bucket.error.serverCount),
45
- totalCount: history.reduce((acc, bucket) => acc + bucket.rps.count, 0)
109
+ rps: 0,
110
+ errorClient: 0,
111
+ errorServer: 0,
112
+ totalCount: 0
46
113
  },
47
114
  percentiles: {
48
- p50: history.map(bucket => bucket.latency.p50),
49
- p95: history.map(bucket => bucket.latency.p95),
50
- p99: history.map(bucket => bucket.latency.p99),
51
- totalCount: history.reduce((acc, bucket) => acc + bucket.rps.count, 0)
115
+ p50: 0,
116
+ p95: 0,
117
+ p99: 0,
118
+ totalCount: 0
52
119
  },
53
120
  runtimePerformance: {
54
- heapUsage: history.map(bucket => bucket.health.memory.heapUsage),
55
- heapSize: history.map(bucket => bucket.health.memory.heapSize),
56
- lag: history.map(bucket => bucket.health.eventLoop.lag),
57
- totalCount: history.reduce((acc, bucket) => acc + bucket.rps.count, 0)
121
+ heapUsage: this.health.get().memory.heapUsage,
122
+ heapSize: this.health.get().memory.heapSize,
123
+ lag: this.health.get().eventLoop.lag,
124
+ totalCount: 0
58
125
  }
126
+ };
127
+ }
128
+ const metrics = this.metrics(latest);
129
+ return {
130
+ throughput: {
131
+ rps: metrics.rps,
132
+ errorClient: metrics.clientErrorCount,
133
+ errorServer: metrics.serverErrorCount,
134
+ totalCount: metrics.requestCount
59
135
  },
136
+ percentiles: {
137
+ p50: metrics.p50,
138
+ p95: metrics.p95,
139
+ p99: metrics.p99,
140
+ totalCount: metrics.requestCount
141
+ },
142
+ runtimePerformance: {
143
+ heapUsage: this.health.get().memory.heapUsage,
144
+ heapSize: this.health.get().memory.heapSize,
145
+ lag: this.health.get().eventLoop.lag,
146
+ totalCount: metrics.requestCount
147
+ }
148
+ };
149
+ }
150
+ get() {
151
+ const history = this.buckets.getHistory();
152
+ const latest = this.buckets.latest();
153
+ const health = this.health.get();
154
+ return {
155
+ current: this.buildCurrent(latest, health),
156
+ history: this.buildHistory(history),
157
+ charts: this.buildCharts(history),
158
+ impactEndpoints: this.getImpactEndpoints(),
159
+ alerts: this.alerts.get(MAX_ALERTS)
160
+ };
161
+ }
162
+ getTickData() {
163
+ const latest = this.buckets.latest();
164
+ const health = this.health.get();
165
+ return {
166
+ current: this.buildCurrent(latest, health),
167
+ history: this.buildHistoryTick(latest),
168
+ charts: this.buildChartsTick(latest),
60
169
  impactEndpoints: this.getImpactEndpoints(),
61
- alerts: this.alerts.get(5)
170
+ alerts: this.alerts.get(MAX_ALERTS)
62
171
  };
63
172
  }
173
+ fillRest(values, length, fillValue) {
174
+ const filledValues = [...values];
175
+ while (filledValues.length < length) {
176
+ filledValues.unshift(fillValue);
177
+ }
178
+ return filledValues;
179
+ }
180
+ getTotalRequestCount(history) {
181
+ return history.reduce((acc, bucket) => acc + bucket.requests.requestCount, 0);
182
+ }
64
183
  getImpactEndpoints() {
65
- return this.endpoints
66
- .all()
67
- .filter(endpoint => {
68
- return (endpoint.errorRate > 0 ||
69
- endpoint.p95 > 500);
184
+ const latest = this.buckets.latest();
185
+ if (!latest)
186
+ return [];
187
+ return latest.endpoints
188
+ .map(endpoint => {
189
+ const metrics = (0, bucket_metric_1.deriveMetrics)(endpoint, latest.durationMs);
190
+ return {
191
+ method: endpoint.method,
192
+ route: endpoint.route,
193
+ rps: metrics.rps,
194
+ requestCount: metrics.requestCount,
195
+ averageLatency: metrics.averageLatency,
196
+ minLatency: metrics.minLatency,
197
+ p95: metrics.p95,
198
+ p99: metrics.p99,
199
+ errorRate: metrics.errorRate,
200
+ status: metrics.errorRate > 0 ? 'DEGRADED' : 'HEALTHY',
201
+ };
70
202
  })
71
- .sort((a, b) => {
72
- const aScore = a.errorRate * 1000 + (a.p95 ?? 0);
73
- const bScore = b.errorRate * 1000 + (b.p95 ?? 0);
74
- return bScore - aScore;
75
- }).slice(0, 10);
203
+ .filter(endpoint => endpoint.errorRate > 0 ||
204
+ endpoint.p95 > IMPACT_P95_THRESHOLD_MS)
205
+ .sort((a, b) => (b.errorRate * 1000 + b.p95) -
206
+ (a.errorRate * 1000 + a.p95))
207
+ .slice(0, MAX_IMPACT_ENDPOINTS);
76
208
  }
77
209
  }
78
210
  exports.DashboardStore = DashboardStore;
@@ -11,6 +11,7 @@ declare class EndpointStore {
11
11
  get(method: string, route: string): EndpointTelemetry | undefined;
12
12
  all(): EndpointTelemetry[];
13
13
  private map;
14
+ private handleTrackingRecord;
14
15
  reset(): void;
15
16
  }
16
17
  export { EndpointStore };
@@ -17,44 +17,60 @@ class EndpointStore {
17
17
  requestCount: 0,
18
18
  errorCount: 0,
19
19
  totalLatency: 0,
20
+ minLatency: input.duration,
20
21
  histogram: new utility_1.Histogram(),
21
22
  lastRequestAt: Date.now(),
23
+ rps: 0,
24
+ lastCalculationRequestCount: 0,
25
+ lastRecalculatedAt: 0,
22
26
  };
23
27
  this.endpoints.set(key, endpoint);
24
28
  }
25
29
  endpoint.requestCount++;
26
30
  endpoint.totalLatency += input.duration;
31
+ endpoint.minLatency = Math.min(endpoint.minLatency, input.duration);
27
32
  endpoint.lastRequestAt = Date.now();
28
33
  endpoint.histogram.record(input.duration);
29
34
  if (input.statusCode >= 400) {
30
35
  endpoint.errorCount++;
31
36
  }
37
+ this.handleTrackingRecord(endpoint, Date.now());
32
38
  }
33
39
  get(method, route) {
34
40
  const endpoint = this.endpoints.get(this.createKey(method, route));
35
41
  if (!endpoint) {
36
42
  return undefined;
37
43
  }
38
- return this.map(endpoint);
44
+ return this.map(endpoint, Date.now());
39
45
  }
40
46
  all() {
41
- return [...this.endpoints.values()].map(endpoint => this.map(endpoint));
47
+ const now = Date.now();
48
+ return [...this.endpoints.values()].map(endpoint => this.map(endpoint, now));
42
49
  }
43
- map(endpoint) {
50
+ map(endpoint, now) {
44
51
  const histogram = endpoint.histogram.snapshot();
52
+ this.handleTrackingRecord(endpoint, now);
45
53
  return {
46
54
  method: endpoint.method,
47
55
  route: endpoint.route,
48
- rps: endpoint.requestCount - histogram.count, //????
49
- // calculated later from buckets
56
+ rps: endpoint.rps,
50
57
  requestCount: endpoint.requestCount,
51
58
  averageLatency: endpoint.requestCount === 0 ? 0 : endpoint.totalLatency / endpoint.requestCount,
59
+ minLatency: endpoint.minLatency,
52
60
  p95: histogram.p95,
53
61
  p99: histogram.p99,
54
62
  errorRate: endpoint.requestCount === 0 ? 0 : endpoint.errorCount / endpoint.requestCount,
55
63
  status: endpoint.errorCount > 0 ? "DEGRADED" : "HEALTHY",
56
64
  };
57
65
  }
66
+ handleTrackingRecord(endpoint, now) {
67
+ if (now - endpoint.lastRecalculatedAt >= 1000) {
68
+ const requestsSinceLastCalculation = endpoint.requestCount - endpoint.lastCalculationRequestCount;
69
+ endpoint.rps = requestsSinceLastCalculation;
70
+ endpoint.lastCalculationRequestCount = endpoint.requestCount;
71
+ endpoint.lastRecalculatedAt = now;
72
+ }
73
+ }
58
74
  reset() {
59
75
  this.endpoints.clear();
60
76
  }
@@ -1,8 +1 @@
1
- export * from './alert.store';
2
- export * from './analytics.store';
3
- export * from './dashboard.store';
4
- export * from './endpoint.store';
5
- export * from './health.store';
6
- export * from './metrics.store';
7
- export * from './system.store';
8
1
  export * from './bucket.store';
@@ -14,11 +14,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./alert.store"), exports);
18
- __exportStar(require("./analytics.store"), exports);
19
- __exportStar(require("./dashboard.store"), exports);
20
- __exportStar(require("./endpoint.store"), exports);
21
- __exportStar(require("./health.store"), exports);
22
- __exportStar(require("./metrics.store"), exports);
23
- __exportStar(require("./system.store"), exports);
24
17
  __exportStar(require("./bucket.store"), exports);
@@ -17,7 +17,7 @@ export declare class MetricsStore {
17
17
  record(input: {
18
18
  duration: number;
19
19
  statusCode: number;
20
- }): "SUCCESS" | "FAILED" | "ANOMALY";
20
+ }): "ANOMALY" | "SUCCESS" | "FAILED";
21
21
  snapshot(): MetricsSnapshot;
22
22
  reset(): void;
23
23
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MetricsStore = void 0;
4
4
  const utility_1 = require("../utility");
5
+ //! This is done
5
6
  class MetricsStore {
6
7
  requestCount;
7
8
  errorClientCount;
@@ -0,0 +1,77 @@
1
+ import type { RuntimeInterval } from './bucket-metric';
2
+ import type { ReadonlyConfig } from '../../../config';
3
+ export interface RuntimeDetails {
4
+ numberOfCores: number;
5
+ perCoreUsage: number[];
6
+ rssMemoryTotal: number;
7
+ externalMemory: number;
8
+ arrayBuffers: number;
9
+ gc: {
10
+ gcCount: number;
11
+ gcTime: number;
12
+ minorGC: {
13
+ runCount: number;
14
+ averageTime: number;
15
+ };
16
+ majorGC: {
17
+ runCount: number;
18
+ averageTime: number;
19
+ };
20
+ incrementalGC: {
21
+ runCount: number;
22
+ averageTime: number;
23
+ };
24
+ heapSpaces: {
25
+ label: string;
26
+ used: number;
27
+ }[];
28
+ gcTotals: {
29
+ totalPauseTime: number;
30
+ freedMemory: number;
31
+ promotions: number;
32
+ tenuredSize: number;
33
+ };
34
+ };
35
+ handles: {
36
+ activeHandles: number;
37
+ activeHandlesTimers: number;
38
+ activeHandlesSockets: number;
39
+ activeLibuvHandles: number;
40
+ timers: number;
41
+ fileDescriptors: number;
42
+ };
43
+ runtime: {
44
+ pid: number;
45
+ platform: NodeJS.Platform;
46
+ nodeVersion: string;
47
+ v8Version: string;
48
+ libuvVersion: string;
49
+ openSSLVersion: string;
50
+ threadPoolSize: number;
51
+ activeThreads: number;
52
+ startup: {
53
+ bootstrapTime: number;
54
+ requiredModules: number;
55
+ };
56
+ };
57
+ }
58
+ export declare class RuntimeStore {
59
+ readonly config: ReadonlyConfig;
60
+ private readonly loopDelay;
61
+ private gcObserver;
62
+ private disposed;
63
+ private lastCpu;
64
+ private intervalGcCount;
65
+ private intervalGcDurationMs;
66
+ private readonly gcTotals;
67
+ private lastCoreTimes;
68
+ constructor(config: ReadonlyConfig);
69
+ private recordGC;
70
+ closeInterval(): RuntimeInterval;
71
+ private collectPerCore;
72
+ private collectGCDetails;
73
+ private collectHandles;
74
+ private collectRuntime;
75
+ details(): RuntimeDetails;
76
+ dispose(): void;
77
+ }
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RuntimeStore = void 0;
7
+ const node_perf_hooks_1 = require("node:perf_hooks");
8
+ const v8_1 = __importDefault(require("v8"));
9
+ const node_os_1 = __importDefault(require("node:os"));
10
+ const utility_1 = require("../../utility");
11
+ class RuntimeStore {
12
+ config;
13
+ loopDelay;
14
+ gcObserver = null;
15
+ disposed = false;
16
+ lastCpu = process.cpuUsage();
17
+ intervalGcCount = 0;
18
+ intervalGcDurationMs = 0;
19
+ gcTotals = {
20
+ gcCount: 0,
21
+ gcTime: 0,
22
+ minorGC: { runCount: 0, totalTime: 0 },
23
+ majorGC: { runCount: 0, totalTime: 0 },
24
+ incrementalGC: { runCount: 0, totalTime: 0 },
25
+ freedMemory: 0
26
+ };
27
+ lastCoreTimes = node_os_1.default.cpus().map(c => ({ ...c.times }));
28
+ constructor(config) {
29
+ this.config = config;
30
+ this.loopDelay = (0, node_perf_hooks_1.monitorEventLoopDelay)({ resolution: config.collection.eventLoopResolutionMs });
31
+ this.loopDelay.enable();
32
+ try {
33
+ this.gcObserver = new node_perf_hooks_1.PerformanceObserver(list => {
34
+ for (const e of list.getEntries())
35
+ this.recordGC(e);
36
+ });
37
+ this.gcObserver.observe({ entryTypes: ['gc'] });
38
+ }
39
+ catch {
40
+ this.gcObserver = null;
41
+ }
42
+ }
43
+ recordGC(e) {
44
+ this.intervalGcCount++;
45
+ this.intervalGcDurationMs += e.duration;
46
+ this.gcTotals.gcCount++;
47
+ this.gcTotals.gcTime += e.duration;
48
+ const detail = e.detail;
49
+ const kind = detail ? detail.kind : 0;
50
+ const bucket = kind === 1 ? this.gcTotals.minorGC
51
+ : kind === 2 ? this.gcTotals.majorGC
52
+ : this.gcTotals.incrementalGC;
53
+ bucket.runCount++;
54
+ bucket.totalTime += e.duration;
55
+ if (detail?.freedMemory)
56
+ this.gcTotals.freedMemory += detail.freedMemory;
57
+ }
58
+ closeInterval() {
59
+ let cpuUserUs = null;
60
+ let cpuSystemUs = null;
61
+ try {
62
+ const now = process.cpuUsage();
63
+ cpuUserUs = now.user - this.lastCpu.user;
64
+ cpuSystemUs = now.system - this.lastCpu.system;
65
+ this.lastCpu = now;
66
+ }
67
+ catch { }
68
+ let heapUsedBytes = null;
69
+ let heapTotalBytes = null;
70
+ let heapLimitBytes = null;
71
+ let rssBytes = null;
72
+ try {
73
+ const memory = process.memoryUsage();
74
+ heapUsedBytes = memory.heapUsed;
75
+ heapTotalBytes = memory.heapTotal;
76
+ rssBytes = memory.rss;
77
+ heapLimitBytes = v8_1.default.getHeapStatistics().heap_size_limit;
78
+ }
79
+ catch { }
80
+ let eventLoopSampleCount = 0;
81
+ let eventLoopDelaySumMs = null;
82
+ let eventLoopDelayMaxMs = null;
83
+ if (!this.disposed) {
84
+ try {
85
+ eventLoopSampleCount = this.loopDelay.count;
86
+ if (eventLoopSampleCount > 0) {
87
+ eventLoopDelaySumMs = (this.loopDelay.mean * eventLoopSampleCount) / 1e6;
88
+ eventLoopDelayMaxMs = this.loopDelay.max / 1e6;
89
+ }
90
+ }
91
+ catch {
92
+ eventLoopSampleCount = 0;
93
+ }
94
+ this.loopDelay.reset();
95
+ }
96
+ const gcCount = this.gcObserver ? this.intervalGcCount : null;
97
+ const gcDurationSumMs = this.gcObserver ? this.intervalGcDurationMs : null;
98
+ this.intervalGcCount = 0;
99
+ this.intervalGcDurationMs = 0;
100
+ return {
101
+ cpuTimeUs: cpuUserUs !== null && cpuSystemUs !== null ? cpuUserUs + cpuSystemUs : null,
102
+ cpuUserUs,
103
+ cpuSystemUs,
104
+ heapUsedBytes,
105
+ heapTotalBytes,
106
+ heapLimitBytes,
107
+ rssBytes,
108
+ eventLoopSampleCount,
109
+ eventLoopDelaySumMs,
110
+ eventLoopDelayMaxMs,
111
+ gcCount,
112
+ gcDurationSumMs,
113
+ };
114
+ }
115
+ collectPerCore() {
116
+ try {
117
+ const cpus = node_os_1.default.cpus();
118
+ const perCoreUsage = cpus.map((core, i) => {
119
+ const prev = this.lastCoreTimes[i];
120
+ const cur = core.times;
121
+ const total = (t) => t.user + t.nice + t.sys + t.idle + t.irq;
122
+ const dTotal = prev ? total(cur) - total(prev) : total(cur);
123
+ const dIdle = prev ? cur.idle - prev.idle : cur.idle;
124
+ return dTotal > 0 ? (0, utility_1.toPercentage)(dTotal - dIdle, dTotal) : 0;
125
+ });
126
+ this.lastCoreTimes = cpus.map(c => ({ ...c.times }));
127
+ return { numberOfCores: cpus.length, perCoreUsage };
128
+ }
129
+ catch {
130
+ return { numberOfCores: 0, perCoreUsage: [] };
131
+ }
132
+ }
133
+ collectGCDetails() {
134
+ const t = this.gcTotals;
135
+ const avg = (k) => k.runCount > 0 ? parseFloat((k.totalTime / k.runCount).toFixed(2)) : 0;
136
+ let heapSpaces = [];
137
+ let tenuredSize = 0;
138
+ try {
139
+ const spaceStats = v8_1.default.getHeapSpaceStatistics();
140
+ heapSpaces = spaceStats.map(space => ({ label: space.space_name, used: space.space_used_size / 1024 / 1024 }));
141
+ const old = spaceStats.find(s => s.space_name === 'old_space');
142
+ tenuredSize = old ? old.space_used_size / 1024 / 1024 : 0;
143
+ }
144
+ catch { }
145
+ return {
146
+ gcCount: t.gcCount,
147
+ gcTime: parseFloat(t.gcTime.toFixed(2)),
148
+ minorGC: { runCount: t.minorGC.runCount, averageTime: avg(t.minorGC) },
149
+ majorGC: { runCount: t.majorGC.runCount, averageTime: avg(t.majorGC) },
150
+ incrementalGC: { runCount: t.incrementalGC.runCount, averageTime: avg(t.incrementalGC) },
151
+ heapSpaces,
152
+ gcTotals: {
153
+ totalPauseTime: parseFloat(t.gcTime.toFixed(2)),
154
+ freedMemory: (0, utility_1.convertBytes)(t.freedMemory, 'MB'),
155
+ promotions: t.majorGC.runCount,
156
+ tenuredSize
157
+ }
158
+ };
159
+ }
160
+ collectHandles() {
161
+ const handles = process._getActiveHandles ? process._getActiveHandles() : [];
162
+ let timers = 0;
163
+ let sockets = 0;
164
+ for (const h of handles) {
165
+ if (h.constructor && h.constructor.name === 'Timeout')
166
+ timers++;
167
+ if (h.constructor && (h.constructor.name === 'Socket' || h.constructor.name === 'TCPSocket'))
168
+ sockets++;
169
+ }
170
+ return {
171
+ activeHandles: handles.length,
172
+ activeHandlesTimers: timers,
173
+ activeHandlesSockets: sockets,
174
+ activeLibuvHandles: handles.length,
175
+ timers,
176
+ fileDescriptors: handles.length
177
+ };
178
+ }
179
+ collectRuntime() {
180
+ const threadPoolSize = process.env.UV_THREADPOOL_SIZE ? parseInt(process.env.UV_THREADPOOL_SIZE) : 4;
181
+ const activeThreads = process._getActiveRequests?.().length ?? 0;
182
+ return {
183
+ pid: process.pid,
184
+ platform: process.platform,
185
+ nodeVersion: process.version,
186
+ v8Version: process.versions.v8,
187
+ libuvVersion: process.versions.uv,
188
+ openSSLVersion: process.versions.openssl,
189
+ threadPoolSize: threadPoolSize,
190
+ activeThreads: activeThreads,
191
+ startup: {
192
+ bootstrapTime: performance.now(),
193
+ requiredModules: Object.keys(require.cache).length,
194
+ }
195
+ };
196
+ }
197
+ details() {
198
+ let memory;
199
+ try {
200
+ const m = process.memoryUsage();
201
+ memory = { rssMemoryTotal: node_os_1.default.totalmem(), externalMemory: m.external, arrayBuffers: m.arrayBuffers };
202
+ }
203
+ catch {
204
+ memory = { rssMemoryTotal: 0, externalMemory: 0, arrayBuffers: 0 };
205
+ }
206
+ return {
207
+ ...this.collectPerCore(),
208
+ ...memory,
209
+ gc: this.collectGCDetails(),
210
+ handles: this.collectHandles(),
211
+ runtime: this.collectRuntime(),
212
+ };
213
+ }
214
+ dispose() {
215
+ if (this.disposed)
216
+ return;
217
+ this.disposed = true;
218
+ this.loopDelay.disable();
219
+ this.gcObserver?.disconnect();
220
+ }
221
+ }
222
+ exports.RuntimeStore = RuntimeStore;
@@ -0,0 +1 @@
1
+ export declare function tryOrDefault<T>(fn: () => Promise<T>, fallback: T): Promise<T>;