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.
- package/dist/adapters/http.adapter.d.ts +12 -0
- package/dist/adapters/http.adapter.js +2 -0
- package/dist/adapters/websocket.adapter.d.ts +5 -0
- package/dist/adapters/websocket.adapter.js +2 -0
- package/dist/config/config.manager.d.ts +12 -0
- package/dist/config/config.manager.js +111 -0
- package/dist/config/config.types.d.ts +19 -0
- package/dist/config/config.types.js +2 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +18 -0
- package/dist/core/delivery/index.d.ts +2 -0
- package/dist/core/delivery/index.js +18 -0
- package/dist/core/delivery/metrics.publisher.d.ts +18 -0
- package/dist/core/delivery/metrics.publisher.js +36 -0
- package/dist/core/delivery/websocket.events.d.ts +12 -0
- package/dist/core/delivery/websocket.events.js +16 -0
- package/dist/core/domain/common.types.d.ts +44 -0
- package/dist/core/domain/common.types.js +20 -0
- package/dist/core/domain/dashboard.types.d.ts +108 -0
- package/dist/core/domain/dashboard.types.js +2 -0
- package/dist/core/domain/endpoints.types.d.ts +43 -0
- package/dist/core/domain/endpoints.types.js +2 -0
- package/dist/core/domain/index.d.ts +6 -0
- package/dist/core/domain/index.js +22 -0
- package/dist/core/domain/metrics.types.d.ts +119 -0
- package/dist/core/domain/metrics.types.js +2 -0
- package/dist/core/domain/system.types.d.ts +51 -0
- package/dist/core/domain/system.types.js +2 -0
- package/dist/core/domain/telemetry.types.d.ts +8 -0
- package/dist/core/domain/telemetry.types.js +2 -0
- package/dist/core/storage/index.d.ts +3 -0
- package/dist/core/storage/index.js +19 -0
- package/dist/core/storage/local.repository.d.ts +17 -0
- package/dist/core/storage/local.repository.js +52 -0
- package/dist/core/storage/stores/alert.store.d.ts +13 -0
- package/dist/core/storage/stores/alert.store.js +71 -0
- package/dist/core/storage/stores/analytics.store.d.ts +15 -0
- package/dist/core/storage/stores/analytics.store.js +59 -0
- package/dist/core/storage/stores/bucket.store.d.ts +40 -0
- package/dist/core/storage/stores/bucket.store.js +75 -0
- package/dist/core/storage/stores/dashboard.store.d.ts +15 -0
- package/dist/core/storage/stores/dashboard.store.js +78 -0
- package/dist/core/storage/stores/endpoint.store.d.ts +16 -0
- package/dist/core/storage/stores/endpoint.store.js +62 -0
- package/dist/core/storage/stores/health.store.d.ts +20 -0
- package/dist/core/storage/stores/health.store.js +133 -0
- package/dist/core/storage/stores/index.d.ts +8 -0
- package/dist/core/storage/stores/index.js +24 -0
- package/dist/core/storage/stores/metrics.store.d.ts +23 -0
- package/dist/core/storage/stores/metrics.store.js +49 -0
- package/dist/core/storage/stores/system.store.d.ts +8 -0
- package/dist/core/storage/stores/system.store.js +19 -0
- package/dist/core/storage/utility/histogram.d.ts +37 -0
- package/dist/core/storage/utility/histogram.js +91 -0
- package/dist/core/storage/utility/index.d.ts +2 -0
- package/dist/core/storage/utility/index.js +18 -0
- package/dist/core/storage/utility/ring-buffer.d.ts +12 -0
- package/dist/core/storage/utility/ring-buffer.js +47 -0
- package/dist/core/telemetry/collector.service.d.ts +18 -0
- package/dist/core/telemetry/collector.service.js +92 -0
- package/dist/core/telemetry/collectors/cpu.collector.d.ts +22 -0
- package/dist/core/telemetry/collectors/cpu.collector.js +39 -0
- package/dist/core/telemetry/collectors/event-loop.collector.d.ts +22 -0
- package/dist/core/telemetry/collectors/event-loop.collector.js +27 -0
- package/dist/core/telemetry/collectors/gc.collector.d.ts +61 -0
- package/dist/core/telemetry/collectors/gc.collector.js +86 -0
- package/dist/core/telemetry/collectors/handles.collector.d.ts +20 -0
- package/dist/core/telemetry/collectors/handles.collector.js +26 -0
- package/dist/core/telemetry/collectors/index.d.ts +6 -0
- package/dist/core/telemetry/collectors/index.js +22 -0
- package/dist/core/telemetry/collectors/interface.d.ts +3 -0
- package/dist/core/telemetry/collectors/interface.js +2 -0
- package/dist/core/telemetry/collectors/memory.collector.d.ts +18 -0
- package/dist/core/telemetry/collectors/memory.collector.js +24 -0
- package/dist/core/telemetry/collectors/runtime.collector.d.ts +32 -0
- package/dist/core/telemetry/collectors/runtime.collector.js +29 -0
- package/dist/core/telemetry/correlation.service.d.ts +9 -0
- package/dist/core/telemetry/correlation.service.js +72 -0
- package/dist/core/telemetry/logger.d.ts +11 -0
- package/dist/core/telemetry/logger.js +63 -0
- package/dist/core/telemetry/telemetry.service.d.ts +10 -0
- package/dist/core/telemetry/telemetry.service.js +36 -0
- package/dist/core/utility/base-math.d.ts +15 -0
- package/dist/core/utility/base-math.js +26 -0
- package/dist/core/utility/conversion.d.ts +31 -0
- package/dist/core/utility/conversion.js +74 -0
- package/dist/core/utility/index.d.ts +4 -0
- package/dist/core/utility/index.js +20 -0
- package/dist/core/utility/mocking.d.ts +21 -0
- package/dist/core/utility/mocking.js +40 -0
- package/dist/core/utility/pagination.d.ts +9 -0
- package/dist/core/utility/pagination.js +23 -0
- package/dist/core/utility/statistics.d.ts +140 -0
- package/dist/core/utility/statistics.js +349 -0
- package/dist/express/index.d.ts +6 -0
- package/dist/express/index.js +22 -0
- package/dist/express/metrics-websocket.adapter.d.ts +14 -0
- package/dist/express/metrics-websocket.adapter.js +70 -0
- package/dist/express/metrics.adapter.d.ts +12 -0
- package/dist/express/metrics.adapter.js +31 -0
- package/dist/express/metrics.bootstrap.d.ts +2 -0
- package/dist/express/metrics.bootstrap.js +35 -0
- package/dist/express/metrics.dashboard.d.ts +2 -0
- package/dist/express/metrics.dashboard.js +15 -0
- package/dist/express/metrics.middleware.d.ts +2 -0
- package/dist/express/metrics.middleware.js +29 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +6 -0
- package/dist/nest/index.d.ts +4 -0
- package/dist/nest/index.js +11 -0
- package/dist/nest/metrics-websocket.adapter.d.ts +15 -0
- package/dist/nest/metrics-websocket.adapter.js +88 -0
- package/dist/nest/metrics.adapter.d.ts +12 -0
- package/dist/nest/metrics.adapter.js +33 -0
- package/dist/nest/metrics.bootstrap.service.d.ts +13 -0
- package/dist/nest/metrics.bootstrap.service.js +66 -0
- package/dist/nest/metrics.interceptor.d.ts +11 -0
- package/dist/nest/metrics.interceptor.js +57 -0
- package/dist/nest/metrics.module.d.ts +6 -0
- package/dist/nest/metrics.module.js +74 -0
- package/dist/simulation/config.d.ts +20 -0
- package/dist/simulation/config.js +54 -0
- package/dist/simulation/journey.d.ts +7 -0
- package/dist/simulation/journey.js +49 -0
- package/dist/simulation/scenarios.d.ts +17 -0
- package/dist/simulation/scenarios.js +96 -0
- package/dist/simulation/simulation.d.ts +24 -0
- package/dist/simulation/simulation.js +154 -0
- package/dist/simulation/utility.d.ts +23 -0
- package/dist/simulation/utility.js +50 -0
- package/package.json +71 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.collectorService = void 0;
|
|
4
|
+
const storage_1 = require("../storage");
|
|
5
|
+
const collectors_1 = require("./collectors");
|
|
6
|
+
const config_1 = require("../../config");
|
|
7
|
+
class CollectorService {
|
|
8
|
+
cpuCollector;
|
|
9
|
+
memoryCollector;
|
|
10
|
+
eventLoopCollector;
|
|
11
|
+
gcCollector;
|
|
12
|
+
handlesCollector;
|
|
13
|
+
runtimeCollector;
|
|
14
|
+
constructor(cpuCollector, memoryCollector, eventLoopCollector, gcCollector, handlesCollector, runtimeCollector) {
|
|
15
|
+
this.cpuCollector = cpuCollector;
|
|
16
|
+
this.memoryCollector = memoryCollector;
|
|
17
|
+
this.eventLoopCollector = eventLoopCollector;
|
|
18
|
+
this.gcCollector = gcCollector;
|
|
19
|
+
this.handlesCollector = handlesCollector;
|
|
20
|
+
this.runtimeCollector = runtimeCollector;
|
|
21
|
+
}
|
|
22
|
+
getSystemStaticInfo() {
|
|
23
|
+
return storage_1.storage.system.get();
|
|
24
|
+
}
|
|
25
|
+
getDashboardData() {
|
|
26
|
+
return storage_1.storage.dashboard.get();
|
|
27
|
+
}
|
|
28
|
+
getAnalyticsData() {
|
|
29
|
+
return storage_1.storage.analytics.get();
|
|
30
|
+
}
|
|
31
|
+
getHealthData() {
|
|
32
|
+
return storage_1.storage.health.get();
|
|
33
|
+
}
|
|
34
|
+
tick() {
|
|
35
|
+
const cpuData = this.cpuCollector.collect();
|
|
36
|
+
storage_1.storage.health.updateCPU({
|
|
37
|
+
usageRate: cpuData.totalPercent,
|
|
38
|
+
numberOfCores: cpuData.numberOfCores,
|
|
39
|
+
perCoreUsage: cpuData.perCoreUsage,
|
|
40
|
+
userUsage: cpuData.userPercent,
|
|
41
|
+
systemUsage: cpuData.systemPercent,
|
|
42
|
+
idleUsage: cpuData.idlePercent
|
|
43
|
+
});
|
|
44
|
+
const memoryData = this.memoryCollector.collect();
|
|
45
|
+
storage_1.storage.health.updateMemory({
|
|
46
|
+
heapUsage: memoryData.heapUsage,
|
|
47
|
+
heapSize: memoryData.heapSize,
|
|
48
|
+
rssMemory: memoryData.rssMemory,
|
|
49
|
+
rssMemoryTotal: memoryData.rssMemoryTotal,
|
|
50
|
+
externalMemory: memoryData.externalMemory,
|
|
51
|
+
});
|
|
52
|
+
const eventLoopData = this.eventLoopCollector.collect();
|
|
53
|
+
storage_1.storage.health.updateEventLoop({
|
|
54
|
+
lag: eventLoopData.meanMs,
|
|
55
|
+
threshold: this.eventLoopCollector.thresholdMs,
|
|
56
|
+
});
|
|
57
|
+
const handlesData = this.handlesCollector.collect();
|
|
58
|
+
storage_1.storage.health.updateHandles({
|
|
59
|
+
activeHandles: handlesData.activeHandles,
|
|
60
|
+
activeHandlesTimers: handlesData.activeHandlesTimers,
|
|
61
|
+
activeHandlesSockets: handlesData.activeHandlesSockets,
|
|
62
|
+
activeLibuvHandles: handlesData.activeLibuvHandles,
|
|
63
|
+
timers: handlesData.timers,
|
|
64
|
+
fileDescriptors: handlesData.fileDescriptors
|
|
65
|
+
});
|
|
66
|
+
const gcData = this.gcCollector.collect();
|
|
67
|
+
storage_1.storage.health.updateGC({
|
|
68
|
+
gcCount: gcData.gcCount,
|
|
69
|
+
gcTime: gcData.gcTime,
|
|
70
|
+
gcPauseAverage: gcData.gcPauseAverage,
|
|
71
|
+
minorGC: gcData.minorGC,
|
|
72
|
+
majorGC: gcData.majorGC,
|
|
73
|
+
incrementalGC: gcData.incrementalGC,
|
|
74
|
+
heapSpaces: gcData.heapSpaces,
|
|
75
|
+
gcTotals: gcData.gcTotals
|
|
76
|
+
});
|
|
77
|
+
const runtimeData = this.runtimeCollector.collect();
|
|
78
|
+
storage_1.storage.health.updateRuntime({
|
|
79
|
+
pid: runtimeData.pid,
|
|
80
|
+
platform: runtimeData.platform,
|
|
81
|
+
nodeVersion: runtimeData.nodeVersion,
|
|
82
|
+
v8Version: runtimeData.v8Version,
|
|
83
|
+
libuvVersion: runtimeData.libuvVersion,
|
|
84
|
+
openSSLVersion: runtimeData.openSSLVersion,
|
|
85
|
+
threadPoolSize: runtimeData.threadPoolSize,
|
|
86
|
+
activeThreads: runtimeData.activeThreads,
|
|
87
|
+
startup: runtimeData.startup
|
|
88
|
+
});
|
|
89
|
+
storage_1.storage.tick();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.collectorService = new CollectorService(new collectors_1.CPUCollector(), new collectors_1.MemoryCollector(), new collectors_1.EventLoopCollector((0, config_1.getConfig)().publisher.eventLoopResolutionMs, (0, config_1.getConfig)().publisher.eventLoopLagThresholdMs), new collectors_1.GCCollector(), new collectors_1.HandlesCollector(), new collectors_1.RuntimeCollector());
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ICollector } from './interface';
|
|
2
|
+
type CPUUsageResult = {
|
|
3
|
+
numberOfCores: number;
|
|
4
|
+
userPercent: number;
|
|
5
|
+
systemPercent: number;
|
|
6
|
+
totalPercent: number;
|
|
7
|
+
idlePercent: number;
|
|
8
|
+
perCoreUsage: number[];
|
|
9
|
+
};
|
|
10
|
+
declare class CPUCollector implements ICollector<CPUUsageResult> {
|
|
11
|
+
private lastCpuSample;
|
|
12
|
+
private lastTimeSample;
|
|
13
|
+
collect(): {
|
|
14
|
+
numberOfCores: number;
|
|
15
|
+
userPercent: number;
|
|
16
|
+
systemPercent: number;
|
|
17
|
+
totalPercent: number;
|
|
18
|
+
idlePercent: number;
|
|
19
|
+
perCoreUsage: number[];
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export { CPUCollector, CPUUsageResult };
|
|
@@ -0,0 +1,39 @@
|
|
|
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.CPUCollector = void 0;
|
|
7
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
8
|
+
const node_process_1 = __importDefault(require("node:process"));
|
|
9
|
+
const utility_1 = require("../../utility");
|
|
10
|
+
class CPUCollector {
|
|
11
|
+
lastCpuSample = node_process_1.default.cpuUsage();
|
|
12
|
+
lastTimeSample = node_process_1.default.hrtime.bigint();
|
|
13
|
+
collect() {
|
|
14
|
+
const currentCpuUsage = node_process_1.default.cpuUsage(this.lastCpuSample);
|
|
15
|
+
const currentSampleTime = node_process_1.default.hrtime.bigint();
|
|
16
|
+
const elapsedTimeInNs = currentSampleTime - this.lastTimeSample;
|
|
17
|
+
const elapsedTimeInMicros = Number(elapsedTimeInNs) / 1000;
|
|
18
|
+
this.lastCpuSample = node_process_1.default.cpuUsage();
|
|
19
|
+
this.lastTimeSample = currentSampleTime;
|
|
20
|
+
const userPercent = (0, utility_1.toPercentage)(currentCpuUsage.user, elapsedTimeInMicros);
|
|
21
|
+
const systemPercent = (0, utility_1.toPercentage)(currentCpuUsage.system, elapsedTimeInMicros);
|
|
22
|
+
const idlePercent = Math.max(0, 100 - (userPercent + systemPercent));
|
|
23
|
+
const cpus = node_os_1.default.cpus();
|
|
24
|
+
const perCoreUsage = cpus.map((core, index) => {
|
|
25
|
+
const coreTotalTime = Object.values(core.times).reduce((a, b) => a + b, 0);
|
|
26
|
+
return coreTotalTime > 0 ? (0, utility_1.toPercentage)((coreTotalTime - core.times.idle), coreTotalTime) : 0;
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
numberOfCores: cpus.length,
|
|
30
|
+
userPercent: userPercent,
|
|
31
|
+
systemPercent: systemPercent,
|
|
32
|
+
totalPercent: (0, utility_1.clamp)(userPercent + systemPercent, 0, 100),
|
|
33
|
+
idlePercent: idlePercent,
|
|
34
|
+
perCoreUsage: perCoreUsage,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
;
|
|
38
|
+
}
|
|
39
|
+
exports.CPUCollector = CPUCollector;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ICollector } from './interface';
|
|
2
|
+
type EventLoopUsageResult = {
|
|
3
|
+
minMs: number;
|
|
4
|
+
maxMs: number;
|
|
5
|
+
meanMs: number;
|
|
6
|
+
p50Ms: number;
|
|
7
|
+
p99Ms: number;
|
|
8
|
+
};
|
|
9
|
+
declare class EventLoopCollector implements ICollector<EventLoopUsageResult> {
|
|
10
|
+
readonly resolutionMs: number;
|
|
11
|
+
readonly thresholdMs: number;
|
|
12
|
+
private histogram;
|
|
13
|
+
constructor(resolutionMs?: number, thresholdMs?: number);
|
|
14
|
+
collect(): {
|
|
15
|
+
minMs: number;
|
|
16
|
+
maxMs: number;
|
|
17
|
+
meanMs: number;
|
|
18
|
+
p50Ms: number;
|
|
19
|
+
p99Ms: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export { EventLoopCollector, EventLoopUsageResult };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventLoopCollector = void 0;
|
|
4
|
+
const perf_hooks_1 = require("perf_hooks");
|
|
5
|
+
const utility_1 = require("../../utility");
|
|
6
|
+
class EventLoopCollector {
|
|
7
|
+
resolutionMs;
|
|
8
|
+
thresholdMs;
|
|
9
|
+
histogram;
|
|
10
|
+
constructor(resolutionMs = 20, thresholdMs = 100) {
|
|
11
|
+
this.resolutionMs = resolutionMs;
|
|
12
|
+
this.thresholdMs = thresholdMs;
|
|
13
|
+
this.histogram = (0, perf_hooks_1.monitorEventLoopDelay)({ resolution: this.resolutionMs });
|
|
14
|
+
this.histogram.enable();
|
|
15
|
+
}
|
|
16
|
+
collect() {
|
|
17
|
+
const toMs = (ns) => (0, utility_1.convertNanoseconds)(ns, 'ms');
|
|
18
|
+
return {
|
|
19
|
+
minMs: toMs(this.histogram.min),
|
|
20
|
+
maxMs: toMs(this.histogram.max),
|
|
21
|
+
meanMs: toMs(this.histogram.mean),
|
|
22
|
+
p50Ms: toMs(this.histogram.percentile(50)),
|
|
23
|
+
p99Ms: toMs(this.histogram.percentile(99))
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.EventLoopCollector = EventLoopCollector;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ICollector } from './interface';
|
|
2
|
+
type GCUsageResult = {
|
|
3
|
+
gcCount: number;
|
|
4
|
+
gcTime: number;
|
|
5
|
+
gcPauseAverage: number;
|
|
6
|
+
minorGC: {
|
|
7
|
+
runCount: number;
|
|
8
|
+
averageTime: number;
|
|
9
|
+
};
|
|
10
|
+
majorGC: {
|
|
11
|
+
runCount: number;
|
|
12
|
+
averageTime: number;
|
|
13
|
+
};
|
|
14
|
+
incrementalGC: {
|
|
15
|
+
runCount: number;
|
|
16
|
+
averageTime: number;
|
|
17
|
+
};
|
|
18
|
+
heapSpaces: {
|
|
19
|
+
label: string;
|
|
20
|
+
used: number;
|
|
21
|
+
}[];
|
|
22
|
+
gcTotals: {
|
|
23
|
+
totalPauseTime: number;
|
|
24
|
+
freedMemory: number;
|
|
25
|
+
promotions: number;
|
|
26
|
+
tenuredSize: number;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
declare class GCCollector implements ICollector<GCUsageResult> {
|
|
30
|
+
private gcStats;
|
|
31
|
+
private gcObserver;
|
|
32
|
+
constructor();
|
|
33
|
+
collect(): {
|
|
34
|
+
gcCount: number;
|
|
35
|
+
gcTime: number;
|
|
36
|
+
gcPauseAverage: number;
|
|
37
|
+
minorGC: {
|
|
38
|
+
runCount: number;
|
|
39
|
+
averageTime: number;
|
|
40
|
+
};
|
|
41
|
+
majorGC: {
|
|
42
|
+
runCount: number;
|
|
43
|
+
averageTime: number;
|
|
44
|
+
};
|
|
45
|
+
incrementalGC: {
|
|
46
|
+
runCount: number;
|
|
47
|
+
averageTime: number;
|
|
48
|
+
};
|
|
49
|
+
heapSpaces: {
|
|
50
|
+
label: string;
|
|
51
|
+
used: number;
|
|
52
|
+
}[];
|
|
53
|
+
gcTotals: {
|
|
54
|
+
totalPauseTime: number;
|
|
55
|
+
freedMemory: number;
|
|
56
|
+
promotions: number;
|
|
57
|
+
tenuredSize: number;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export { GCCollector, GCUsageResult };
|
|
@@ -0,0 +1,86 @@
|
|
|
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.GCCollector = void 0;
|
|
7
|
+
const node_v8_1 = __importDefault(require("node:v8"));
|
|
8
|
+
const node_perf_hooks_1 = require("node:perf_hooks");
|
|
9
|
+
const utility_1 = require("../../utility");
|
|
10
|
+
class GCCollector {
|
|
11
|
+
gcStats;
|
|
12
|
+
gcObserver = new node_perf_hooks_1.PerformanceObserver((list) => {
|
|
13
|
+
const entries = list.getEntries();
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
const duration = entry.duration;
|
|
16
|
+
this.gcStats.gcCount++;
|
|
17
|
+
this.gcStats.gcTime += duration;
|
|
18
|
+
const detail = entry.detail;
|
|
19
|
+
const kind = detail ? detail.kind : 0;
|
|
20
|
+
if (kind === 1) { // Minor GC
|
|
21
|
+
this.gcStats.minorGC.runCount++;
|
|
22
|
+
this.gcStats.minorGC.totalTime += duration;
|
|
23
|
+
}
|
|
24
|
+
else if (kind === 2) { // Major GC
|
|
25
|
+
this.gcStats.majorGC.runCount++;
|
|
26
|
+
this.gcStats.majorGC.totalTime += duration;
|
|
27
|
+
}
|
|
28
|
+
else { // Incremental GC
|
|
29
|
+
this.gcStats.incrementalGC.runCount++;
|
|
30
|
+
this.gcStats.incrementalGC.totalTime += duration;
|
|
31
|
+
}
|
|
32
|
+
if (detail) {
|
|
33
|
+
if (detail.freedMemory)
|
|
34
|
+
this.gcStats.freedMemory += detail.freedMemory;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
constructor() {
|
|
39
|
+
this.gcStats = {
|
|
40
|
+
gcCount: 0,
|
|
41
|
+
gcTime: 0,
|
|
42
|
+
gcPauseAverage: 0,
|
|
43
|
+
minorGC: { runCount: 0, totalTime: 0 },
|
|
44
|
+
majorGC: { runCount: 0, totalTime: 0 },
|
|
45
|
+
incrementalGC: { runCount: 0, totalTime: 0 },
|
|
46
|
+
freedMemory: 0
|
|
47
|
+
};
|
|
48
|
+
this.gcObserver.observe({ entryTypes: ['gc'], buffered: true });
|
|
49
|
+
}
|
|
50
|
+
collect() {
|
|
51
|
+
const spaceStats = node_v8_1.default.getHeapSpaceStatistics();
|
|
52
|
+
const heapSpaces = spaceStats.map(space => ({
|
|
53
|
+
label: space.space_name,
|
|
54
|
+
used: space.space_used_size / 1024 / 1024
|
|
55
|
+
}));
|
|
56
|
+
const tenuredSpace = spaceStats.find(s => s.space_name === 'old_space');
|
|
57
|
+
const parseFloatFixed = (value) => parseFloat(value.toFixed(2));
|
|
58
|
+
const parseFloatSafe = (value, condition) => condition ? parseFloatFixed(value) : 0;
|
|
59
|
+
return {
|
|
60
|
+
gcCount: this.gcStats.gcCount,
|
|
61
|
+
gcTime: parseFloatFixed(this.gcStats.gcTime),
|
|
62
|
+
gcPauseAverage: parseFloatSafe(this.gcStats.gcTime / this.gcStats.gcCount, this.gcStats.gcCount > 0),
|
|
63
|
+
minorGC: {
|
|
64
|
+
runCount: this.gcStats.minorGC.runCount,
|
|
65
|
+
averageTime: parseFloatSafe(this.gcStats.minorGC.totalTime / this.gcStats.minorGC.runCount, this.gcStats.minorGC.runCount > 0)
|
|
66
|
+
},
|
|
67
|
+
majorGC: {
|
|
68
|
+
runCount: this.gcStats.majorGC.runCount,
|
|
69
|
+
averageTime: parseFloatSafe(this.gcStats.majorGC.totalTime / this.gcStats.majorGC.runCount, this.gcStats.majorGC.runCount > 0)
|
|
70
|
+
},
|
|
71
|
+
incrementalGC: {
|
|
72
|
+
runCount: this.gcStats.incrementalGC.runCount,
|
|
73
|
+
averageTime: parseFloatSafe(this.gcStats.incrementalGC.totalTime / this.gcStats.incrementalGC.runCount, this.gcStats.incrementalGC.runCount > 0)
|
|
74
|
+
},
|
|
75
|
+
heapSpaces,
|
|
76
|
+
gcTotals: {
|
|
77
|
+
totalPauseTime: parseFloatFixed(this.gcStats.gcTime),
|
|
78
|
+
freedMemory: (0, utility_1.convertBytes)(this.gcStats.freedMemory, 'MB'),
|
|
79
|
+
promotions: this.gcStats.majorGC.runCount,
|
|
80
|
+
tenuredSize: tenuredSpace ? tenuredSpace.space_used_size / 1024 / 1024 : 0
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.GCCollector = GCCollector;
|
|
86
|
+
;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ICollector } from './interface';
|
|
2
|
+
type HandleUsageResult = {
|
|
3
|
+
activeHandles: number;
|
|
4
|
+
activeHandlesTimers: number;
|
|
5
|
+
activeHandlesSockets: number;
|
|
6
|
+
activeLibuvHandles: number;
|
|
7
|
+
timers: number;
|
|
8
|
+
fileDescriptors: number;
|
|
9
|
+
};
|
|
10
|
+
declare class HandlesCollector implements ICollector<HandleUsageResult> {
|
|
11
|
+
collect(): {
|
|
12
|
+
activeHandles: any;
|
|
13
|
+
activeHandlesTimers: number;
|
|
14
|
+
activeHandlesSockets: number;
|
|
15
|
+
activeLibuvHandles: any;
|
|
16
|
+
timers: number;
|
|
17
|
+
fileDescriptors: any;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export { HandlesCollector, HandleUsageResult };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HandlesCollector = void 0;
|
|
4
|
+
class HandlesCollector {
|
|
5
|
+
collect() {
|
|
6
|
+
const handles = process._getActiveHandles ? process._getActiveHandles() : [];
|
|
7
|
+
let timers = 0;
|
|
8
|
+
let sockets = 0;
|
|
9
|
+
for (const h of handles) {
|
|
10
|
+
if (h.constructor && h.constructor.name === 'Timeout')
|
|
11
|
+
timers++;
|
|
12
|
+
if (h.constructor && (h.constructor.name === 'Socket' || h.constructor.name === 'TCPSocket'))
|
|
13
|
+
sockets++;
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
activeHandles: handles.length,
|
|
17
|
+
activeHandlesTimers: timers,
|
|
18
|
+
activeHandlesSockets: sockets,
|
|
19
|
+
activeLibuvHandles: handles.length,
|
|
20
|
+
timers,
|
|
21
|
+
fileDescriptors: handles.length
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.HandlesCollector = HandlesCollector;
|
|
26
|
+
;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./cpu.collector"), exports);
|
|
18
|
+
__exportStar(require("./memory.collector"), exports);
|
|
19
|
+
__exportStar(require("./event-loop.collector"), exports);
|
|
20
|
+
__exportStar(require("./gc.collector"), exports);
|
|
21
|
+
__exportStar(require("./handles.collector"), exports);
|
|
22
|
+
__exportStar(require("./runtime.collector"), exports);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ICollector } from './interface';
|
|
2
|
+
type MemoryUsageResult = {
|
|
3
|
+
heapUsage: number;
|
|
4
|
+
heapSize: number;
|
|
5
|
+
rssMemory: number;
|
|
6
|
+
rssMemoryTotal: number;
|
|
7
|
+
externalMemory: number;
|
|
8
|
+
};
|
|
9
|
+
declare class MemoryCollector implements ICollector<MemoryUsageResult> {
|
|
10
|
+
collect(): {
|
|
11
|
+
heapUsage: number;
|
|
12
|
+
heapSize: number;
|
|
13
|
+
rssMemory: number;
|
|
14
|
+
rssMemoryTotal: number;
|
|
15
|
+
externalMemory: number;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export { MemoryCollector, MemoryUsageResult };
|
|
@@ -0,0 +1,24 @@
|
|
|
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.MemoryCollector = void 0;
|
|
7
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
8
|
+
const node_process_1 = __importDefault(require("node:process"));
|
|
9
|
+
const utility_1 = require("../../utility");
|
|
10
|
+
class MemoryCollector {
|
|
11
|
+
collect() {
|
|
12
|
+
const toMB = (bytes) => (0, utility_1.convertBytes)(bytes, 'MB');
|
|
13
|
+
const memoryUsage = node_process_1.default.memoryUsage();
|
|
14
|
+
const totalMemory = node_os_1.default.totalmem();
|
|
15
|
+
return {
|
|
16
|
+
heapUsage: toMB(memoryUsage.heapUsed),
|
|
17
|
+
heapSize: toMB(memoryUsage.heapTotal),
|
|
18
|
+
rssMemory: toMB(memoryUsage.rss),
|
|
19
|
+
rssMemoryTotal: toMB(totalMemory),
|
|
20
|
+
externalMemory: toMB(memoryUsage.external),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.MemoryCollector = MemoryCollector;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ICollector } from './interface';
|
|
2
|
+
type RuntimeUsageResult = {
|
|
3
|
+
pid: number;
|
|
4
|
+
platform: NodeJS.Platform;
|
|
5
|
+
nodeVersion: string;
|
|
6
|
+
v8Version: string;
|
|
7
|
+
libuvVersion: string;
|
|
8
|
+
openSSLVersion: string;
|
|
9
|
+
threadPoolSize: number;
|
|
10
|
+
activeThreads: number;
|
|
11
|
+
startup: {
|
|
12
|
+
bootstrapTime: number;
|
|
13
|
+
requiredModules: number;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
declare class RuntimeCollector implements ICollector<RuntimeUsageResult> {
|
|
17
|
+
collect(): {
|
|
18
|
+
pid: number;
|
|
19
|
+
platform: NodeJS.Platform;
|
|
20
|
+
nodeVersion: string;
|
|
21
|
+
v8Version: string;
|
|
22
|
+
libuvVersion: string;
|
|
23
|
+
openSSLVersion: string;
|
|
24
|
+
threadPoolSize: number;
|
|
25
|
+
activeThreads: any;
|
|
26
|
+
startup: {
|
|
27
|
+
bootstrapTime: number;
|
|
28
|
+
requiredModules: number;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export { RuntimeCollector, RuntimeUsageResult };
|
|
@@ -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.RuntimeCollector = void 0;
|
|
7
|
+
const node_process_1 = __importDefault(require("node:process"));
|
|
8
|
+
class RuntimeCollector {
|
|
9
|
+
collect() {
|
|
10
|
+
const threadPoolSize = node_process_1.default.env.UV_THREADPOOL_SIZE ? parseInt(node_process_1.default.env.UV_THREADPOOL_SIZE) : 4;
|
|
11
|
+
const activeThreads = node_process_1.default._getActiveRequests().length ?? 0;
|
|
12
|
+
return {
|
|
13
|
+
pid: node_process_1.default.pid,
|
|
14
|
+
platform: node_process_1.default.platform,
|
|
15
|
+
nodeVersion: node_process_1.default.version,
|
|
16
|
+
v8Version: node_process_1.default.versions.v8,
|
|
17
|
+
libuvVersion: node_process_1.default.versions.uv,
|
|
18
|
+
openSSLVersion: node_process_1.default.versions.openssl,
|
|
19
|
+
threadPoolSize: threadPoolSize,
|
|
20
|
+
activeThreads: activeThreads,
|
|
21
|
+
startup: {
|
|
22
|
+
bootstrapTime: performance.now(),
|
|
23
|
+
requiredModules: Object.keys(require.cache).length,
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.RuntimeCollector = RuntimeCollector;
|
|
29
|
+
;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.correlationService = void 0;
|
|
4
|
+
const local_repository_1 = require("../storage/local.repository");
|
|
5
|
+
const statistics_1 = require("../utility/statistics");
|
|
6
|
+
class CorrelationService {
|
|
7
|
+
sampleSize;
|
|
8
|
+
constructor() {
|
|
9
|
+
this.sampleSize =
|
|
10
|
+
(0, statistics_1.calculateSampleSizeProportion)(0.05, 0.95); //! This maybe from config?
|
|
11
|
+
}
|
|
12
|
+
tick() {
|
|
13
|
+
const totalHistory = local_repository_1.storage.bucket.getHistory();
|
|
14
|
+
const size = totalHistory.length;
|
|
15
|
+
if (size < this.sampleSize) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const rps = totalHistory.map(e => e.rps.count);
|
|
19
|
+
const errorRate = totalHistory.map(e => e.error.rate);
|
|
20
|
+
const heapUsage = totalHistory.map(e => e.health.memory.heapUsage);
|
|
21
|
+
const p95Latency = totalHistory.map(e => e.latency.p95);
|
|
22
|
+
const eventLoopLag = totalHistory.map(e => e.health.eventLoop.lag);
|
|
23
|
+
const averageLatency = totalHistory.map(e => e.latency.average);
|
|
24
|
+
// 1. eventLoopLag <-> p95 latency
|
|
25
|
+
this.handleReport(this.testCorrelation(eventLoopLag, p95Latency));
|
|
26
|
+
// 2. eventLoopLag <-> average latency
|
|
27
|
+
this.handleReport(this.testCorrelation(eventLoopLag, averageLatency));
|
|
28
|
+
// 3. heapUsage <-> eventLoopLag
|
|
29
|
+
this.handleReport(this.testCorrelation(heapUsage, eventLoopLag));
|
|
30
|
+
// 4. heapUsage <-> p95 latency
|
|
31
|
+
this.handleReport(this.testCorrelation(heapUsage, p95Latency));
|
|
32
|
+
// 5. rps <-> errorRate
|
|
33
|
+
this.handleReport(this.testCorrelation(rps, errorRate));
|
|
34
|
+
// 6. rps <-> latency
|
|
35
|
+
this.handleReport(this.testCorrelation(rps, averageLatency));
|
|
36
|
+
}
|
|
37
|
+
testCorrelation(x, y) {
|
|
38
|
+
const pearsonR = (0, statistics_1.pearsonCorrelation)(x, y);
|
|
39
|
+
const spearmanR = (0, statistics_1.spearmanCorrelation)(x, y);
|
|
40
|
+
const { determination, alienation } = (0, statistics_1.determinationAndAlienation)(pearsonR);
|
|
41
|
+
if (Math.abs(spearmanR) > 0.7 && Math.abs(pearsonR) <= 0.6) {
|
|
42
|
+
return {
|
|
43
|
+
status: 'NON_LINEAR_BURST',
|
|
44
|
+
recommendation: 'Kritično! Detektovan nelinearan (eksponencijalni) skok. Sistem ulazi u zonu zasićenja resursa.'
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
else if (spearmanR > 0.7 && determination > 0.5) {
|
|
48
|
+
if (alienation > 0.4) {
|
|
49
|
+
return {
|
|
50
|
+
status: 'EXTERNAL_INFLUENCE',
|
|
51
|
+
recommendation: `Uočena je povezanost (r=${spearmanR.toFixed(2)}), ali eksterni faktori utiču sa ${(alienation * 100).toFixed(1)}%. Ne donositi ishitren zaključak o uzročnosti.`
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
return {
|
|
56
|
+
status: 'SYSTEMIC_LINEAR_DEGRADATION',
|
|
57
|
+
recommendation: `Linearna degradacija. Varijable zajednički rastu.`
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
status: 'STABLE',
|
|
63
|
+
recommendation: 'Sistem je stabilan. Nema detektovanih uzročnih veza između posmatranih varijabli.'
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
handleReport(report) {
|
|
67
|
+
if (report.status === 'STABLE')
|
|
68
|
+
return;
|
|
69
|
+
local_repository_1.storage.alerts.warning(report.recommendation);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.correlationService = new CorrelationService();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
declare class Logger {
|
|
3
|
+
private static readonly RESET;
|
|
4
|
+
private static readonly BOLD;
|
|
5
|
+
private static readonly DIM;
|
|
6
|
+
private static readonly COLORS;
|
|
7
|
+
static log(req: Request, res: Response, duration: number): void;
|
|
8
|
+
static debug(message: string): void;
|
|
9
|
+
static duration(message: string, duration: number): void;
|
|
10
|
+
}
|
|
11
|
+
export default Logger;
|