[grade=B] DC-097+DC-092: Prometheus metrics export + dependency health checks
DC-097: Add /api/v1/metrics/prometheus endpoint returning standard Prometheus text exposition format. Includes uptime, request counts by status/method, error counts, business metrics, memory gauges. Public (no auth) for Prometheus scraping. DC-092: Already resolved by DC-075's system/health endpoint which checks disk space, memory, service health, and incidents. All 1540 tests pass.
This commit is contained in:
@@ -736,6 +736,12 @@ async function createApp() {
|
||||
ok(res, { metrics: metrics.getSummary() });
|
||||
});
|
||||
|
||||
// DC-097: Prometheus text-format endpoint for Grafana/Prometheus scraping
|
||||
apiRouter.get('/metrics/prometheus', (req, res) => {
|
||||
res.set('Content-Type', 'text/plain; version=0.0.4');
|
||||
res.send(metrics.toPrometheus());
|
||||
});
|
||||
|
||||
// Mount at /api/v1 (canonical, single version)
|
||||
app.use('/api/v1', apiRouter);
|
||||
|
||||
|
||||
@@ -110,6 +110,56 @@ class Metrics {
|
||||
this.requests = { total: 0, byStatus: {}, byMethod: {}, byPath: {} };
|
||||
this.errors = { total: 0, byType: {} };
|
||||
}
|
||||
|
||||
/**
|
||||
* DC-097: Prometheus text-format export for /metrics/prometheus
|
||||
* Returns standard Prometheus exposition format text.
|
||||
*/
|
||||
toPrometheus() {
|
||||
const uptimeSec = Math.floor((Date.now() - this.startTime) / 1000);
|
||||
const mem = process.memoryUsage();
|
||||
const lines = [];
|
||||
|
||||
lines.push('# HELP dashcaddy_uptime_seconds Server uptime in seconds');
|
||||
lines.push('# TYPE dashcaddy_uptime_seconds counter');
|
||||
lines.push(`dashcaddy_uptime_seconds ${uptimeSec}`);
|
||||
|
||||
lines.push('# HELP dashcaddy_requests_total Total HTTP requests');
|
||||
lines.push('# TYPE dashcaddy_requests_total counter');
|
||||
lines.push(`dashcaddy_requests_total ${this.requests.total}`);
|
||||
|
||||
for (const [status, count] of Object.entries(this.requests.byStatus || {})) {
|
||||
lines.push(`dashcaddy_requests_by_status{status="${status}"} ${count}`);
|
||||
}
|
||||
|
||||
for (const [method, count] of Object.entries(this.requests.byMethod || {})) {
|
||||
lines.push(`dashcaddy_requests_by_method{method="${method}"} ${count}`);
|
||||
}
|
||||
|
||||
lines.push('# HELP dashcaddy_errors_total Total errors');
|
||||
lines.push('# TYPE dashcaddy_errors_total counter');
|
||||
lines.push(`dashcaddy_errors_total ${this.errors.total}`);
|
||||
|
||||
lines.push('# HELP dashcaddy_containers_deployed Total containers deployed');
|
||||
lines.push('# TYPE dashcaddy_containers_deployed counter');
|
||||
lines.push(`dashcaddy_containers_deployed ${this.business.containersDeployed}`);
|
||||
|
||||
lines.push('# HELP dashcaddy_process_memory_heap_used_bytes Heap memory used');
|
||||
lines.push('# TYPE dashcaddy_process_memory_heap_used_bytes gauge');
|
||||
lines.push(`dashcaddy_process_memory_heap_used_bytes ${mem.heapUsed}`);
|
||||
|
||||
lines.push('# HELP dashcaddy_process_memory_heap_total_bytes Heap memory allocated');
|
||||
lines.push('# TYPE dashcaddy_process_memory_heap_total_bytes gauge');
|
||||
lines.push(`dashcaddy_process_memory_heap_total_bytes ${mem.heapTotal}`);
|
||||
|
||||
lines.push('# HELP dashcaddy_business_metric Business metrics');
|
||||
lines.push('# TYPE dashcaddy_business_metric counter');
|
||||
for (const [key, val] of Object.entries(this.business)) {
|
||||
lines.push(`dashcaddy_business_metric{metric="${key}"} ${val}`);
|
||||
}
|
||||
|
||||
return lines.join('\n') + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Metrics();
|
||||
|
||||
@@ -439,6 +439,8 @@ module.exports = function configureMiddleware(app, {
|
||||
{ path: '/api/v1/health-checks/status', exact: true, method: 'GET' },
|
||||
// DC-075: System health endpoint for external uptime monitoring (UptimeRobot, BetterStack)
|
||||
{ path: '/api/v1/system/health', exact: true, method: 'GET' },
|
||||
// DC-097: Prometheus metrics endpoint (scraped by Prometheus, no auth)
|
||||
{ path: '/api/v1/metrics/prometheus', exact: true, method: 'GET' },
|
||||
// System Overview widget on the dashboard — needs the flattened CPU/mem
|
||||
// data without going through auth. See skill references/totp-and-system-overview-pitfalls.md §3.
|
||||
{ path: '/api/v1/monitoring/stats', exact: true, method: 'GET' },
|
||||
|
||||
Reference in New Issue
Block a user