@texagon/nestjs-health
Version:
A comprehensive health monitoring package for NestJS applications with metrics and Kubernetes-ready health checks
244 lines • 11.6 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HealthController = void 0;
const common_1 = require("@nestjs/common");
const swagger_1 = require("@nestjs/swagger");
const terminus_1 = require("@nestjs/terminus");
const health_service_1 = require("./health.service");
const metrics_service_1 = require("./metrics.service");
const health_module_1 = require("./health.module");
const health_auth_guard_1 = require("./health-auth.guard");
let HealthController = class HealthController {
constructor(health, memory, disk, healthService, metricsService, options) {
this.health = health;
this.memory = memory;
this.disk = disk;
this.healthService = healthService;
this.metricsService = metricsService;
this.options = options || {
enableMemoryMonitoring: true,
enableDiskMonitoring: true,
diskPath: "/",
diskThresholdPercent: 0.75,
routePrefix: "health",
};
}
check() {
const checks = [() => this.healthService.isHealthy()];
if (this.options.enableMemoryMonitoring) {
checks.push(() => this.memory.checkHeap("memory_heap", 150 * 1024 * 1024));
checks.push(() => this.memory.checkRSS("memory_rss", 150 * 1024 * 1024));
}
if (this.options.enableDiskMonitoring) {
checks.push(() => this.disk.checkStorage("disk", {
path: this.options.diskPath,
thresholdPercent: this.options.diskThresholdPercent,
}));
}
return this.health.check(checks);
}
liveness() {
return this.health.check([() => this.healthService.isHealthy()]);
}
readiness() {
return this.health.check([
() => this.healthService.isHealthy(),
() => this.memory.checkHeap("memory_heap", 300 * 1024 * 1024),
]);
}
async getDetailedStats(includeHistory) {
var _a;
const startTime = process.uptime();
const memoryStats = await this.healthService.getMemoryStats();
let healthStatus = "unhealthy";
let healthDetails = {};
try {
const health = await this.healthService.isHealthy();
healthStatus = "healthy";
healthDetails = health;
}
catch (error) {
healthStatus = "unhealthy";
if (error.response) {
healthDetails = error.response;
}
}
const diskStats = this.options.enableDiskMonitoring
? await this.disk.checkStorage("disk", {
path: this.options.diskPath,
thresholdPercent: this.options.diskThresholdPercent,
})
: { disk: { status: "unknown" } };
const os = require("os");
const cpuUsage = process.cpuUsage();
const systemUptime = os.uptime();
const loadAvg = os.loadavg();
const metrics = this.metricsService.getMetrics();
return Object.assign({ status: healthStatus, timestamp: new Date().toISOString(), version: process.env.npm_package_version || "1.0.0", process: {
pid: process.pid,
ppid: process.ppid,
title: process.title,
uptime: {
seconds: startTime,
formatted: this.formatUptime(startTime),
},
memoryUsage: {
current: {
rss: this.formatBytes(process.memoryUsage().rss),
heapTotal: this.formatBytes(process.memoryUsage().heapTotal),
heapUsed: this.formatBytes(process.memoryUsage().heapUsed),
external: this.formatBytes(process.memoryUsage().external || 0),
arrayBuffers: this.formatBytes(process.memoryUsage().arrayBuffers || 0),
},
max: {
rss: this.formatBytes(metrics.max.memory.rss),
heapTotal: this.formatBytes(metrics.max.memory.heapTotal),
heapUsed: this.formatBytes(metrics.max.memory.heapUsed),
external: this.formatBytes(metrics.max.memory.external),
arrayBuffers: this.formatBytes(metrics.max.memory.arrayBuffers || 0),
},
min: {
rss: this.formatBytes(metrics.min.memory.rss),
heapTotal: this.formatBytes(metrics.min.memory.heapTotal),
heapUsed: this.formatBytes(metrics.min.memory.heapUsed),
external: this.formatBytes(metrics.min.memory.external),
arrayBuffers: this.formatBytes(metrics.min.memory.arrayBuffers || 0),
},
},
cpuUsage: {
current: {
user: cpuUsage.user,
system: cpuUsage.system,
percent: ((_a = metrics.current) === null || _a === void 0 ? void 0 : _a.cpu.percent.toFixed(2)) + "%" || "0%",
},
max: {
user: metrics.max.cpu.user,
system: metrics.max.cpu.system,
percent: metrics.max.cpu.percent.toFixed(2) + "%",
},
},
}, system: {
platform: process.platform,
arch: process.arch,
nodeVersion: process.version,
hostname: os.hostname(),
uptime: {
seconds: systemUptime,
formatted: this.formatUptime(systemUptime),
},
loadAvg: os.loadavg(),
totalMemory: this.formatBytes(os.totalmem()),
freeMemory: this.formatBytes(os.freemem()),
cpus: os.cpus().length,
}, disk: diskStats, environment: process.env.NODE_ENV || "development", requests: {
total: metrics.requests.stats.total,
responseTime: {
avg: metrics.requests.stats.avgResponseTime.toFixed(2) + "ms",
max: metrics.requests.stats.maxResponseTime + "ms",
min: metrics.requests.stats.minResponseTime === Number.MAX_SAFE_INTEGER
? "0ms"
: metrics.requests.stats.minResponseTime + "ms",
},
byMethod: metrics.requests.stats.byMethod,
byStatusCode: metrics.requests.stats.byStatusCode,
recent: metrics.requests.recent,
} }, (includeHistory === "true" && { history: metrics.history }));
}
formatBytes(bytes) {
if (bytes === 0)
return "0 Bytes";
const k = 1024;
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
}
formatUptime(seconds) {
const days = Math.floor(seconds / (3600 * 24));
const hours = Math.floor((seconds % (3600 * 24)) / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = Math.floor(seconds % 60);
return `${days}d ${hours}h ${minutes}m ${secs}s`;
}
};
exports.HealthController = HealthController;
__decorate([
(0, common_1.Get)(),
(0, common_1.UseGuards)(health_auth_guard_1.HealthAuthGuard),
(0, terminus_1.HealthCheck)(),
(0, swagger_1.ApiOperation)({ summary: "Check application health status" }),
(0, swagger_1.ApiResponse)({ status: 200, description: "Application is healthy" }),
(0, swagger_1.ApiResponse)({ status: 503, description: "Application is not healthy" }),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], HealthController.prototype, "check", null);
__decorate([
(0, common_1.Get)("live"),
(0, common_1.UseGuards)(health_auth_guard_1.HealthAuthGuard),
(0, terminus_1.HealthCheck)(),
(0, swagger_1.ApiOperation)({ summary: "Liveness probe for container orchestration" }),
(0, swagger_1.ApiResponse)({ status: 200, description: "Application is alive" }),
(0, swagger_1.ApiResponse)({ status: 503, description: "Application is not alive" }),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], HealthController.prototype, "liveness", null);
__decorate([
(0, common_1.Get)("ready"),
(0, common_1.UseGuards)(health_auth_guard_1.HealthAuthGuard),
(0, terminus_1.HealthCheck)(),
(0, swagger_1.ApiOperation)({ summary: "Readiness probe for container orchestration" }),
(0, swagger_1.ApiResponse)({
status: 200,
description: "Application is ready to accept traffic",
}),
(0, swagger_1.ApiResponse)({ status: 503, description: "Application is not ready" }),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], HealthController.prototype, "readiness", null);
__decorate([
(0, common_1.Get)("stats"),
(0, common_1.UseGuards)(health_auth_guard_1.HealthAuthGuard),
(0, common_1.Version)(common_1.VERSION_NEUTRAL),
(0, swagger_1.ApiOperation)({ summary: "Get detailed application statistics" }),
(0, swagger_1.ApiQuery)({
name: "includeHistory",
required: false,
type: "boolean",
description: "Whether to include historical metrics data",
}),
(0, swagger_1.ApiResponse)({
status: 200,
description: "Application statistics retrieved successfully",
}),
__param(0, (0, common_1.Query)("includeHistory")),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", Promise)
], HealthController.prototype, "getDetailedStats", null);
exports.HealthController = HealthController = __decorate([
(0, swagger_1.ApiTags)("health"),
(0, swagger_1.ApiSecurity)("auth-key"),
(0, common_1.Controller)("health"),
__param(5, (0, common_1.Optional)()),
__param(5, (0, common_1.Inject)(health_module_1.MODULE_OPTIONS_TOKEN)),
__metadata("design:paramtypes", [terminus_1.HealthCheckService,
terminus_1.MemoryHealthIndicator,
terminus_1.DiskHealthIndicator,
health_service_1.HealthService,
metrics_service_1.MetricsService, Object])
], HealthController);
//# sourceMappingURL=health.controller.js.map