fix(smartmetrics): Refactor metrics calculation and update Prometheus integration documentation

This commit is contained in:
Juergen Kunz
2025-06-09 12:07:24 +00:00
parent 34b09ed7a7
commit 30992ea44b
6 changed files with 112 additions and 24 deletions

32
changelog.md Normal file
View File

@ -0,0 +1,32 @@
# Changelog
## 2025-06-09 - 2.0.8 - fix(smartmetrics)
Refactor metrics calculation and update Prometheus integration documentation
- Removed dependency on registry.getMetricsAsJSON by directly calculating Node.js metrics
- Updated getMetrics to compute CPU time, heap size, and set default values for deprecated metrics
- Enhanced documentation with comprehensive Prometheus integration examples
- Improved logging on shutdown of the Prometheus endpoint
## 2025-06-09 - 2.0.7 - Prometheus Metrics Integration
feat: Implement Prometheus metrics exposure in SmartMetrics
- Added Prometheus gauges for CPU and memory metrics.
- Implemented HTTP server to expose metrics at the /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.
## 2023-07-02 to 2023-08-08 - 2.0.0 to 2.0.6 - Maintenance Updates
Over this period several releases were published with iterative fixes and minor organizational changes.
- Applied multiple core fixes and routine maintenance updates.
- Switched to new organization scheme (recorded on 2023-07-10).
- Performed several version bumps and configuration updates.
## 2021-08-12 to 2022-07-27 - 1.0.1 to 1.0.17 - Maintenance and Breaking Changes
During this interval a series of minor fixes were combined with a significant breaking change.
- BREAKING CHANGE: Switched to ESM in 1.0.17 (2022-07-27).
- Numerous maintenance updates and core fixes were applied.

View File

@ -1 +1,30 @@
# SmartMetrics Implementation Hints
## Prometheus Integration
The package now supports exposing metrics in Prometheus format through two mechanisms:
1. **Direct Export**: `getPrometheusFormattedMetrics()` returns metrics in Prometheus text exposition format
2. **HTTP Endpoint**: `enablePrometheusEndpoint(port)` starts an HTTP server that exposes metrics on `/metrics`
### Architecture Decisions
- We use the prom-client library's default collectors for standard Node.js metrics
- Custom gauges are created for our calculated metrics (CPU percentage, memory percentage, memory bytes)
- The `getMetrics()` method calculates values directly rather than parsing the Prometheus registry JSON
- For metrics like `nodejs_active_handles_total` and `nodejs_active_requests_total`, we return 0 in `getMetrics()` since these require deprecated Node.js APIs, but the Prometheus collectors still track the real values
### Consolidation Approach
Initially, we were mixing two approaches:
1. Extracting values from the Prometheus registry JSON for default metrics
2. Creating custom gauges for calculated metrics
We consolidated by:
- Calculating all values directly in `getMetrics()` where possible
- Only using the Prometheus registry for the text exposition format
- This eliminates the dependency on parsing registry JSON and makes the code cleaner
### Memory Calculation
The package tracks memory usage across the main process and all child processes using `pidtree` and `pidusage`. This provides a more comprehensive view than just the main process memory.

View File

@ -96,6 +96,33 @@ The `getMetrics` method returns a snapshot of various system metrics, including
- `memoryUsageBytes`: Total memory used in bytes.
- `memoryUsageText`: Readable string representation of memory usage.
### Prometheus Integration
`smartmetrics` can expose metrics in Prometheus format for scraping:
```typescript
// Enable Prometheus endpoint on port 9090 (default)
smartMetrics.enablePrometheusEndpoint();
// Or specify a custom port
smartMetrics.enablePrometheusEndpoint(3000);
// The metrics will be available at http://localhost:9090/metrics
// To get Prometheus-formatted metrics programmatically
const prometheusMetrics = await smartMetrics.getPrometheusFormattedMetrics();
console.log(prometheusMetrics);
// Disable the endpoint when done
smartMetrics.disablePrometheusEndpoint();
```
The Prometheus endpoint exposes both default Node.js metrics (via prom-client) and custom calculated metrics:
- `smartmetrics_cpu_percentage` - Current CPU usage percentage
- `smartmetrics_memory_percentage` - Current memory usage percentage
- `smartmetrics_memory_usage_bytes` - Current memory usage in bytes
- Plus all default Node.js metrics collected by prom-client
### Conclusion
`@push.rocks/smartmetrics` offers a straightforward and efficient way to monitor essential system metrics of your Node.js application. By integrating it, you gain valuable insights into the performance and health of your system, aiding in diagnosis and optimization efforts.

View File

@ -71,8 +71,8 @@ Add Prometheus metrics exposure functionality to SmartMetrics while maintaining
- [x] Clean up by calling `disablePrometheusEndpoint()`
### 10. Update Documentation
- [ ] Add usage example in readme.md for Prometheus integration
- [ ] Document the new methods in code comments
- [x] Add usage example in readme.md for Prometheus integration
- [x] Document the new methods in code comments
## Notes
- Using Node.js built-in `http` module to avoid adding unnecessary dependencies

View File

@ -1,8 +1,8 @@
/**
* autocreated commitinfo by @pushrocks/commitinfo
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@push.rocks/smartmetrics',
version: '2.0.7',
description: 'easy system metrics'
version: '2.0.8',
description: 'A package for easy collection and reporting of system and process metrics.'
}

View File

@ -104,7 +104,6 @@ export class SmartMetrics {
}
public async getMetrics() {
const originalMetrics = await this.registry.getMetricsAsJSON();
const pids = await plugins.pidtree(process.pid);
const stats = await plugins.pidusage([process.pid, ...pids]);
@ -140,23 +139,23 @@ export class SmartMetrics {
this.memoryUsageBytesGauge.set(memoryUsageBytes);
}
// Calculate Node.js metrics directly
const cpuUsage = process.cpuUsage();
const process_cpu_seconds_total = (cpuUsage.user + cpuUsage.system) / 1000000; // Convert from microseconds to seconds
const heapStats = plugins.v8.getHeapStatistics();
const nodejs_heap_size_total_bytes = heapStats.total_heap_size;
// Note: Active handles and requests are internal Node.js metrics that require deprecated APIs
// We return 0 here, but the Prometheus default collectors will track the real values
const nodejs_active_handles_total = 0;
const nodejs_active_requests_total = 0;
const returnMetrics: interfaces.IMetricsSnapshot = {
process_cpu_seconds_total: (
originalMetrics.find((metricSet) => metricSet.name === 'process_cpu_seconds_total') as any
).values[0].value,
nodejs_active_handles_total: (
originalMetrics.find((metricSet) => metricSet.name === 'nodejs_active_handles_total') as any
).values[0].value,
nodejs_active_requests_total: (
originalMetrics.find(
(metricSet) => metricSet.name === 'nodejs_active_requests_total'
) as any
).values[0].value,
nodejs_heap_size_total_bytes: (
originalMetrics.find(
(metricSet) => metricSet.name === 'nodejs_heap_size_total_bytes'
) as any
).values[0].value,
process_cpu_seconds_total,
nodejs_active_handles_total,
nodejs_active_requests_total,
nodejs_heap_size_total_bytes,
cpuPercentage,
cpuUsageText,
memoryPercentage,
@ -208,8 +207,9 @@ export class SmartMetrics {
return;
}
const port = this.prometheusPort;
this.prometheusServer.close(() => {
this.logger.log('info', `Prometheus metrics endpoint on port ${this.prometheusPort} has been shut down`);
this.logger.log('info', `Prometheus metrics endpoint on port ${port} has been shut down`);
});
this.prometheusServer = undefined;