apm-optima 0.0.1

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 (131) hide show
  1. package/dist/adapters/http.adapter.d.ts +12 -0
  2. package/dist/adapters/http.adapter.js +2 -0
  3. package/dist/adapters/websocket.adapter.d.ts +5 -0
  4. package/dist/adapters/websocket.adapter.js +2 -0
  5. package/dist/config/config.manager.d.ts +12 -0
  6. package/dist/config/config.manager.js +111 -0
  7. package/dist/config/config.types.d.ts +19 -0
  8. package/dist/config/config.types.js +2 -0
  9. package/dist/config/index.d.ts +2 -0
  10. package/dist/config/index.js +18 -0
  11. package/dist/core/delivery/index.d.ts +2 -0
  12. package/dist/core/delivery/index.js +18 -0
  13. package/dist/core/delivery/metrics.publisher.d.ts +18 -0
  14. package/dist/core/delivery/metrics.publisher.js +36 -0
  15. package/dist/core/delivery/websocket.events.d.ts +12 -0
  16. package/dist/core/delivery/websocket.events.js +16 -0
  17. package/dist/core/domain/common.types.d.ts +44 -0
  18. package/dist/core/domain/common.types.js +20 -0
  19. package/dist/core/domain/dashboard.types.d.ts +108 -0
  20. package/dist/core/domain/dashboard.types.js +2 -0
  21. package/dist/core/domain/endpoints.types.d.ts +43 -0
  22. package/dist/core/domain/endpoints.types.js +2 -0
  23. package/dist/core/domain/index.d.ts +6 -0
  24. package/dist/core/domain/index.js +22 -0
  25. package/dist/core/domain/metrics.types.d.ts +119 -0
  26. package/dist/core/domain/metrics.types.js +2 -0
  27. package/dist/core/domain/system.types.d.ts +51 -0
  28. package/dist/core/domain/system.types.js +2 -0
  29. package/dist/core/domain/telemetry.types.d.ts +8 -0
  30. package/dist/core/domain/telemetry.types.js +2 -0
  31. package/dist/core/storage/index.d.ts +3 -0
  32. package/dist/core/storage/index.js +19 -0
  33. package/dist/core/storage/local.repository.d.ts +17 -0
  34. package/dist/core/storage/local.repository.js +52 -0
  35. package/dist/core/storage/stores/alert.store.d.ts +13 -0
  36. package/dist/core/storage/stores/alert.store.js +71 -0
  37. package/dist/core/storage/stores/analytics.store.d.ts +15 -0
  38. package/dist/core/storage/stores/analytics.store.js +59 -0
  39. package/dist/core/storage/stores/bucket.store.d.ts +40 -0
  40. package/dist/core/storage/stores/bucket.store.js +75 -0
  41. package/dist/core/storage/stores/dashboard.store.d.ts +15 -0
  42. package/dist/core/storage/stores/dashboard.store.js +78 -0
  43. package/dist/core/storage/stores/endpoint.store.d.ts +16 -0
  44. package/dist/core/storage/stores/endpoint.store.js +62 -0
  45. package/dist/core/storage/stores/health.store.d.ts +20 -0
  46. package/dist/core/storage/stores/health.store.js +133 -0
  47. package/dist/core/storage/stores/index.d.ts +8 -0
  48. package/dist/core/storage/stores/index.js +24 -0
  49. package/dist/core/storage/stores/metrics.store.d.ts +23 -0
  50. package/dist/core/storage/stores/metrics.store.js +49 -0
  51. package/dist/core/storage/stores/system.store.d.ts +8 -0
  52. package/dist/core/storage/stores/system.store.js +19 -0
  53. package/dist/core/storage/utility/histogram.d.ts +37 -0
  54. package/dist/core/storage/utility/histogram.js +91 -0
  55. package/dist/core/storage/utility/index.d.ts +2 -0
  56. package/dist/core/storage/utility/index.js +18 -0
  57. package/dist/core/storage/utility/ring-buffer.d.ts +12 -0
  58. package/dist/core/storage/utility/ring-buffer.js +47 -0
  59. package/dist/core/telemetry/collector.service.d.ts +18 -0
  60. package/dist/core/telemetry/collector.service.js +92 -0
  61. package/dist/core/telemetry/collectors/cpu.collector.d.ts +22 -0
  62. package/dist/core/telemetry/collectors/cpu.collector.js +39 -0
  63. package/dist/core/telemetry/collectors/event-loop.collector.d.ts +22 -0
  64. package/dist/core/telemetry/collectors/event-loop.collector.js +27 -0
  65. package/dist/core/telemetry/collectors/gc.collector.d.ts +61 -0
  66. package/dist/core/telemetry/collectors/gc.collector.js +86 -0
  67. package/dist/core/telemetry/collectors/handles.collector.d.ts +20 -0
  68. package/dist/core/telemetry/collectors/handles.collector.js +26 -0
  69. package/dist/core/telemetry/collectors/index.d.ts +6 -0
  70. package/dist/core/telemetry/collectors/index.js +22 -0
  71. package/dist/core/telemetry/collectors/interface.d.ts +3 -0
  72. package/dist/core/telemetry/collectors/interface.js +2 -0
  73. package/dist/core/telemetry/collectors/memory.collector.d.ts +18 -0
  74. package/dist/core/telemetry/collectors/memory.collector.js +24 -0
  75. package/dist/core/telemetry/collectors/runtime.collector.d.ts +32 -0
  76. package/dist/core/telemetry/collectors/runtime.collector.js +29 -0
  77. package/dist/core/telemetry/correlation.service.d.ts +9 -0
  78. package/dist/core/telemetry/correlation.service.js +72 -0
  79. package/dist/core/telemetry/logger.d.ts +11 -0
  80. package/dist/core/telemetry/logger.js +63 -0
  81. package/dist/core/telemetry/telemetry.service.d.ts +10 -0
  82. package/dist/core/telemetry/telemetry.service.js +36 -0
  83. package/dist/core/utility/base-math.d.ts +15 -0
  84. package/dist/core/utility/base-math.js +26 -0
  85. package/dist/core/utility/conversion.d.ts +31 -0
  86. package/dist/core/utility/conversion.js +74 -0
  87. package/dist/core/utility/index.d.ts +4 -0
  88. package/dist/core/utility/index.js +20 -0
  89. package/dist/core/utility/mocking.d.ts +21 -0
  90. package/dist/core/utility/mocking.js +40 -0
  91. package/dist/core/utility/pagination.d.ts +9 -0
  92. package/dist/core/utility/pagination.js +23 -0
  93. package/dist/core/utility/statistics.d.ts +140 -0
  94. package/dist/core/utility/statistics.js +349 -0
  95. package/dist/express/index.d.ts +6 -0
  96. package/dist/express/index.js +22 -0
  97. package/dist/express/metrics-websocket.adapter.d.ts +14 -0
  98. package/dist/express/metrics-websocket.adapter.js +70 -0
  99. package/dist/express/metrics.adapter.d.ts +12 -0
  100. package/dist/express/metrics.adapter.js +31 -0
  101. package/dist/express/metrics.bootstrap.d.ts +2 -0
  102. package/dist/express/metrics.bootstrap.js +35 -0
  103. package/dist/express/metrics.dashboard.d.ts +2 -0
  104. package/dist/express/metrics.dashboard.js +15 -0
  105. package/dist/express/metrics.middleware.d.ts +2 -0
  106. package/dist/express/metrics.middleware.js +29 -0
  107. package/dist/index.d.ts +3 -0
  108. package/dist/index.js +6 -0
  109. package/dist/nest/index.d.ts +4 -0
  110. package/dist/nest/index.js +11 -0
  111. package/dist/nest/metrics-websocket.adapter.d.ts +15 -0
  112. package/dist/nest/metrics-websocket.adapter.js +88 -0
  113. package/dist/nest/metrics.adapter.d.ts +12 -0
  114. package/dist/nest/metrics.adapter.js +33 -0
  115. package/dist/nest/metrics.bootstrap.service.d.ts +13 -0
  116. package/dist/nest/metrics.bootstrap.service.js +66 -0
  117. package/dist/nest/metrics.interceptor.d.ts +11 -0
  118. package/dist/nest/metrics.interceptor.js +57 -0
  119. package/dist/nest/metrics.module.d.ts +6 -0
  120. package/dist/nest/metrics.module.js +74 -0
  121. package/dist/simulation/config.d.ts +20 -0
  122. package/dist/simulation/config.js +54 -0
  123. package/dist/simulation/journey.d.ts +7 -0
  124. package/dist/simulation/journey.js +49 -0
  125. package/dist/simulation/scenarios.d.ts +17 -0
  126. package/dist/simulation/scenarios.js +96 -0
  127. package/dist/simulation/simulation.d.ts +24 -0
  128. package/dist/simulation/simulation.js +154 -0
  129. package/dist/simulation/utility.d.ts +23 -0
  130. package/dist/simulation/utility.js +50 -0
  131. package/package.json +71 -0
