@merncloud/nodejs-monitoring
Version:
A comprehensive monitoring service for Node.js applications with built-in health probes and metrics collection
166 lines • 6.33 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MonitoringService = void 0;
const SystemMetrics_1 = require("./collectors/SystemMetrics");
const RequestTracker_1 = require("./collectors/RequestTracker");
const BuiltInProbes_1 = require("./probes/BuiltInProbes");
class MonitoringService {
constructor(config = {}) {
this.customProbes = [];
this.probeResults = new Map();
this.metricsHistory = [];
this.config = {
enableHealthRoute: true,
healthRoutePath: "/health",
enableMetricsCollection: true,
metricsInterval: 30000,
enableRequestTracking: true,
enableErrorTracking: true,
...config,
};
this.systemMetrics = SystemMetrics_1.SystemMetrics.getInstance();
this.requestTracker = RequestTracker_1.RequestTracker.getInstance();
this.startTime = Date.now();
this.initializeBuiltInProbes();
this.startMetricsCollection();
this.startProbeExecution();
}
static getInstance(config) {
if (!MonitoringService.instance) {
MonitoringService.instance = new MonitoringService(config);
}
return MonitoringService.instance;
}
initializeBuiltInProbes() {
const thresholds = this.config.alertThresholds || {};
this.customProbes.push(BuiltInProbes_1.BuiltInProbes.createMemoryProbe(thresholds.memoryUsage), BuiltInProbes_1.BuiltInProbes.createCpuProbe(thresholds.cpuUsage), BuiltInProbes_1.BuiltInProbes.createUptimeProbe(), BuiltInProbes_1.BuiltInProbes.createDiskSpaceProbe());
if (this.config.customProbes) {
this.customProbes.push(...this.config.customProbes);
}
}
startMetricsCollection() {
if (!this.config.enableMetricsCollection)
return;
setInterval(() => {
const metrics = this.collectMetrics();
this.metricsHistory.push(metrics);
if (this.metricsHistory.length > 100) {
this.metricsHistory.shift();
}
}, this.config.metricsInterval);
}
startProbeExecution() {
this.customProbes.forEach((probe) => {
const interval = probe.interval || 60000;
const executeProbe = async () => {
try {
const result = await probe.check();
this.probeResults.set(probe.name, result);
}
catch (error) {
this.probeResults.set(probe.name, {
status: "critical",
message: `Probe execution failed: ${error instanceof Error ? error.message : "Unknown error"}`,
});
}
};
executeProbe();
setInterval(executeProbe, interval);
});
}
collectMetrics() {
const memory = this.systemMetrics.getMemoryMetrics();
const cpu = this.systemMetrics.getCpuMetrics();
const process = this.systemMetrics.getProcessMetrics();
const requestMetrics = this.requestTracker.getMetrics();
return {
timestamp: Date.now(),
uptime: Math.floor((Date.now() - this.startTime) / 1000),
memory,
cpu,
process,
requests: {
total: requestMetrics.total,
active: requestMetrics.active,
averageResponseTime: requestMetrics.averageResponseTime,
},
errors: requestMetrics.errors,
};
}
requestTrackingMiddleware() {
if (!this.config.enableRequestTracking) {
return (req, res, next) => next();
}
return (req, res, next) => {
const startTime = Date.now();
const requestId = this.requestTracker.startRequest();
res.on("finish", () => {
this.requestTracker.endRequest(requestId, startTime);
if (res.statusCode >= 400 && this.config.enableErrorTracking) {
this.requestTracker.recordError();
}
});
next();
};
}
healthCheckHandler() {
return (req, res) => {
const metrics = this.collectMetrics();
const probes = Object.fromEntries(this.probeResults);
const overallStatus = this.getOverallStatus(probes);
res.status(overallStatus === "healthy" ? 200 : 503).json({
status: overallStatus,
timestamp: metrics.timestamp,
uptime: metrics.uptime,
metrics,
probes,
version: process.env.npm_package_version || "1.0.0",
});
};
}
metricsHistoryHandler() {
return (req, res) => {
const limit = parseInt(req.query.limit) || 50;
const metrics = this.metricsHistory.slice(-limit);
res.json({
metrics,
count: metrics.length,
latest: metrics[metrics.length - 1],
});
};
}
getOverallStatus(probes) {
const statuses = Object.values(probes).map((probe) => probe.status);
if (statuses.includes("critical"))
return "critical";
if (statuses.includes("warning"))
return "warning";
return "healthy";
}
addProbe(probe) {
this.customProbes.push(probe);
const interval = probe.interval || 60000;
const executeProbe = async () => {
try {
const result = await probe.check();
this.probeResults.set(probe.name, result);
}
catch (error) {
this.probeResults.set(probe.name, {
status: "critical",
message: `Probe execution failed: ${error instanceof Error ? error.message : "Unknown error"}`,
});
}
};
executeProbe();
setInterval(executeProbe, interval);
}
getCurrentMetrics() {
return this.collectMetrics();
}
getProbeResults() {
return Object.fromEntries(this.probeResults);
}
}
exports.MonitoringService = MonitoringService;
//# sourceMappingURL=MonitoringService.js.map