feat: Implement Prometheus metrics exposure in SmartMetrics
- Added Prometheus gauges for CPU and memory metrics. - Implemented HTTP server to expose metrics at /metrics endpoint. - Created methods to enable and disable the Prometheus endpoint. - Updated getMetrics() to set gauge values. - Added tests for Prometheus metrics functionality. - Updated documentation plan for Prometheus integration.
This commit is contained in:
@ -7,11 +7,39 @@ export class SmartMetrics {
|
||||
public logger: plugins.smartlog.Smartlog;
|
||||
public registry: plugins.promClient.Registry;
|
||||
public maxMemoryMB: number;
|
||||
|
||||
// Prometheus gauges for custom metrics
|
||||
private cpuPercentageGauge: plugins.promClient.Gauge<string>;
|
||||
private memoryPercentageGauge: plugins.promClient.Gauge<string>;
|
||||
private memoryUsageBytesGauge: plugins.promClient.Gauge<string>;
|
||||
|
||||
// HTTP server for Prometheus endpoint
|
||||
private prometheusServer?: plugins.http.Server;
|
||||
private prometheusPort?: number;
|
||||
|
||||
public async setup() {
|
||||
const collectDefaultMetrics = plugins.promClient.collectDefaultMetrics;
|
||||
this.registry = new plugins.promClient.Registry();
|
||||
collectDefaultMetrics({ register: this.registry });
|
||||
|
||||
// Initialize custom gauges
|
||||
this.cpuPercentageGauge = new plugins.promClient.Gauge({
|
||||
name: 'smartmetrics_cpu_percentage',
|
||||
help: 'Current CPU usage percentage',
|
||||
registers: [this.registry]
|
||||
});
|
||||
|
||||
this.memoryPercentageGauge = new plugins.promClient.Gauge({
|
||||
name: 'smartmetrics_memory_percentage',
|
||||
help: 'Current memory usage percentage',
|
||||
registers: [this.registry]
|
||||
});
|
||||
|
||||
this.memoryUsageBytesGauge = new plugins.promClient.Gauge({
|
||||
name: 'smartmetrics_memory_usage_bytes',
|
||||
help: 'Current memory usage in bytes',
|
||||
registers: [this.registry]
|
||||
});
|
||||
}
|
||||
|
||||
constructor(loggerArg: plugins.smartlog.Smartlog, sourceNameArg: string) {
|
||||
@ -100,6 +128,17 @@ export class SmartMetrics {
|
||||
)} / ${this.formatBytes(this.maxMemoryMB * 1024 * 1024)}`;
|
||||
|
||||
console.log(`${cpuUsageText} ||| ${memoryUsageText} `);
|
||||
|
||||
// Update Prometheus gauges with current values
|
||||
if (this.cpuPercentageGauge) {
|
||||
this.cpuPercentageGauge.set(cpuPercentage);
|
||||
}
|
||||
if (this.memoryPercentageGauge) {
|
||||
this.memoryPercentageGauge.set(memoryPercentage);
|
||||
}
|
||||
if (this.memoryUsageBytesGauge) {
|
||||
this.memoryUsageBytesGauge.set(memoryUsageBytes);
|
||||
}
|
||||
|
||||
const returnMetrics: interfaces.IMetricsSnapshot = {
|
||||
process_cpu_seconds_total: (
|
||||
@ -127,7 +166,58 @@ export class SmartMetrics {
|
||||
return returnMetrics;
|
||||
}
|
||||
|
||||
public async getPrometheusFormattedMetrics(): Promise<string> {
|
||||
// Update metrics to ensure gauges have latest values
|
||||
await this.getMetrics();
|
||||
|
||||
// Return Prometheus text exposition format
|
||||
return await this.registry.metrics();
|
||||
}
|
||||
|
||||
public enablePrometheusEndpoint(port: number = 9090): void {
|
||||
if (this.prometheusServer) {
|
||||
this.logger.log('warn', 'Prometheus endpoint is already running');
|
||||
return;
|
||||
}
|
||||
|
||||
this.prometheusServer = plugins.http.createServer(async (req, res) => {
|
||||
if (req.url === '/metrics' && req.method === 'GET') {
|
||||
try {
|
||||
const metrics = await this.getPrometheusFormattedMetrics();
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain; version=0.0.4' });
|
||||
res.end(metrics);
|
||||
} catch (error) {
|
||||
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
||||
res.end('Error generating metrics');
|
||||
this.logger.log('error', 'Error generating Prometheus metrics', error);
|
||||
}
|
||||
} else {
|
||||
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
||||
res.end('Not Found');
|
||||
}
|
||||
});
|
||||
|
||||
this.prometheusPort = port;
|
||||
this.prometheusServer.listen(port, () => {
|
||||
this.logger.log('info', `Prometheus metrics endpoint available at http://localhost:${port}/metrics`);
|
||||
});
|
||||
}
|
||||
|
||||
public disablePrometheusEndpoint(): void {
|
||||
if (!this.prometheusServer) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.prometheusServer.close(() => {
|
||||
this.logger.log('info', `Prometheus metrics endpoint on port ${this.prometheusPort} has been shut down`);
|
||||
});
|
||||
|
||||
this.prometheusServer = undefined;
|
||||
this.prometheusPort = undefined;
|
||||
}
|
||||
|
||||
public stop() {
|
||||
this.started = false;
|
||||
this.disablePrometheusEndpoint();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user