apm-optima 1.0.5 → 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.
- package/README.md +54 -23
- package/dashboard-out/404/index.html +1 -1
- package/dashboard-out/404.html +1 -1
- package/dashboard-out/__next.__PAGE__.txt +4 -4
- package/dashboard-out/__next._full.txt +17 -17
- package/dashboard-out/__next._head.txt +4 -4
- package/dashboard-out/__next._index.txt +10 -10
- package/dashboard-out/__next._tree.txt +2 -2
- package/dashboard-out/_next/static/chunks/{2xjcsu4pgp14_.js → 062oipeclh9bq.js} +1 -1
- package/dashboard-out/_next/static/chunks/0ncbimuip0-o7.css +3 -0
- package/dashboard-out/_next/static/chunks/0xtgenoch3q77.js +1 -0
- package/dashboard-out/_next/static/chunks/1xln1-s87x5yp.js +27 -0
- package/dashboard-out/_not-found/__next._full.txt +15 -15
- package/dashboard-out/_not-found/__next._head.txt +4 -4
- package/dashboard-out/_not-found/__next._index.txt +10 -10
- package/dashboard-out/_not-found/__next._not-found.__PAGE__.txt +2 -2
- package/dashboard-out/_not-found/__next._not-found.txt +3 -3
- package/dashboard-out/_not-found/__next._tree.txt +2 -2
- package/dashboard-out/_not-found/index.html +1 -1
- package/dashboard-out/_not-found/index.txt +15 -15
- package/dashboard-out/index.html +1 -1
- package/dashboard-out/index.txt +17 -17
- package/dist/adapters/session-export.handler.d.ts +4 -0
- package/dist/adapters/session-export.handler.js +29 -0
- package/dist/adapters/socket.options.d.ts +3 -0
- package/dist/adapters/socket.options.js +16 -0
- package/dist/config/config.manager.d.ts +80 -3
- package/dist/config/config.manager.js +269 -89
- package/dist/config/config.types.d.ts +89 -13
- package/dist/core/delivery/buckets-request.d.ts +2 -0
- package/dist/core/delivery/buckets-request.js +18 -0
- package/dist/core/delivery/index.d.ts +1 -0
- package/dist/core/delivery/index.js +1 -0
- package/dist/core/delivery/metrics.publisher.d.ts +23 -10
- package/dist/core/delivery/metrics.publisher.js +22 -22
- package/dist/core/delivery/websocket.events.d.ts +14 -3
- package/dist/core/delivery/websocket.events.js +13 -2
- package/dist/core/domain/correlation.types.d.ts +37 -0
- package/dist/core/domain/correlation.types.js +2 -0
- package/dist/core/domain/dashboard.types.d.ts +16 -69
- package/dist/core/domain/dashboard.types.js +29 -0
- package/dist/core/domain/endpoints.types.d.ts +3 -0
- package/dist/core/domain/event.types.d.ts +14 -0
- package/dist/core/domain/event.types.js +2 -0
- package/dist/core/domain/incident.types.d.ts +50 -0
- package/dist/core/domain/incident.types.js +2 -0
- package/dist/core/domain/index.d.ts +5 -0
- package/dist/core/domain/index.js +5 -0
- package/dist/core/domain/live-bucket.types.d.ts +86 -0
- package/dist/core/domain/live-bucket.types.js +2 -0
- package/dist/core/domain/metrics.types.d.ts +41 -11
- package/dist/core/domain/session.types.d.ts +93 -0
- package/dist/core/domain/session.types.js +2 -0
- package/dist/core/domain/telemetry.types.d.ts +1 -0
- package/dist/core/organizers/event.manager.d.ts +19 -0
- package/dist/core/organizers/event.manager.js +73 -0
- package/dist/core/organizers/index.d.ts +2 -0
- package/dist/core/organizers/index.js +18 -0
- package/dist/core/organizers/interval.manager.d.ts +18 -0
- package/dist/core/organizers/interval.manager.js +54 -0
- package/dist/core/storage/index.d.ts +1 -0
- package/dist/core/storage/index.js +1 -0
- package/dist/core/storage/local.repository.d.ts +12 -12
- package/dist/core/storage/local.repository.js +38 -38
- package/dist/core/storage/persistence/persistence-writer.d.ts +48 -0
- package/dist/core/storage/persistence/persistence-writer.js +191 -0
- package/dist/core/storage/persistence/segment-index.d.ts +27 -0
- package/dist/core/storage/persistence/segment-index.js +206 -0
- package/dist/core/storage/persistence/session-registry.d.ts +28 -0
- package/dist/core/storage/persistence/session-registry.js +127 -0
- package/dist/core/storage/persistence/session-summary.d.ts +3 -0
- package/dist/core/storage/persistence/session-summary.js +112 -0
- package/dist/core/storage/persistence.layer.d.ts +69 -0
- package/dist/core/storage/persistence.layer.js +404 -0
- package/dist/core/storage/runtime/anomaly-detector.d.ts +11 -0
- package/dist/core/storage/runtime/anomaly-detector.js +42 -0
- package/dist/core/storage/stores/analytics.store.d.ts +5 -5
- package/dist/core/storage/stores/analytics.store.js +39 -12
- package/dist/core/storage/stores/bucket-metric.d.ts +85 -0
- package/dist/core/storage/stores/bucket-metric.js +168 -0
- package/dist/core/storage/stores/bucket-view.d.ts +44 -0
- package/dist/core/storage/stores/bucket-view.js +63 -0
- package/dist/core/storage/stores/bucket.store.d.ts +39 -36
- package/dist/core/storage/stores/bucket.store.js +112 -60
- package/dist/core/storage/stores/dashboard.store.d.ts +11 -4
- package/dist/core/storage/stores/dashboard.store.js +179 -47
- package/dist/core/storage/stores/endpoint.store.d.ts +1 -0
- package/dist/core/storage/stores/endpoint.store.js +21 -5
- package/dist/core/storage/stores/index.d.ts +0 -7
- package/dist/core/storage/stores/index.js +0 -7
- package/dist/core/storage/stores/metrics.store.d.ts +1 -1
- package/dist/core/storage/stores/metrics.store.js +1 -0
- package/dist/core/storage/stores/runtime.store.d.ts +77 -0
- package/dist/core/storage/stores/runtime.store.js +222 -0
- package/dist/core/storage/utility/common.d.ts +1 -0
- package/dist/core/storage/utility/common.js +11 -0
- package/dist/core/storage/utility/file-buffer.d.ts +31 -0
- package/dist/core/storage/utility/file-buffer.js +238 -0
- package/dist/core/storage/utility/histogram.d.ts +1 -2
- package/dist/core/storage/utility/histogram.js +1 -2
- package/dist/core/storage/utility/index.d.ts +2 -0
- package/dist/core/storage/utility/index.js +2 -0
- package/dist/core/storage/utility/persistence-files.d.ts +3 -0
- package/dist/core/storage/utility/persistence-files.js +34 -0
- package/dist/core/storage/utility/persistence-writer.d.ts +39 -0
- package/dist/core/storage/utility/persistence-writer.js +183 -0
- package/dist/core/storage/utility/session-export.d.ts +3 -0
- package/dist/core/storage/utility/session-export.js +31 -0
- package/dist/core/storage/utility/session-registry.d.ts +21 -0
- package/dist/core/storage/utility/session-registry.js +91 -0
- package/dist/core/storage/utility/session-window.d.ts +8 -0
- package/dist/core/storage/utility/session-window.js +43 -0
- package/dist/core/telemetry/analytics.service.d.ts +18 -0
- package/dist/core/telemetry/analytics.service.js +100 -0
- package/dist/core/telemetry/collector.service.d.ts +17 -15
- package/dist/core/telemetry/collector.service.js +23 -80
- package/dist/core/telemetry/correlation.service.d.ts +57 -9
- package/dist/core/telemetry/correlation.service.js +246 -54
- package/dist/core/telemetry/dashboard-live.service.d.ts +10 -0
- package/dist/core/telemetry/dashboard-live.service.js +110 -0
- package/dist/core/telemetry/dashboard.service.d.ts +20 -0
- package/dist/core/telemetry/dashboard.service.js +140 -0
- package/dist/core/telemetry/incident.service.d.ts +71 -0
- package/dist/core/telemetry/incident.service.js +239 -0
- package/dist/core/telemetry/logger.d.ts +4 -0
- package/dist/core/telemetry/logger.js +5 -2
- package/dist/core/telemetry/runtime.service.d.ts +14 -0
- package/dist/core/telemetry/runtime.service.js +56 -0
- package/dist/core/telemetry/telemetry-query.service.d.ts +82 -0
- package/dist/core/telemetry/telemetry-query.service.js +231 -0
- package/dist/core/telemetry/telemetry.service.d.ts +10 -4
- package/dist/core/telemetry/telemetry.service.js +60 -10
- package/dist/core/telemetry/utility/correlation-analysis.d.ts +9 -0
- package/dist/core/telemetry/utility/correlation-analysis.js +143 -0
- package/dist/core/telemetry/utility/correlation-finding.d.ts +70 -0
- package/dist/core/telemetry/utility/correlation-finding.js +41 -0
- package/dist/core/telemetry/utility/correlation-input.d.ts +59 -0
- package/dist/core/telemetry/utility/correlation-input.js +139 -0
- package/dist/core/telemetry/utility/correlation-replay.d.ts +24 -0
- package/dist/core/telemetry/utility/correlation-replay.js +46 -0
- package/dist/core/utility/correlation.analysis.d.ts +9 -0
- package/dist/core/utility/correlation.analysis.js +144 -0
- package/dist/core/utility/statistics.d.ts +65 -0
- package/dist/core/utility/statistics.js +141 -0
- package/dist/express/index.d.ts +1 -1
- package/dist/express/index.js +7 -5
- package/dist/express/metrics-websocket.adapter.d.ts +8 -2
- package/dist/express/metrics-websocket.adapter.js +52 -19
- package/dist/express/metrics.adapter.d.ts +1 -0
- package/dist/express/metrics.adapter.js +8 -1
- package/dist/express/metrics.bootstrap.d.ts +6 -1
- package/dist/express/metrics.bootstrap.js +48 -22
- package/dist/express/metrics.dashboard.d.ts +2 -1
- package/dist/express/metrics.dashboard.js +4 -1
- package/dist/express/metrics.middleware.d.ts +2 -1
- package/dist/express/metrics.middleware.js +23 -20
- package/dist/nest/metrics-websocket.adapter.d.ts +19 -3
- package/dist/nest/metrics-websocket.adapter.js +101 -21
- package/dist/nest/metrics.adapter.d.ts +4 -1
- package/dist/nest/metrics.adapter.js +24 -1
- package/dist/nest/metrics.bootstrap.service.d.ts +7 -3
- package/dist/nest/metrics.bootstrap.service.js +56 -21
- package/dist/nest/metrics.interceptor.d.ts +3 -3
- package/dist/nest/metrics.interceptor.js +11 -8
- package/dist/nest/metrics.module.d.ts +3 -0
- package/dist/nest/metrics.module.js +27 -9
- package/dist/runtime/index.d.ts +32 -0
- package/dist/runtime/index.js +104 -0
- package/dist/simulation/simulation.d.ts +5 -16
- package/dist/simulation/simulation.js +5 -8
- package/package.json +2 -1
- package/dashboard-out/_next/static/chunks/23soo6qkun-yv.js +0 -1
- package/dashboard-out/_next/static/chunks/3xoopocxi2vi8.css +0 -3
- package/dashboard-out/_next/static/chunks/3z-nzyp9z8vih.js +0 -3
- /package/dashboard-out/_next/static/{kFIRZt4fuL4Zsh38-jGui → 17egwqgk36_DSRF55LJZG}/_buildManifest.js +0 -0
- /package/dashboard-out/_next/static/{kFIRZt4fuL4Zsh38-jGui → 17egwqgk36_DSRF55LJZG}/_clientMiddlewareManifest.js +0 -0
- /package/dashboard-out/_next/static/{kFIRZt4fuL4Zsh38-jGui → 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,
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
rps:
|
|
22
|
-
latency:
|
|
23
|
-
errorRate:
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
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:
|
|
43
|
-
errorClient:
|
|
44
|
-
errorServer:
|
|
45
|
-
totalCount:
|
|
109
|
+
rps: 0,
|
|
110
|
+
errorClient: 0,
|
|
111
|
+
errorServer: 0,
|
|
112
|
+
totalCount: 0
|
|
46
113
|
},
|
|
47
114
|
percentiles: {
|
|
48
|
-
p50:
|
|
49
|
-
p95:
|
|
50
|
-
p99:
|
|
51
|
-
totalCount:
|
|
115
|
+
p50: 0,
|
|
116
|
+
p95: 0,
|
|
117
|
+
p99: 0,
|
|
118
|
+
totalCount: 0
|
|
52
119
|
},
|
|
53
120
|
runtimePerformance: {
|
|
54
|
-
heapUsage:
|
|
55
|
-
heapSize:
|
|
56
|
-
lag:
|
|
57
|
-
totalCount:
|
|
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(
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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;
|
|
@@ -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
|
-
|
|
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.
|
|
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);
|
|
@@ -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>;
|