feat(phase-2): workstream 7 — Prometheus + Grafana Monitoring
- Add prom-client 15; shared registry in src/metrics/registry.ts (7 metrics) - HTTP request counter + duration histogram via metricsMiddleware - DB query duration histogram wrapping pg Pool.query - Redis command duration histogram via typed instrumentRedisMethod wrapper - agentidp_tokens_issued_total in OAuth2Service - agentidp_agents_registered_total in AgentService - GET /metrics unauthenticated endpoint (Prometheus text format) - docker-compose.monitoring.yml overlay (Prometheus + Grafana) - Grafana auto-provisioned datasource + pre-built AgentIdP dashboard - docs/devops/operations.md monitoring section added - 36/36 unit tests passing, 100% coverage on new metrics code - Fix pre-existing unused import in tests/integration/agents.test.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import { Pool } from 'pg';
|
||||
import { dbQueryDurationSeconds } from '../metrics/registry.js';
|
||||
|
||||
let pool: Pool | null = null;
|
||||
|
||||
@@ -26,6 +27,24 @@ export function getPool(): Pool {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Unexpected pg pool error', err);
|
||||
});
|
||||
|
||||
// Wrap pool.query to record duration in Prometheus.
|
||||
// The pg Pool.query method is heavily overloaded — the only safe approach
|
||||
// without TypeScript errors is a typed-any wrapper on the shim itself.
|
||||
// We capture originalQuery as `(...args: any[]) => Promise<any>` to satisfy
|
||||
// TypeScript's spread-into-rest constraint; this is the one sanctioned use of
|
||||
// `any` in this file.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const originalQuery = pool.query.bind(pool) as (...args: any[]) => Promise<any>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(pool as any).query = async (...args: any[]): Promise<any> => {
|
||||
const end = dbQueryDurationSeconds.startTimer({ operation: 'query' });
|
||||
try {
|
||||
return await originalQuery(...args);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
};
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user