@@ -0,0 +1,349 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hash = hash;
4
+ exports.rate = rate;
5
+ exports.mean = mean;
6
+ exports.percentile = percentile;
7
+ exports.percentileHistogram = percentileHistogram;
8
+ exports.median = median;
9
+ exports.calculateSampleSizeProportion = calculateSampleSizeProportion;
10
+ exports.pearsonCorrelation = pearsonCorrelation;
11
+ exports.spearmanCorrelation = spearmanCorrelation;
12
+ exports.determinationAndAlienation = determinationAndAlienation;
13
+ exports.standardDeviation = standardDeviation;
14
+ exports.standardDeviationHistogram = standardDeviationHistogram;
15
+ exports.zScore = zScore;
16
+ exports.zScoreHistogram = zScoreHistogram;
17
+ exports.isDataAnomaly = isDataAnomaly;
18
+ exports.isDataAnomalyHistogram = isDataAnomalyHistogram;
19
+ /**
20
+ * Generates a hash code for a given value. This function converts the value to a JSON string and computes a hash code based on its characters.
21
+ * @param value The value to be hashed. It can be of any type that can be serialized to JSON.
22
+ * @returns The hash code for the given value.
23
+ */
24
+ function hash(value) {
25
+ const str = JSON.stringify(value);
26
+ let hash = 0;
27
+ for (let i = 0; i < str.length; i++) {
28
+ const char = str.charCodeAt(i);
29
+ hash = (hash << 5) - hash + char;
30
+ hash |= 0; // Convert to 32bit integer
31
+ }
32
+ return hash;
33
+ }
34
+ /**
35
+ * Calculates the rate as a percentage of accounted over total.
36
+ * @param accounted The number of items accounted for.
37
+ * @param total The total number of items.
38
+ * @returns The rate as a percentage.
39
+ */
40
+ function rate(accounted, total) {
41
+ if (total === 0)
42
+ return 0;
43
+ return (accounted / total) * 100;
44
+ }
45
+ /**
46
+ * Calculates the mean (average) of a dataset.
47
+ * @param data - An array of numbers representing the dataset.
48
+ * @returns The mean of the dataset.
49
+ */
50
+ function mean(data) {
51
+ if (data.length === 0)
52
+ return 0;
53
+ const sum = data.reduce((acc, val) => acc + val, 0);
54
+ return sum / data.length;
55
+ }
56
+ /**
57
+ * Calculates the specified percentile of a dataset. (e.g., p95, p99)
58
+ * @param data - An array of numbers representing the dataset.
59
+ * @param percentile - The desired percentile (between 0 and 1, e.g., 0.95 for p95).
60
+ * @returns The value at the specified percentile of the dataset.
61
+ */
62
+ function percentile(data, percentile) {
63
+ if (data.length === 0)
64
+ return 0;
65
+ if (percentile >= 1)
66
+ return Math.max(...data);
67
+ else if (percentile <= 0)
68
+ return Math.min(...data);
69
+ const sorted = [...data].sort((a, b) => a - b);
70
+ const index = percentile * (sorted.length - 1);
71
+ const lower = Math.floor(index);
72
+ const upper = Math.ceil(index);
73
+ if (lower === upper) {
74
+ return sorted[lower];
75
+ }
76
+ return sorted[lower] + (sorted[upper] - sorted[lower]) * (index - lower);
77
+ }
78
+ /**
79
+ * Calculates the specified percentile of a histogram represented by counters and limits.
80
+ * This function is useful for determining latency percentiles from histogram data.
81
+ * @param counters An array of counts representing the number of occurrences in each histogram bucket.
82
+ * @param totalCount The total number of occurrences across all histogram buckets.
83
+ * @param percentile The desired percentile (between 0 and 1, e.g., 0.95 for p95).
84
+ * @param limits An array of upper limits for each histogram bucket, corresponding to the counters.
85
+ * @returns The value at the specified percentile of the histogram.
86
+ */
87
+ function percentileHistogram(counters, totalCount, percentile, limits) {
88
+ if (totalCount === 0)
89
+ return 0;
90
+ if (percentile >= 1) {
91
+ const last = limits[limits.length - 1];
92
+ return Number.isFinite(last) ? last : 0;
93
+ }
94
+ else if (percentile <= 0) {
95
+ const first = limits[0];
96
+ return Number.isFinite(first) ? first : 0;
97
+ }
98
+ const target = totalCount * percentile;
99
+ let cumulative = 0;
100
+ for (let i = 0; i < counters.length; i++) {
101
+ const previous = cumulative;
102
+ cumulative += counters[i];
103
+ if (cumulative >= target) {
104
+ const lower = i === 0 ? 0 : limits[i - 1];
105
+ const upper = Number.isFinite(limits[i]) ? limits[i] : lower;
106
+ if (upper === lower)
107
+ return upper;
108
+ const bucketCount = cumulative - previous;
109
+ const bucketPosition = bucketCount === 0
110
+ ? 0
111
+ : (target - previous) / bucketCount;
112
+ return lower + (upper - lower) * bucketPosition;
113
+ }
114
+ }
115
+ return limits[limits.length - 1];
116
+ }
117
+ /**
118
+ * Calculates the median (p50) of a dataset.
119
+ * @param data - An array of numbers representing the dataset.
120
+ * @returns The median of the dataset.
121
+ */
122
+ function median(data) {
123
+ if (data.length === 0)
124
+ return 0;
125
+ const sorted = [...data].sort((a, b) => a - b);
126
+ const mid = Math.floor(sorted.length / 2);
127
+ if (sorted.length % 2 === 0) {
128
+ return (sorted[mid - 1] + sorted[mid]) / 2;
129
+ }
130
+ else {
131
+ return sorted[mid];
132
+ }
133
+ }
134
+ /**
135
+ * Calculates the inverse of the standard normal cumulative distribution function (CDF).
136
+ * @param p The probability value (between 0 and 1) for which to calculate the inverse CDF.
137
+ * @returns The z-score corresponding to the given probability value.
138
+ */
139
+ function normsinv(p) {
140
+ if (p <= 0 || p >= 1)
141
+ return 0;
142
+ const t = Math.sqrt(-2.0 * Math.log(p < 0.5 ? p : 1.0 - p));
143
+ const c0 = 2.515517, c1 = 0.802853, c2 = 0.010328;
144
+ const d1 = 1.432788, d2 = 0.189269, d3 = 0.001308;
145
+ const index = t - ((c2 * t + c1) * t + c0) / (((d3 * t + d2) * t + d1) * t + 1.0);
146
+ return p < 0.5 ? -index : index;
147
+ }
148
+ /**
149
+ * Calculates the required sample size for estimating a population proportion with a specified margin of error and confidence level.
150
+ * The formula used is based on the normal approximation to the binomial distribution.
151
+ * @param marginOfError The desired margin of error (e.g., 0.05 for ±5%).
152
+ * @param confidenceLevel The desired confidence level (default is 0.95 for 95% confidence).
153
+ * @returns The required sample size to achieve the specified margin of error and confidence level.
154
+ */
155
+ function calculateSampleSizeProportion(marginOfError, confidenceLevel = 0.95) {
156
+ const alpha = 1 - confidenceLevel;
157
+ const z = normsinv(1 - (alpha / 2));
158
+ const p = 0.5;
159
+ const n = (Math.pow(z, 2) * p * (1 - p)) / Math.pow(marginOfError, 2);
160
+ return Math.ceil(n);
161
+ }
162
+ /**
163
+ * Calculates the Pearson correlation coefficient (r) between two datasets.
164
+ * The correlation coefficient measures the strength and direction of the linear relationship between two variables.
165
+ * The value of r ranges from -1 to 1, where:
166
+ * - r = 1 indicates a perfect positive correlation,
167
+ * - r = -1 indicates a perfect negative correlation,
168
+ * - r = 0 indicates no correlation.
169
+ *
170
+ * The function also provides an interpretation of the correlation strength and assigns a color class for visualization purposes.
171
+ * @param x The first dataset (X values) as an array of numbers.
172
+ * @param y The second dataset (Y values) as an array of numbers.
173
+ * @returns The Pearson correlation coefficient (r).
174
+ */
175
+ function pearsonCorrelation(x, y) {
176
+ if (x.length !== y.length || x.length === 0)
177
+ return 0;
178
+ const n = x.length;
179
+ const meanX = x.reduce((a, b) => a + b, 0) / n;
180
+ const meanY = y.reduce((a, b) => a + b, 0) / n;
181
+ let numerator = 0;
182
+ let denominatorX = 0;
183
+ let denominatorY = 0;
184
+ for (let i = 0; i < n; i++) {
185
+ const diffX = x[i] - meanX;
186
+ const diffY = y[i] - meanY;
187
+ numerator += diffX * diffY;
188
+ denominatorX += diffX * diffX;
189
+ denominatorY += diffY * diffY;
190
+ }
191
+ const denominator = Math.sqrt(denominatorX * denominatorY);
192
+ return denominator === 0 ? 0 : numerator / denominator;
193
+ }
194
+ /**
195
+ * Calculates the ranks of the elements in an array. The rank of an element is its position in the sorted order of the array, with ties receiving the average rank.
196
+ * For example, in the array [3, 1, 2], the ranks would be [3, 1, 2] because 1 is the smallest (rank 1), 2 is the second smallest (rank 2), and 3 is the largest (rank 3).
197
+ * In the case of ties, such as in the array [3, 1, 2, 2], the ranks would be [4, 1, 2.5, 2.5] because both occurrences of 2 share the average rank of (2 + 3) / 2 = 2.5.
198
+ * @param arr An array of numbers for which to calculate the ranks.
199
+ * @returns An array of ranks corresponding to the input array, where each rank indicates the position of the element in the sorted order.
200
+ */
201
+ function getRanks(arr) {
202
+ const sorted = [...arr].map((val, ind) => ({ val, ind })).sort((a, b) => a.val - b.val);
203
+ const ranks = new Array(arr.length);
204
+ let i = 0;
205
+ while (i < sorted.length) {
206
+ let j = i;
207
+ while (j < sorted.length && sorted[j].val === sorted[i].val) {
208
+ j++;
209
+ }
210
+ const rank = (i + 1 + j) / 2;
211
+ for (let k = i; k < j; k++) {
212
+ ranks[sorted[k].ind] = rank;
213
+ }
214
+ i = j;
215
+ }
216
+ return ranks;
217
+ }
218
+ /**
219
+ * Calculates the Spearman rank correlation coefficient (ρ) between two datasets.
220
+ * @param x An array of numbers representing the first dataset.
221
+ * @param y An array of numbers representing the second dataset.
222
+ * @returns The Spearman rank correlation coefficient (ρ).
223
+ */
224
+ function spearmanCorrelation(x, y) {
225
+ if (x.length !== y.length || x.length === 0)
226
+ return 0;
227
+ const n = x.length;
228
+ const ranksX = getRanks(x);
229
+ const ranksY = getRanks(y);
230
+ const meanRX = ranksX.reduce((a, b) => a + b, 0) / n;
231
+ const meanRY = ranksY.reduce((a, b) => a + b, 0) / n;
232
+ let numeratorS = 0;
233
+ let denomSX = 0;
234
+ let denomSY = 0;
235
+ for (let i = 0; i < n; i++) {
236
+ const diffRX = ranksX[i] - meanRX;
237
+ const diffRY = ranksY[i] - meanRY;
238
+ numeratorS += diffRX * diffRY;
239
+ denomSX += diffRX * diffRX;
240
+ denomSY += diffRY * diffRY;
241
+ }
242
+ const denomS = Math.sqrt(denomSX * denomSY);
243
+ const spearmanR = denomS === 0 ? 0 : numeratorS / denomS;
244
+ return spearmanR;
245
+ }
246
+ /**
247
+ * Calculates the coefficient of determination (R²) and the coefficient of alienation (1 - R²) based on the Pearson correlation coefficient (r).
248
+ * The coefficient of determination (R²) indicates the proportion of the variance in the dependent variable that is predictable from the independent variable.
249
+ * The coefficient of alienation (1 - R²) indicates the proportion of the variance that is not explained by the model.
250
+ *
251
+ * @param pearsonR The Pearson correlation coefficient (r) between two datasets.
252
+ * @returns An object containing the coefficient of determination (R²) and the coefficient of alienation (1 - R²).
253
+ */
254
+ function determinationAndAlienation(pearsonR) {
255
+ const determination = pearsonR * pearsonR;
256
+ const alienation = 1 - determination;
257
+ return { determination, alienation };
258
+ }
259
+ /**
260
+ * Calculates the standard deviation of a dataset.
261
+ * The standard deviation is a measure of the amount of variation or dispersion in a set of values.
262
+ * @param data An array of numbers representing the dataset.
263
+ * @returns The standard deviation of the dataset.
264
+ */
265
+ function standardDeviation(data) {
266
+ if (data.length === 0)
267
+ return 0;
268
+ const mu = mean(data);
269
+ const variance = data.reduce((acc, val) => acc + (val - mu) ** 2, 0) / data.length;
270
+ return Math.sqrt(variance);
271
+ }
272
+ /**
273
+ * Calculates the standard deviation from histogram data.
274
+ * The standard deviation is a measure of the amount of variation or dispersion in a set of values.
275
+ * This function uses the total count, total sum, and total sum of squares to compute the standard deviation.
276
+ * @param totalCount The total number of occurrences across all histogram buckets.
277
+ * @param totalSum The total sum of all values across the histogram buckets.
278
+ * @param totalSumOfSquares The total sum of squares of all values across the histogram buckets.
279
+ * @returns The standard deviation of the histogram data.
280
+ */
281
+ function standardDeviationHistogram(totalCount, totalSum, totalSumOfSquares) {
282
+ if (totalCount === 0)
283
+ return 0;
284
+ const mean = totalSum / totalCount;
285
+ const variance = (totalSumOfSquares / totalCount) - (mean ** 2);
286
+ return Math.sqrt(Math.max(0, variance));
287
+ }
288
+ /**
289
+ * Calculates the z-score for a given value based on the mean and standard deviation of a dataset.
290
+ * The z-score indicates how many standard deviations a value is from the mean.
291
+ * A positive z-score indicates the value is above the mean, while a negative z-score indicates it is below the mean.
292
+ * @param value The value for which the z-score is to be calculated.
293
+ * @param data An array of numbers representing the dataset.
294
+ * @returns The z-score of the value. If the dataset is empty or has zero standard deviation, the function returns 0.
295
+ */
296
+ function zScore(value, data) {
297
+ if (data.length === 0)
298
+ return 0;
299
+ const mu = mean(data);
300
+ const sigma = standardDeviation(data);
301
+ if (sigma === 0)
302
+ return 0;
303
+ return (value - mu) / sigma;
304
+ }
305
+ /**
306
+ * Calculates the z-score for a given value based on histogram data.
307
+ * The z-score indicates how many standard deviations a value is from the mean.
308
+ * A positive z-score indicates the value is above the mean, while a negative z-score indicates it is below the mean.
309
+ * @param value The value for which the z-score is to be calculated.
310
+ * @param totalCount The total number of occurrences across all histogram buckets.
311
+ * @param totalSum The total sum of all values across the histogram buckets.
312
+ * @param totalSumOfSquares The total sum of squares of all values across the histogram buckets.
313
+ * @returns The z-score of the value. If the histogram is empty or has zero standard deviation, the function returns 0.
314
+ */
315
+ function zScoreHistogram(value, totalCount, totalSum, totalSumOfSquares) {
316
+ if (totalCount === 0)
317
+ return 0;
318
+ const mu = totalSum / totalCount;
319
+ const sigma = standardDeviationHistogram(totalCount, totalSum, totalSumOfSquares);
320
+ if (sigma === 0)
321
+ return 0;
322
+ return (value - mu) / sigma;
323
+ }
324
+ /**
325
+ * Determines if a given value is an anomaly based on its z-score relative to a dataset.
326
+ * A value is considered an anomaly if its z-score exceeds the specified threshold.
327
+ * @param value The value to be evaluated for anomaly detection.
328
+ * @param data An array of numbers representing the dataset against which the value is compared.
329
+ * @param threshold The z-score threshold beyond which a value is considered an anomaly. Default is 3.
330
+ * @returns A boolean indicating whether the value is an anomaly (true) or not (false).
331
+ */
332
+ function isDataAnomaly(value, data, threshold = 3) {
333
+ const z = zScore(value, data);
334
+ return Math.abs(z) > threshold;
335
+ }
336
+ /**
337
+ * Determines if a given value is an anomaly based on its z-score relative to histogram data.
338
+ * A value is considered an anomaly if its z-score exceeds the specified threshold.
339
+ * @param value The value to be evaluated for anomaly detection.
340
+ * @param totalCount The total number of occurrences across all histogram buckets.
341
+ * @param totalSum The total sum of all values across the histogram buckets.
342
+ * @param totalSumOfSquares The total sum of squares of all values across the histogram buckets.
343
+ * @param threshold The z-score threshold beyond which a value is considered an anomaly. Default is 3.
344
+ * @returns A boolean indicating whether the value is an anomaly (true) or not (false).
345
+ */
346
+ function isDataAnomalyHistogram(value, totalCount, totalSum, totalSumOfSquares, threshold = 3) {
347
+ const z = zScoreHistogram(value, totalCount, totalSum, totalSumOfSquares);
348
+ return Math.abs(z) > threshold;
349
+ }
@@ -0,0 +1,6 @@
1
+ import express from 'express';
2
+ import { Server as HTTPServer } from 'http';
3
+ import { type ConfigOptions } from '../config';
4
+ export declare function setupOptima(app: express.Express, options?: ConfigOptions): {
5
+ attachServer: (server: HTTPServer) => () => void;
6
+ };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupOptima = setupOptima;
4
+ const config_1 = require("../config");
5
+ const metrics_middleware_1 = require("./metrics.middleware");
6
+ const metrics_dashboard_1 = require("./metrics.dashboard");
7
+ const metrics_bootstrap_1 = require("./metrics.bootstrap");
8
+ function setupOptima(app, options) {
9
+ config_1.ConfigManager.getInstance().initialize(options);
10
+ const config = config_1.ConfigManager.getInstance().get();
11
+ // Registering the metrics middleware
12
+ app.use(metrics_middleware_1.expressMetricsMiddleware);
13
+ // Attaching the dashboard on provided path
14
+ if (config.dashboardPath !== false) {
15
+ (0, metrics_dashboard_1.attachDashboard)(app, config.dashboardPath);
16
+ }
17
+ return {
18
+ attachServer: (server) => {
19
+ return (0, metrics_bootstrap_1.expressMetricsBootstrap)(server);
20
+ }
21
+ };
22
+ }
@@ -0,0 +1,14 @@
1
+ import type { Server as HTTPServer } from 'http';
2
+ import type { WebSocketAdapter } from '../adapters/websocket.adapter';
3
+ import { type MetricsDataProvider } from '../core/delivery';
4
+ export declare class ExpressWebSocketAdapter implements WebSocketAdapter {
5
+ private readonly server;
6
+ private readonly provider;
7
+ private io?;
8
+ constructor(server: HTTPServer, provider: MetricsDataProvider);
9
+ init(): void;
10
+ private setupEvents;
11
+ private setupClient;
12
+ broadcast(event: string, data: unknown): void;
13
+ disconnect(): void;
14
+ }
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExpressWebSocketAdapter = void 0;
4
+ const socket_io_1 = require("socket.io");
5
+ const delivery_1 = require("../core/delivery");
6
+ const config_1 = require("../config");
7
+ class ExpressWebSocketAdapter {
8
+ server;
9
+ provider;
10
+ io;
11
+ constructor(server, provider) {
12
+ this.server = server;
13
+ this.provider = provider;
14
+ }
15
+ init() {
16
+ if (this.io) {
17
+ console.warn('[Optima] WebSocket server is already initialized.');
18
+ return;
19
+ }
20
+ this.io = new socket_io_1.Server(this.server, {
21
+ transports: ['websocket'],
22
+ maxHttpBufferSize: 1e8, // 100MB
23
+ pingTimeout: 10000, // 10 seconds
24
+ pingInterval: 25000, // 25 seconds
25
+ cors: {
26
+ origin: '*',
27
+ methods: ['GET', 'POST'],
28
+ },
29
+ });
30
+ console.log('[Optima] WebSocket server initialized successfully.');
31
+ this.setupEvents();
32
+ }
33
+ setupEvents() {
34
+ if (!this.io)
35
+ return;
36
+ console.log('[Optima] Setting up WebSocket event bindings.');
37
+ this.io.on('connection', socket => {
38
+ console.log(`[Optima] New WebSocket connection: ${socket.id}`);
39
+ this.setupClient(socket);
40
+ });
41
+ }
42
+ setupClient(socket) {
43
+ socket.on(delivery_1.WebSocketEvents.REQUEST_CONFIGURATION, () => {
44
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_CONFIGURATION, config_1.ConfigManager.getInstance().get());
45
+ });
46
+ socket.on(delivery_1.WebSocketEvents.REQUEST_SYSTEM_DATA, () => {
47
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_SYSTEM_DATA, this.provider.getSystemStaticInfo());
48
+ });
49
+ socket.on(delivery_1.WebSocketEvents.REQUEST_DASHBOARD_DATA, () => {
50
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_DASHBOARD_DATA, this.provider.getDashboardData());
51
+ });
52
+ socket.on(delivery_1.WebSocketEvents.REQUEST_ANALYTICS_DATA, () => {
53
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_ANALYTICS_DATA, this.provider.getAnalyticsData());
54
+ });
55
+ socket.on(delivery_1.WebSocketEvents.REQUEST_HEALTH_DATA, () => {
56
+ socket.emit(delivery_1.WebSocketEvents.RESPONSE_HEALTH_DATA, this.provider.getHealthData());
57
+ });
58
+ socket.on('disconnect', () => {
59
+ console.log(`[Optima] WebSocket disconnected: ${socket.id}`);
60
+ });
61
+ }
62
+ broadcast(event, data) {
63
+ this.io?.emit(event, data);
64
+ }
65
+ disconnect() {
66
+ this.io?.close();
67
+ this.io = undefined;
68
+ }
69
+ }
70
+ exports.ExpressWebSocketAdapter = ExpressWebSocketAdapter;
@@ -0,0 +1,12 @@
1
+ import type { Request, Response } from 'express';
2
+ import type { HttpAdapter } from '../adapters/http.adapter';
3
+ export declare class ExpressAdapter implements HttpAdapter<Request, Response> {
4
+ getRequest(request: Request): {
5
+ method: string;
6
+ endpoint: string;
7
+ clientIp: string | undefined;
8
+ };
9
+ getResponse(response: Response): {
10
+ statusCode: number;
11
+ };
12
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExpressAdapter = void 0;
4
+ class ExpressAdapter {
5
+ getRequest(request) {
6
+ const { body, // Parsed JSON or form data
7
+ params, // Route path variables
8
+ query, // URL query string parameters
9
+ headers, // HTTP request headers
10
+ cookies, // Parsed client browser cookies
11
+ method, // Executed HTTP verb (GET, POST, etc.)
12
+ path, // Requested URL path string
13
+ ip, // Remote client IP address
14
+ secure, // Boolean for TLS connection status
15
+ url, // Full requested URL string
16
+ } = request;
17
+ return {
18
+ method,
19
+ endpoint: path,
20
+ clientIp: ip,
21
+ };
22
+ }
23
+ getResponse(response) {
24
+ const { locals, // Request-scoped middleware variables
25
+ headersSent, // Boolean tracking sent HTTP headers
26
+ statusCode, // Current HTTP status code
27
+ } = response;
28
+ return { statusCode };
29
+ }
30
+ }
31
+ exports.ExpressAdapter = ExpressAdapter;
@@ -0,0 +1,2 @@
1
+ import { Server as HTTPServer } from 'http';
2
+ export declare function expressMetricsBootstrap(server: HTTPServer): () => void;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.expressMetricsBootstrap = expressMetricsBootstrap;
4
+ const metrics_websocket_adapter_1 = require("./metrics-websocket.adapter");
5
+ const collector_service_1 = require("../core/telemetry/collector.service");
6
+ const simulation_1 = require("../simulation/simulation");
7
+ const delivery_1 = require("../core/delivery");
8
+ const correlation_service_1 = require("../core/telemetry/correlation.service");
9
+ const config_1 = require("../config");
10
+ function expressMetricsBootstrap(server) {
11
+ const config = (0, config_1.getConfig)();
12
+ let simulator = null;
13
+ if (config.simulation) {
14
+ simulator = new simulation_1.TrafficSimulator();
15
+ simulator.start({
16
+ intervalMs: config.simulation.intervalMs,
17
+ requestsPerTick: config.simulation.requestsPerTick,
18
+ });
19
+ }
20
+ const websocket = new metrics_websocket_adapter_1.ExpressWebSocketAdapter(server, collector_service_1.collectorService);
21
+ websocket.init();
22
+ const publisher = new delivery_1.MetricsPublisher(collector_service_1.collectorService, websocket, config.publisher.intervalMs);
23
+ publisher.start();
24
+ const tickInterval = setInterval(() => {
25
+ collector_service_1.collectorService.tick();
26
+ correlation_service_1.correlationService.tick();
27
+ }, config.tickIntervalMs);
28
+ console.log('[Optima] Uspešno inicijalizovani svi podsistemi monitoringa.');
29
+ return () => {
30
+ simulator?.stop();
31
+ publisher.stop();
32
+ clearInterval(tickInterval);
33
+ websocket.disconnect();
34
+ };
35
+ }
@@ -0,0 +1,2 @@
1
+ import express from 'express';
2
+ export declare function attachDashboard(app: express.Express, routePath?: string): void;
@@ -0,0 +1,15 @@
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.attachDashboard = attachDashboard;
7
+ const express_1 = __importDefault(require("express"));
8
+ const path_1 = __importDefault(require("path"));
9
+ function attachDashboard(app, routePath = '/dashboard') {
10
+ const staticAssetsPath = path_1.default.resolve(__dirname, '../../../dashboard/out');
11
+ app.use(routePath, express_1.default.static(staticAssetsPath));
12
+ app.get(`${routePath}/*`, (req, res) => {
13
+ res.sendFile(path_1.default.join(staticAssetsPath, 'index.html'));
14
+ });
15
+ }
@@ -0,0 +1,2 @@
1
+ import type { RequestHandler } from 'express';
2
+ export declare const expressMetricsMiddleware: RequestHandler;
@@ -0,0 +1,29 @@
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.expressMetricsMiddleware = void 0;
7
+ const telemetry_service_1 = __importDefault(require("../core/telemetry/telemetry.service"));
8
+ const logger_1 = __importDefault(require("../core/telemetry/logger"));
9
+ const metrics_adapter_1 = require("./metrics.adapter");
10
+ const telemetryService = new telemetry_service_1.default();
11
+ const adapter = new metrics_adapter_1.ExpressAdapter();
12
+ const expressMetricsMiddleware = (req, res, next) => {
13
+ const startHrTime = process.hrtime.bigint();
14
+ res.on('finish', () => {
15
+ const requestData = adapter.getRequest(req);
16
+ const responseData = adapter.getResponse(res);
17
+ const telemetryRequest = telemetryService.record({
18
+ endpoint: requestData.endpoint,
19
+ method: requestData.method,
20
+ statusCode: responseData.statusCode,
21
+ clientIp: requestData.clientIp
22
+ }, startHrTime);
23
+ if (telemetryRequest !== null) {
24
+ logger_1.default.log(req, res, telemetryRequest.responseTime);
25
+ }
26
+ });
27
+ next();
28
+ };
29
+ exports.expressMetricsMiddleware = expressMetricsMiddleware;
@@ -0,0 +1,3 @@
1
+ export type { HttpAdapter, RequestRequiredData, ResponseRequiredData } from './adapters/http.adapter';
2
+ export type { WebSocketAdapter } from './adapters/websocket.adapter';
3
+ export declare function getHelloMetrics(): string;
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getHelloMetrics = getHelloMetrics;
4
+ function getHelloMetrics() {
5
+ return "Metrics Pack is greeting you!";
6
+ }
@@ -0,0 +1,4 @@
1
+ export { MetricsInterceptor } from './metrics.interceptor';
2
+ export { MetricsModule } from './metrics.module';
3
+ export { NestAdapter } from './metrics.adapter';
4
+ export { NestWebSocketAdapter } from './metrics-websocket.adapter';
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NestWebSocketAdapter = exports.NestAdapter = exports.MetricsModule = exports.MetricsInterceptor = void 0;
4
+ var metrics_interceptor_1 = require("./metrics.interceptor");
5
+ Object.defineProperty(exports, "MetricsInterceptor", { enumerable: true, get: function () { return metrics_interceptor_1.MetricsInterceptor; } });
6
+ var metrics_module_1 = require("./metrics.module");
7
+ Object.defineProperty(exports, "MetricsModule", { enumerable: true, get: function () { return metrics_module_1.MetricsModule; } });
8
+ var metrics_adapter_1 = require("./metrics.adapter");
9
+ Object.defineProperty(exports, "NestAdapter", { enumerable: true, get: function () { return metrics_adapter_1.NestAdapter; } });
10
+ var metrics_websocket_adapter_1 = require("./metrics-websocket.adapter");
11
+ Object.defineProperty(exports, "NestWebSocketAdapter", { enumerable: true, get: function () { return metrics_websocket_adapter_1.NestWebSocketAdapter; } });
@@ -0,0 +1,15 @@
1
+ import { OnGatewayConnection, OnGatewayDisconnect } from '@nestjs/websockets';
2
+ import type { Socket } from 'socket.io';
3
+ import type { WebSocketAdapter } from '../adapters/websocket.adapter';
4
+ export declare class NestWebSocketAdapter implements WebSocketAdapter, OnGatewayConnection, OnGatewayDisconnect {
5
+ private server;
6
+ init(): void;
7
+ handleConnection(socket: Socket): void;
8
+ handleDisconnect(socket: Socket): void;
9
+ handleSystemData(socket: Socket): void;
10
+ handleDashboardData(socket: Socket): void;
11
+ handleAnalyticsData(socket: Socket): void;
12
+ handleHealthData(socket: Socket): void;
13
+ broadcast(event: string, data: unknown): void;
14
+ disconnect(): void;
15
+ }