115 lines
3.7 KiB
TypeScript
115 lines
3.7 KiB
TypeScript
import { register, Counter, Gauge, Histogram } from 'prom-client';
|
|
import { db } from '@/storage/db';
|
|
import { forever } from '@/utils/forever';
|
|
import { delay } from '@/utils/delay';
|
|
import { shutdownSignal } from '@/utils/shutdown';
|
|
|
|
// Application metrics
|
|
export const websocketConnectionsGauge = new Gauge({
|
|
name: 'websocket_connections_total',
|
|
help: 'Number of active WebSocket connections',
|
|
labelNames: ['type'] as const,
|
|
registers: [register]
|
|
});
|
|
|
|
export const sessionAliveEventsCounter = new Counter({
|
|
name: 'session_alive_events_total',
|
|
help: 'Total number of session-alive events',
|
|
registers: [register]
|
|
});
|
|
|
|
export const machineAliveEventsCounter = new Counter({
|
|
name: 'machine_alive_events_total',
|
|
help: 'Total number of machine-alive events',
|
|
registers: [register]
|
|
});
|
|
|
|
export const sessionCacheCounter = new Counter({
|
|
name: 'session_cache_operations_total',
|
|
help: 'Total session cache operations',
|
|
labelNames: ['operation', 'result'] as const,
|
|
registers: [register]
|
|
});
|
|
|
|
export const databaseUpdatesSkippedCounter = new Counter({
|
|
name: 'database_updates_skipped_total',
|
|
help: 'Number of database updates skipped due to debouncing',
|
|
labelNames: ['type'] as const,
|
|
registers: [register]
|
|
});
|
|
|
|
export const websocketEventsCounter = new Counter({
|
|
name: 'websocket_events_total',
|
|
help: 'Total WebSocket events received by type',
|
|
labelNames: ['event_type'] as const,
|
|
registers: [register]
|
|
});
|
|
|
|
export const httpRequestsCounter = new Counter({
|
|
name: 'http_requests_total',
|
|
help: 'Total number of HTTP requests',
|
|
labelNames: ['method', 'route', 'status'] as const,
|
|
registers: [register]
|
|
});
|
|
|
|
export const httpRequestDurationHistogram = new Histogram({
|
|
name: 'http_request_duration_seconds',
|
|
help: 'HTTP request duration in seconds',
|
|
labelNames: ['method', 'route', 'status'] as const,
|
|
buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10],
|
|
registers: [register]
|
|
});
|
|
|
|
// Database count metrics
|
|
export const databaseRecordCountGauge = new Gauge({
|
|
name: 'database_records_total',
|
|
help: 'Total number of records in database tables',
|
|
labelNames: ['table'] as const,
|
|
registers: [register]
|
|
});
|
|
|
|
// WebSocket connection tracking
|
|
const connectionCounts = {
|
|
'user-scoped': 0,
|
|
'session-scoped': 0,
|
|
'machine-scoped': 0
|
|
};
|
|
|
|
export function incrementWebSocketConnection(type: 'user-scoped' | 'session-scoped' | 'machine-scoped'): void {
|
|
connectionCounts[type]++;
|
|
websocketConnectionsGauge.set({ type }, connectionCounts[type]);
|
|
}
|
|
|
|
export function decrementWebSocketConnection(type: 'user-scoped' | 'session-scoped' | 'machine-scoped'): void {
|
|
connectionCounts[type] = Math.max(0, connectionCounts[type] - 1);
|
|
websocketConnectionsGauge.set({ type }, connectionCounts[type]);
|
|
}
|
|
|
|
// Database metrics updater
|
|
export async function updateDatabaseMetrics(): Promise<void> {
|
|
// Query counts for each table
|
|
const [accountCount, sessionCount, messageCount, machineCount] = await Promise.all([
|
|
db.account.count(),
|
|
db.session.count(),
|
|
db.sessionMessage.count(),
|
|
db.machine.count()
|
|
]);
|
|
|
|
// Update metrics
|
|
databaseRecordCountGauge.set({ table: 'accounts' }, accountCount);
|
|
databaseRecordCountGauge.set({ table: 'sessions' }, sessionCount);
|
|
databaseRecordCountGauge.set({ table: 'messages' }, messageCount);
|
|
databaseRecordCountGauge.set({ table: 'machines' }, machineCount);
|
|
}
|
|
|
|
export function startDatabaseMetricsUpdater(): void {
|
|
forever('database-metrics-updater', async () => {
|
|
await updateDatabaseMetrics();
|
|
|
|
// Wait 60 seconds before next update
|
|
await delay(60 * 1000, shutdownSignal);
|
|
});
|
|
}
|
|
|
|
// Export the register for combining metrics
|
|
export { register }; |