171 lines
4.6 KiB
JavaScript
171 lines
4.6 KiB
JavaScript
/**
|
|
* Container Health & Metrics Endpoint
|
|
* Add this to your main application containers for self-reporting
|
|
*/
|
|
|
|
const express = require('express');
|
|
const os = require('os');
|
|
const fs = require('fs');
|
|
const { exec } = require('child_process');
|
|
const { promisify } = require('util');
|
|
const execAsync = promisify(exec);
|
|
|
|
/**
|
|
* Health & Metrics endpoint implementation
|
|
* Add this to your Express app in each container
|
|
*/
|
|
const createHealthEndpoint = (app) => {
|
|
app.get('/health/metrics', async (req, res) => {
|
|
try {
|
|
const containerName = process.env.CONTAINER_NAME || 'unknown-container';
|
|
const memUsage = process.memoryUsage();
|
|
const cpuUsage = process.cpuUsage();
|
|
|
|
// Get system load average
|
|
const loadAvg = os.loadavg();
|
|
|
|
// Get network connections (if available)
|
|
let networkConnections = 'N/A';
|
|
try {
|
|
const { stdout } = await execAsync('netstat -an | grep ESTABLISHED | wc -l');
|
|
networkConnections = parseInt(stdout.trim());
|
|
} catch (e) {
|
|
// Network info not available
|
|
}
|
|
|
|
// Get disk usage for common paths
|
|
let diskUsage = {};
|
|
try {
|
|
const paths = ['/tmp', '/var/log', '/app'];
|
|
for (const path of paths) {
|
|
if (fs.existsSync(path)) {
|
|
const stats = fs.statSync(path);
|
|
diskUsage[path] = `${Math.round(stats.size / 1024 / 1024)}MB`;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
diskUsage = { error: 'Disk info unavailable' };
|
|
}
|
|
|
|
// Calculate CPU percentage (approximate)
|
|
const cpuPercent = ((cpuUsage.user + cpuUsage.system) / 1000000 / process.uptime() * 100).toFixed(1);
|
|
|
|
const metrics = {
|
|
container: containerName,
|
|
timestamp: new Date().toISOString(),
|
|
uptime: Math.round(process.uptime()),
|
|
health: 'healthy',
|
|
version: process.env.APP_VERSION || '1.0.0',
|
|
|
|
// Memory metrics
|
|
memory: {
|
|
usage: `${Math.round(memUsage.heapUsed / 1024 / 1024)}MB / ${Math.round(memUsage.heapTotal / 1024 / 1024)}MB`,
|
|
percentage: `${Math.round((memUsage.heapUsed / memUsage.heapTotal) * 100)}%`,
|
|
rss: `${Math.round(memUsage.rss / 1024 / 1024)}MB`,
|
|
external: `${Math.round(memUsage.external / 1024 / 1024)}MB`
|
|
},
|
|
|
|
// CPU metrics
|
|
cpu: `${cpuPercent}%`,
|
|
|
|
// System metrics
|
|
system: {
|
|
platform: os.platform(),
|
|
arch: os.arch(),
|
|
nodeVersion: process.version,
|
|
loadAverage: loadAvg[0].toFixed(2)
|
|
},
|
|
|
|
// Network metrics
|
|
network: {
|
|
connections: networkConnections,
|
|
requests_handled: global.requestCounter || 0
|
|
},
|
|
|
|
// Disk metrics
|
|
disk: diskUsage,
|
|
|
|
// Additional app-specific metrics
|
|
application: {
|
|
environment: process.env.NODE_ENV || 'development',
|
|
pid: process.pid,
|
|
ppid: process.ppid
|
|
}
|
|
};
|
|
|
|
res.json({
|
|
success: true,
|
|
data: metrics,
|
|
source: 'internal_health_endpoint'
|
|
});
|
|
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to collect metrics',
|
|
message: error.message,
|
|
container: process.env.CONTAINER_NAME || 'unknown-container'
|
|
});
|
|
}
|
|
});
|
|
|
|
// Simple health check endpoint
|
|
app.get('/health', (req, res) => {
|
|
res.json({
|
|
status: 'healthy',
|
|
timestamp: new Date().toISOString(),
|
|
uptime: process.uptime(),
|
|
container: process.env.CONTAINER_NAME || 'unknown-container'
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Middleware to count requests (for metrics)
|
|
*/
|
|
const requestCounter = (req, res, next) => {
|
|
global.requestCounter = (global.requestCounter || 0) + 1;
|
|
next();
|
|
};
|
|
|
|
/**
|
|
* Enhanced logging for metrics
|
|
*/
|
|
const logMetrics = () => {
|
|
const memUsage = process.memoryUsage();
|
|
const metrics = {
|
|
timestamp: new Date().toISOString(),
|
|
container: process.env.CONTAINER_NAME || 'unknown-container',
|
|
memory_mb: Math.round(memUsage.heapUsed / 1024 / 1024),
|
|
uptime_seconds: Math.round(process.uptime()),
|
|
requests_handled: global.requestCounter || 0
|
|
};
|
|
|
|
console.log(`METRICS: ${JSON.stringify(metrics)}`);
|
|
};
|
|
|
|
// Example usage in your main app:
|
|
/*
|
|
const app = express();
|
|
|
|
// Add request counter middleware
|
|
app.use(requestCounter);
|
|
|
|
// Add health endpoints
|
|
createHealthEndpoint(app);
|
|
|
|
// Log metrics every 30 seconds
|
|
setInterval(logMetrics, 30000);
|
|
|
|
// Your other routes...
|
|
app.listen(3000, () => {
|
|
console.log('Server started with health endpoints');
|
|
});
|
|
*/
|
|
|
|
module.exports = {
|
|
createHealthEndpoint,
|
|
requestCounter,
|
|
logMetrics
|
|
};
|