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,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.NestWebSocketAdapter = void 0;
|
|
16
|
+
const websockets_1 = require("@nestjs/websockets");
|
|
17
|
+
const delivery_1 = require("../core/delivery");
|
|
18
|
+
const collector_service_1 = require("../core/telemetry/collector.service");
|
|
19
|
+
let NestWebSocketAdapter = class NestWebSocketAdapter {
|
|
20
|
+
server;
|
|
21
|
+
init() { }
|
|
22
|
+
handleConnection(socket) {
|
|
23
|
+
console.log('[Optima] Dashboard klijent se povezao.', socket.id);
|
|
24
|
+
}
|
|
25
|
+
handleDisconnect(socket) {
|
|
26
|
+
console.log('[Optima] Dashboard klijent se odjavio.', socket.id);
|
|
27
|
+
}
|
|
28
|
+
handleSystemData(socket) {
|
|
29
|
+
socket.emit(delivery_1.WebSocketEvents.RESPONSE_SYSTEM_DATA, collector_service_1.collectorService.getSystemStaticInfo());
|
|
30
|
+
}
|
|
31
|
+
handleDashboardData(socket) {
|
|
32
|
+
socket.emit(delivery_1.WebSocketEvents.RESPONSE_DASHBOARD_DATA, collector_service_1.collectorService.getDashboardData());
|
|
33
|
+
}
|
|
34
|
+
handleAnalyticsData(socket) {
|
|
35
|
+
socket.emit(delivery_1.WebSocketEvents.RESPONSE_ANALYTICS_DATA, collector_service_1.collectorService.getAnalyticsData());
|
|
36
|
+
}
|
|
37
|
+
handleHealthData(socket) {
|
|
38
|
+
socket.emit(delivery_1.WebSocketEvents.RESPONSE_HEALTH_DATA, collector_service_1.collectorService.getHealthData());
|
|
39
|
+
}
|
|
40
|
+
broadcast(event, data) {
|
|
41
|
+
this.server.emit(event, data);
|
|
42
|
+
}
|
|
43
|
+
disconnect() {
|
|
44
|
+
this.server?.disconnectSockets(true);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
exports.NestWebSocketAdapter = NestWebSocketAdapter;
|
|
48
|
+
__decorate([
|
|
49
|
+
(0, websockets_1.WebSocketServer)(),
|
|
50
|
+
__metadata("design:type", Function)
|
|
51
|
+
], NestWebSocketAdapter.prototype, "server", void 0);
|
|
52
|
+
__decorate([
|
|
53
|
+
(0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_SYSTEM_DATA),
|
|
54
|
+
__param(0, (0, websockets_1.ConnectedSocket)()),
|
|
55
|
+
__metadata("design:type", Function),
|
|
56
|
+
__metadata("design:paramtypes", [Function]),
|
|
57
|
+
__metadata("design:returntype", void 0)
|
|
58
|
+
], NestWebSocketAdapter.prototype, "handleSystemData", null);
|
|
59
|
+
__decorate([
|
|
60
|
+
(0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_DASHBOARD_DATA),
|
|
61
|
+
__param(0, (0, websockets_1.ConnectedSocket)()),
|
|
62
|
+
__metadata("design:type", Function),
|
|
63
|
+
__metadata("design:paramtypes", [Function]),
|
|
64
|
+
__metadata("design:returntype", void 0)
|
|
65
|
+
], NestWebSocketAdapter.prototype, "handleDashboardData", null);
|
|
66
|
+
__decorate([
|
|
67
|
+
(0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_ANALYTICS_DATA),
|
|
68
|
+
__param(0, (0, websockets_1.ConnectedSocket)()),
|
|
69
|
+
__metadata("design:type", Function),
|
|
70
|
+
__metadata("design:paramtypes", [Function]),
|
|
71
|
+
__metadata("design:returntype", void 0)
|
|
72
|
+
], NestWebSocketAdapter.prototype, "handleAnalyticsData", null);
|
|
73
|
+
__decorate([
|
|
74
|
+
(0, websockets_1.SubscribeMessage)(delivery_1.WebSocketEvents.REQUEST_HEALTH_DATA),
|
|
75
|
+
__param(0, (0, websockets_1.ConnectedSocket)()),
|
|
76
|
+
__metadata("design:type", Function),
|
|
77
|
+
__metadata("design:paramtypes", [Function]),
|
|
78
|
+
__metadata("design:returntype", void 0)
|
|
79
|
+
], NestWebSocketAdapter.prototype, "handleHealthData", null);
|
|
80
|
+
exports.NestWebSocketAdapter = NestWebSocketAdapter = __decorate([
|
|
81
|
+
(0, websockets_1.WebSocketGateway)({
|
|
82
|
+
transports: ['websocket'],
|
|
83
|
+
cors: {
|
|
84
|
+
origin: '*',
|
|
85
|
+
methods: ['GET', 'POST'],
|
|
86
|
+
},
|
|
87
|
+
})
|
|
88
|
+
], NestWebSocketAdapter);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ExecutionContext } from '@nestjs/common';
|
|
2
|
+
import type { HttpAdapter } from '../adapters/http.adapter';
|
|
3
|
+
export declare class NestAdapter implements HttpAdapter<ExecutionContext, ExecutionContext> {
|
|
4
|
+
getRequest(context: ExecutionContext): {
|
|
5
|
+
method: any;
|
|
6
|
+
endpoint: any;
|
|
7
|
+
clientIp: any;
|
|
8
|
+
};
|
|
9
|
+
getResponse(context: ExecutionContext): {
|
|
10
|
+
statusCode: any;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NestAdapter = void 0;
|
|
4
|
+
class NestAdapter {
|
|
5
|
+
getRequest(context) {
|
|
6
|
+
const request = context.switchToHttp().getRequest();
|
|
7
|
+
const { body, // Parsed JSON or form data
|
|
8
|
+
params, // Route path variables
|
|
9
|
+
query, // URL query string parameters
|
|
10
|
+
headers, // HTTP request headers
|
|
11
|
+
cookies, // Parsed client browser cookies
|
|
12
|
+
method, // Executed HTTP verb (GET, POST, etc.)
|
|
13
|
+
path, // Requested URL path string
|
|
14
|
+
ip, // Remote client IP address
|
|
15
|
+
secure, // Boolean for TLS connection status
|
|
16
|
+
url, // Full requested URL string
|
|
17
|
+
} = request;
|
|
18
|
+
return {
|
|
19
|
+
method,
|
|
20
|
+
endpoint: path,
|
|
21
|
+
clientIp: ip,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
getResponse(context) {
|
|
25
|
+
const response = context.switchToHttp().getResponse();
|
|
26
|
+
const { locals, // Request-scoped middleware variables
|
|
27
|
+
headersSent, // Boolean tracking sent HTTP headers
|
|
28
|
+
statusCode, // Current HTTP status code
|
|
29
|
+
} = response;
|
|
30
|
+
return { statusCode };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.NestAdapter = NestAdapter;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { OnApplicationBootstrap, OnApplicationShutdown } from '@nestjs/common';
|
|
2
|
+
import { NestWebSocketAdapter } from './metrics-websocket.adapter';
|
|
3
|
+
import { type ReadonlyConfig } from '../config';
|
|
4
|
+
export declare class MetricsBootstrapService implements OnApplicationBootstrap, OnApplicationShutdown {
|
|
5
|
+
private readonly websocket;
|
|
6
|
+
private readonly config;
|
|
7
|
+
private simulator;
|
|
8
|
+
private publisher;
|
|
9
|
+
private tickInterval;
|
|
10
|
+
constructor(websocket: NestWebSocketAdapter, config: ReadonlyConfig);
|
|
11
|
+
onApplicationBootstrap(): void;
|
|
12
|
+
onApplicationShutdown(): void;
|
|
13
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.MetricsBootstrapService = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const collector_service_1 = require("../core/telemetry/collector.service");
|
|
18
|
+
const correlation_service_1 = require("../core/telemetry/correlation.service");
|
|
19
|
+
const delivery_1 = require("../core/delivery");
|
|
20
|
+
const simulation_1 = require("../simulation/simulation");
|
|
21
|
+
const metrics_websocket_adapter_1 = require("./metrics-websocket.adapter");
|
|
22
|
+
let MetricsBootstrapService = class MetricsBootstrapService {
|
|
23
|
+
websocket;
|
|
24
|
+
config;
|
|
25
|
+
simulator = null;
|
|
26
|
+
publisher = null;
|
|
27
|
+
tickInterval = null;
|
|
28
|
+
constructor(websocket, config) {
|
|
29
|
+
this.websocket = websocket;
|
|
30
|
+
this.config = config;
|
|
31
|
+
}
|
|
32
|
+
onApplicationBootstrap() {
|
|
33
|
+
const simulationConfig = this.config.simulation === false
|
|
34
|
+
? null
|
|
35
|
+
: this.config.simulation;
|
|
36
|
+
if (simulationConfig) {
|
|
37
|
+
this.simulator = new simulation_1.TrafficSimulator();
|
|
38
|
+
this.simulator.start(simulationConfig);
|
|
39
|
+
}
|
|
40
|
+
this.websocket.init();
|
|
41
|
+
this.publisher = new delivery_1.MetricsPublisher(collector_service_1.collectorService, this.websocket, this.config.publisher.intervalMs);
|
|
42
|
+
this.publisher.start();
|
|
43
|
+
this.tickInterval = setInterval(() => {
|
|
44
|
+
collector_service_1.collectorService.tick();
|
|
45
|
+
correlation_service_1.correlationService.tick();
|
|
46
|
+
}, this.config.tickIntervalMs);
|
|
47
|
+
console.log('[Optima] Nest metrics bootstrap initialized.');
|
|
48
|
+
}
|
|
49
|
+
onApplicationShutdown() {
|
|
50
|
+
this.simulator?.stop();
|
|
51
|
+
this.simulator = null;
|
|
52
|
+
this.publisher?.stop();
|
|
53
|
+
this.publisher = null;
|
|
54
|
+
if (this.tickInterval) {
|
|
55
|
+
clearInterval(this.tickInterval);
|
|
56
|
+
this.tickInterval = null;
|
|
57
|
+
}
|
|
58
|
+
this.websocket.disconnect();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
exports.MetricsBootstrapService = MetricsBootstrapService;
|
|
62
|
+
exports.MetricsBootstrapService = MetricsBootstrapService = __decorate([
|
|
63
|
+
(0, common_1.Injectable)(),
|
|
64
|
+
__param(1, (0, common_1.Inject)('METRICS_CONFIG')),
|
|
65
|
+
__metadata("design:paramtypes", [metrics_websocket_adapter_1.NestWebSocketAdapter, Object])
|
|
66
|
+
], MetricsBootstrapService);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import TelemetryService from '../core/telemetry/telemetry.service';
|
|
4
|
+
import { NestAdapter } from './metrics.adapter';
|
|
5
|
+
export declare class MetricsInterceptor implements NestInterceptor {
|
|
6
|
+
private readonly adapter;
|
|
7
|
+
private readonly telemetryService;
|
|
8
|
+
constructor(adapter: NestAdapter, telemetryService: TelemetryService);
|
|
9
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
|
|
10
|
+
private record;
|
|
11
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.MetricsInterceptor = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const operators_1 = require("rxjs/operators");
|
|
18
|
+
const telemetry_service_1 = __importDefault(require("../core/telemetry/telemetry.service"));
|
|
19
|
+
const metrics_adapter_1 = require("./metrics.adapter");
|
|
20
|
+
const logger_1 = __importDefault(require("../core/telemetry/logger"));
|
|
21
|
+
let MetricsInterceptor = class MetricsInterceptor {
|
|
22
|
+
adapter;
|
|
23
|
+
telemetryService;
|
|
24
|
+
constructor(adapter, telemetryService) {
|
|
25
|
+
this.adapter = adapter;
|
|
26
|
+
this.telemetryService = telemetryService;
|
|
27
|
+
}
|
|
28
|
+
intercept(context, next) {
|
|
29
|
+
if (context.getType() !== 'http') {
|
|
30
|
+
return next.handle();
|
|
31
|
+
}
|
|
32
|
+
const startHrTime = process.hrtime.bigint();
|
|
33
|
+
return next.handle().pipe((0, operators_1.tap)({
|
|
34
|
+
next: () => this.record(context, startHrTime),
|
|
35
|
+
error: () => this.record(context, startHrTime),
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
record(context, startHrTime) {
|
|
39
|
+
const requestData = this.adapter.getRequest(context);
|
|
40
|
+
const responseData = this.adapter.getResponse(context);
|
|
41
|
+
const telemetryRequest = this.telemetryService.record({
|
|
42
|
+
endpoint: requestData.endpoint,
|
|
43
|
+
method: requestData.method,
|
|
44
|
+
statusCode: responseData.statusCode,
|
|
45
|
+
clientIp: requestData.clientIp
|
|
46
|
+
}, startHrTime);
|
|
47
|
+
if (telemetryRequest !== null) {
|
|
48
|
+
logger_1.default.log(context.switchToHttp().getRequest(), context.switchToHttp().getResponse(), telemetryRequest.responseTime);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
exports.MetricsInterceptor = MetricsInterceptor;
|
|
53
|
+
exports.MetricsInterceptor = MetricsInterceptor = __decorate([
|
|
54
|
+
(0, common_1.Injectable)(),
|
|
55
|
+
__metadata("design:paramtypes", [metrics_adapter_1.NestAdapter,
|
|
56
|
+
telemetry_service_1.default])
|
|
57
|
+
], MetricsInterceptor);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DynamicModule, NestModule, MiddlewareConsumer } from "@nestjs/common";
|
|
2
|
+
import { ConfigOptions } from '../config';
|
|
3
|
+
export declare class MetricsModule implements NestModule {
|
|
4
|
+
static forRoot(options?: ConfigOptions): DynamicModule;
|
|
5
|
+
configure(consumer: MiddlewareConsumer): void;
|
|
6
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
var MetricsModule_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.MetricsModule = void 0;
|
|
14
|
+
const express_1 = __importDefault(require("express"));
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const core_1 = require("@nestjs/core");
|
|
18
|
+
const metrics_interceptor_1 = require("./metrics.interceptor");
|
|
19
|
+
const metrics_adapter_1 = require("./metrics.adapter");
|
|
20
|
+
const metrics_websocket_adapter_1 = require("./metrics-websocket.adapter");
|
|
21
|
+
const metrics_bootstrap_service_1 = require("./metrics.bootstrap.service");
|
|
22
|
+
const telemetry_service_1 = __importDefault(require("../core/telemetry/telemetry.service"));
|
|
23
|
+
const config_1 = require("../config");
|
|
24
|
+
let MetricsModule = MetricsModule_1 = class MetricsModule {
|
|
25
|
+
static forRoot(options) {
|
|
26
|
+
config_1.ConfigManager.getInstance().initialize(options);
|
|
27
|
+
return {
|
|
28
|
+
module: MetricsModule_1,
|
|
29
|
+
providers: [
|
|
30
|
+
{
|
|
31
|
+
provide: 'METRICS_CONFIG',
|
|
32
|
+
useValue: config_1.ConfigManager.getInstance().get(),
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
exports: ['METRICS_CONFIG'],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
configure(consumer) {
|
|
39
|
+
const config = config_1.ConfigManager.getInstance().get();
|
|
40
|
+
if (config.dashboardPath === false) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const dashboardRoute = config.dashboardPath;
|
|
44
|
+
const staticAssetsPath = path_1.default.resolve(__dirname, '../../../dashboard/out');
|
|
45
|
+
consumer
|
|
46
|
+
.apply(express_1.default.static(staticAssetsPath), (req, res, next) => {
|
|
47
|
+
// SPA Fallback
|
|
48
|
+
if (!req.path.includes('.')) {
|
|
49
|
+
return res.sendFile(path_1.default.join(staticAssetsPath, 'index.html'));
|
|
50
|
+
}
|
|
51
|
+
next();
|
|
52
|
+
})
|
|
53
|
+
.forRoutes(dashboardRoute);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
exports.MetricsModule = MetricsModule;
|
|
57
|
+
exports.MetricsModule = MetricsModule = MetricsModule_1 = __decorate([
|
|
58
|
+
(0, common_1.Global)(),
|
|
59
|
+
(0, common_1.Module)({
|
|
60
|
+
providers: [
|
|
61
|
+
telemetry_service_1.default,
|
|
62
|
+
metrics_adapter_1.NestAdapter,
|
|
63
|
+
metrics_websocket_adapter_1.NestWebSocketAdapter,
|
|
64
|
+
metrics_bootstrap_service_1.MetricsBootstrapService,
|
|
65
|
+
{
|
|
66
|
+
provide: core_1.APP_INTERCEPTOR,
|
|
67
|
+
useClass: metrics_interceptor_1.MetricsInterceptor
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
exports: [
|
|
71
|
+
telemetry_service_1.default,
|
|
72
|
+
],
|
|
73
|
+
})
|
|
74
|
+
], MetricsModule);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type Method = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
2
|
+
export interface EndpointLatency {
|
|
3
|
+
normal: number;
|
|
4
|
+
p95: number;
|
|
5
|
+
p99: number;
|
|
6
|
+
}
|
|
7
|
+
export interface EndpointErrors {
|
|
8
|
+
client: number;
|
|
9
|
+
server: number;
|
|
10
|
+
}
|
|
11
|
+
export interface EndpointConfig {
|
|
12
|
+
url: string;
|
|
13
|
+
methods: Method[];
|
|
14
|
+
weight: number;
|
|
15
|
+
latency: EndpointLatency;
|
|
16
|
+
errors: EndpointErrors;
|
|
17
|
+
service: "USER" | "ORDER" | "PRODUCT" | "AUTH" | "SYSTEM";
|
|
18
|
+
}
|
|
19
|
+
export declare const endpoints: EndpointConfig[];
|
|
20
|
+
export declare const TOTAL_WEIGHT: number;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TOTAL_WEIGHT = exports.endpoints = void 0;
|
|
4
|
+
exports.endpoints = [
|
|
5
|
+
{
|
|
6
|
+
url: "/api/users",
|
|
7
|
+
methods: ["GET", "POST", "PATCH"],
|
|
8
|
+
weight: 35,
|
|
9
|
+
latency: { normal: 25, p95: 120, p99: 500 },
|
|
10
|
+
errors: { client: 0.01, server: 0.005 },
|
|
11
|
+
service: "USER",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
url: "/api/orders",
|
|
15
|
+
methods: ["GET", "POST", "PATCH"],
|
|
16
|
+
weight: 25,
|
|
17
|
+
latency: { normal: 80, p95: 350, p99: 700 },
|
|
18
|
+
errors: { client: 0.01, server: 0.01 },
|
|
19
|
+
service: "ORDER",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
url: "/api/products",
|
|
23
|
+
methods: ["GET"],
|
|
24
|
+
weight: 20,
|
|
25
|
+
latency: { normal: 15, p95: 80, p99: 250 },
|
|
26
|
+
errors: { client: 0.005, server: 0.002 },
|
|
27
|
+
service: "PRODUCT",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
url: "/api/auth/login",
|
|
31
|
+
methods: ["POST"],
|
|
32
|
+
weight: 10,
|
|
33
|
+
latency: { normal: 120, p95: 400, p99: 900 },
|
|
34
|
+
errors: { client: 0.02, server: 0.01 },
|
|
35
|
+
service: "AUTH",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
url: "/health",
|
|
39
|
+
methods: ["GET"],
|
|
40
|
+
weight: 7,
|
|
41
|
+
latency: { normal: 3, p95: 10, p99: 20 },
|
|
42
|
+
errors: { client: 0, server: 0 },
|
|
43
|
+
service: "SYSTEM",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
url: "/metrics",
|
|
47
|
+
methods: ["GET"],
|
|
48
|
+
weight: 3,
|
|
49
|
+
latency: { normal: 5, p95: 20, p99: 50 },
|
|
50
|
+
errors: { client: 0, server: 0 },
|
|
51
|
+
service: "SYSTEM",
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
exports.TOTAL_WEIGHT = exports.endpoints.reduce((sum, e) => sum + e.weight, 0);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pickJourney = pickJourney;
|
|
4
|
+
const journeys = [
|
|
5
|
+
{
|
|
6
|
+
name: "browse",
|
|
7
|
+
probability: 0.55,
|
|
8
|
+
endpoints: [
|
|
9
|
+
"/api/products",
|
|
10
|
+
"/api/products",
|
|
11
|
+
"/api/users",
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: "shopping",
|
|
16
|
+
probability: 0.30,
|
|
17
|
+
endpoints: [
|
|
18
|
+
"/api/auth/login",
|
|
19
|
+
"/api/products",
|
|
20
|
+
"/api/orders",
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "admin",
|
|
25
|
+
probability: 0.10,
|
|
26
|
+
endpoints: [
|
|
27
|
+
"/api/users",
|
|
28
|
+
"/api/orders",
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "health",
|
|
33
|
+
probability: 0.05,
|
|
34
|
+
endpoints: [
|
|
35
|
+
"/health",
|
|
36
|
+
"/metrics",
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
];
|
|
40
|
+
function pickJourney() {
|
|
41
|
+
let value = Math.random();
|
|
42
|
+
for (const journey of journeys) {
|
|
43
|
+
value -= journey.probability;
|
|
44
|
+
if (value <= 0) {
|
|
45
|
+
return journey;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return journeys[0];
|
|
49
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const scenario: {
|
|
2
|
+
trafficMultiplier: number;
|
|
3
|
+
databaseSlowUntil: number;
|
|
4
|
+
authDownUntil: number;
|
|
5
|
+
latencySpikeUntil: number;
|
|
6
|
+
memoryLeak: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function updateScenarios(): void;
|
|
9
|
+
type ScenarioName = "TRAFFIC_SPIKE" | "DATABASE_SLOWDOWN" | "AUTH_OUTAGE" | "MEMORY_LEAK" | "RESET";
|
|
10
|
+
export declare class ScenarioController {
|
|
11
|
+
private readonly state;
|
|
12
|
+
constructor(state: typeof scenario);
|
|
13
|
+
start(name: ScenarioName): void;
|
|
14
|
+
stop(name: ScenarioName): void;
|
|
15
|
+
reset(): void;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ScenarioController = exports.scenario = void 0;
|
|
4
|
+
exports.updateScenarios = updateScenarios;
|
|
5
|
+
const utility_1 = require("./utility");
|
|
6
|
+
exports.scenario = {
|
|
7
|
+
trafficMultiplier: 1,
|
|
8
|
+
databaseSlowUntil: 0,
|
|
9
|
+
authDownUntil: 0,
|
|
10
|
+
latencySpikeUntil: 0,
|
|
11
|
+
memoryLeak: false,
|
|
12
|
+
};
|
|
13
|
+
function updateScenarios() {
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
// traffic spike
|
|
16
|
+
if (now > exports.scenario.latencySpikeUntil && (0, utility_1.probability)(0.002)) {
|
|
17
|
+
exports.scenario.trafficMultiplier = 3;
|
|
18
|
+
exports.scenario.latencySpikeUntil = now + 10000;
|
|
19
|
+
console.log("📈 Traffic spike started");
|
|
20
|
+
}
|
|
21
|
+
if (now > exports.scenario.latencySpikeUntil) {
|
|
22
|
+
exports.scenario.trafficMultiplier = 1;
|
|
23
|
+
}
|
|
24
|
+
// database slowdown
|
|
25
|
+
if (now > exports.scenario.databaseSlowUntil && (0, utility_1.probability)(0.001)) {
|
|
26
|
+
exports.scenario.databaseSlowUntil = now + 12000;
|
|
27
|
+
console.log("🐢 Database slowdown");
|
|
28
|
+
}
|
|
29
|
+
// auth outage
|
|
30
|
+
if (now > exports.scenario.authDownUntil && (0, utility_1.probability)(0.0005)) {
|
|
31
|
+
exports.scenario.authDownUntil = now + 8000;
|
|
32
|
+
console.log("🔐 Auth outage");
|
|
33
|
+
}
|
|
34
|
+
// memory leak
|
|
35
|
+
if (!exports.scenario.memoryLeak && (0, utility_1.probability)(0.0002)) {
|
|
36
|
+
exports.scenario.memoryLeak = true;
|
|
37
|
+
console.log("🧠 Memory leak started");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
class ScenarioController {
|
|
41
|
+
state;
|
|
42
|
+
constructor(state) {
|
|
43
|
+
this.state = state;
|
|
44
|
+
}
|
|
45
|
+
start(name) {
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
switch (name) {
|
|
48
|
+
case "TRAFFIC_SPIKE":
|
|
49
|
+
this.state.trafficMultiplier = 4;
|
|
50
|
+
this.state.latencySpikeUntil = now + 30000;
|
|
51
|
+
console.log("Manual traffic spike!");
|
|
52
|
+
break;
|
|
53
|
+
case "DATABASE_SLOWDOWN":
|
|
54
|
+
this.state.databaseSlowUntil = now + 60000;
|
|
55
|
+
console.log("Manual database slowdown!");
|
|
56
|
+
break;
|
|
57
|
+
case "AUTH_OUTAGE":
|
|
58
|
+
this.state.authDownUntil = now + 30000;
|
|
59
|
+
console.log("Manual auth outage!");
|
|
60
|
+
break;
|
|
61
|
+
case "MEMORY_LEAK":
|
|
62
|
+
this.state.memoryLeak = true;
|
|
63
|
+
console.log("Manual memory leak!");
|
|
64
|
+
break;
|
|
65
|
+
case "RESET":
|
|
66
|
+
this.reset();
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
stop(name) {
|
|
71
|
+
switch (name) {
|
|
72
|
+
case "TRAFFIC_SPIKE":
|
|
73
|
+
this.state.trafficMultiplier = 1;
|
|
74
|
+
this.state.latencySpikeUntil = 0;
|
|
75
|
+
break;
|
|
76
|
+
case "DATABASE_SLOWDOWN":
|
|
77
|
+
this.state.databaseSlowUntil = 0;
|
|
78
|
+
break;
|
|
79
|
+
case "AUTH_OUTAGE":
|
|
80
|
+
this.state.authDownUntil = 0;
|
|
81
|
+
break;
|
|
82
|
+
case "MEMORY_LEAK":
|
|
83
|
+
this.state.memoryLeak = false;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
reset() {
|
|
88
|
+
this.state.trafficMultiplier = 1;
|
|
89
|
+
this.state.databaseSlowUntil = 0;
|
|
90
|
+
this.state.authDownUntil = 0;
|
|
91
|
+
this.state.latencySpikeUntil = 0;
|
|
92
|
+
this.state.memoryLeak = false;
|
|
93
|
+
console.log("Scenarios reset!");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.ScenarioController = ScenarioController;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { TelemetryRequest } from "../core/domain";
|
|
2
|
+
export declare class TrafficSimulator {
|
|
3
|
+
private readonly repository;
|
|
4
|
+
private timer?;
|
|
5
|
+
private running;
|
|
6
|
+
constructor(repository?: {
|
|
7
|
+
readonly endpoint: import("../core/storage").EndpointStore;
|
|
8
|
+
readonly alerts: import("../core/storage").AlertStore;
|
|
9
|
+
readonly metrics: import("../core/storage").MetricsStore;
|
|
10
|
+
readonly health: import("../core/storage").HealthStore;
|
|
11
|
+
readonly bucket: import("../core/storage").BucketStore;
|
|
12
|
+
readonly dashboard: import("../core/storage").DashboardStore;
|
|
13
|
+
readonly analytics: import("../core/storage").AnalyticsStore;
|
|
14
|
+
readonly system: import("../core/storage").SystemStore;
|
|
15
|
+
record(request: TelemetryRequest): void;
|
|
16
|
+
tick(): void;
|
|
17
|
+
});
|
|
18
|
+
start(options?: {
|
|
19
|
+
intervalMs?: number;
|
|
20
|
+
requestsPerTick?: number;
|
|
21
|
+
}): void;
|
|
22
|
+
stop(): void;
|
|
23
|
+
isRunning(): boolean;
|
|
24
|
+
}
|