UNPKG

@texagon/nestjs-health

Version:

A comprehensive health monitoring package for NestJS applications with metrics and Kubernetes-ready health checks

244 lines 11.6 kB
"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