306 lines
8.5 KiB
TypeScript
306 lines
8.5 KiB
TypeScript
import client from 'prom-client';
|
|
import { env } from '../config/env';
|
|
|
|
const register = new client.Registry();
|
|
|
|
register.setDefaultLabels({
|
|
app: 'changemaker-v2-api',
|
|
instance: env.INSTANCE_LABEL || env.DOMAIN || 'unknown',
|
|
});
|
|
|
|
client.collectDefaultMetrics({ register });
|
|
|
|
// --- HTTP Metrics (existing) ---
|
|
|
|
export const httpRequestDuration = new client.Histogram({
|
|
name: 'http_request_duration_seconds',
|
|
help: 'Duration of HTTP requests in seconds',
|
|
labelNames: ['method', 'route', 'status_code'],
|
|
buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 3, 5, 10],
|
|
registers: [register],
|
|
});
|
|
|
|
export const httpRequestsTotal = new client.Counter({
|
|
name: 'http_requests_total',
|
|
help: 'Total number of HTTP requests',
|
|
labelNames: ['method', 'route', 'status_code'],
|
|
registers: [register],
|
|
});
|
|
|
|
// --- Email Metrics ---
|
|
|
|
export const emailsSentTotal = new client.Counter({
|
|
name: 'cm_emails_sent_total',
|
|
help: 'Total campaign emails sent successfully',
|
|
labelNames: ['campaign_id'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const emailsFailedTotal = new client.Counter({
|
|
name: 'cm_emails_failed_total',
|
|
help: 'Total campaign emails that failed to send',
|
|
labelNames: ['campaign_id', 'error_type'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const emailQueueSize = new client.Gauge({
|
|
name: 'cm_email_queue_size',
|
|
help: 'Current email queue size (waiting + active)',
|
|
registers: [register],
|
|
});
|
|
|
|
export const emailSendDuration = new client.Histogram({
|
|
name: 'cm_email_send_duration_seconds',
|
|
help: 'Duration of individual email sends',
|
|
buckets: [0.1, 0.5, 1, 2, 5, 10, 30],
|
|
registers: [register],
|
|
});
|
|
|
|
// --- Auth Metrics ---
|
|
|
|
export const loginAttemptsTotal = new client.Counter({
|
|
name: 'cm_login_attempts_total',
|
|
help: 'Total login attempts',
|
|
labelNames: ['status'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const activeSessions = new client.Gauge({
|
|
name: 'cm_active_sessions',
|
|
help: 'Number of active refresh tokens (approximate session count)',
|
|
registers: [register],
|
|
});
|
|
|
|
// --- Campaign / Influence Metrics ---
|
|
|
|
export const campaignEmailsTotal = new client.Counter({
|
|
name: 'cm_campaign_emails_total',
|
|
help: 'Total campaign emails created (SMTP + mailto)',
|
|
labelNames: ['campaign_id'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const responseSubmissionsTotal = new client.Counter({
|
|
name: 'cm_response_submissions_total',
|
|
help: 'Total response submissions from public',
|
|
registers: [register],
|
|
});
|
|
|
|
// --- Canvass / Map Metrics ---
|
|
|
|
export const canvassVisitsTotal = new client.Counter({
|
|
name: 'cm_canvass_visits_total',
|
|
help: 'Total canvass visits recorded',
|
|
labelNames: ['outcome'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const activeCanvassSessions = new client.Gauge({
|
|
name: 'cm_active_canvass_sessions',
|
|
help: 'Number of active canvass sessions',
|
|
registers: [register],
|
|
});
|
|
|
|
export const shiftSignupsTotal = new client.Counter({
|
|
name: 'cm_shift_signups_total',
|
|
help: 'Total shift signups',
|
|
registers: [register],
|
|
});
|
|
|
|
// --- Location Query Metrics ---
|
|
|
|
export const locationQueryDuration = new client.Histogram({
|
|
name: 'cm_map_location_query_duration_seconds',
|
|
help: 'Duration of location queries',
|
|
labelNames: ['endpoint', 'has_bounds'],
|
|
buckets: [0.01, 0.05, 0.1, 0.2, 0.5, 1, 2, 5],
|
|
registers: [register],
|
|
});
|
|
|
|
export const locationQueryCount = new client.Counter({
|
|
name: 'cm_map_location_query_count_total',
|
|
help: 'Total location queries',
|
|
labelNames: ['endpoint', 'has_bounds'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const locationResultCount = new client.Histogram({
|
|
name: 'cm_map_location_result_count',
|
|
help: 'Number of locations returned per query',
|
|
labelNames: ['endpoint'],
|
|
buckets: [10, 50, 100, 500, 1000, 5000, 10000],
|
|
registers: [register],
|
|
});
|
|
|
|
// --- Geocoding Metrics ---
|
|
|
|
export const cm_geocode_cache_hits = new client.Counter({
|
|
name: 'cm_geocode_cache_hits_total',
|
|
help: 'Total geocoding cache hits',
|
|
registers: [register],
|
|
});
|
|
|
|
export const cm_geocode_cache_misses = new client.Counter({
|
|
name: 'cm_geocode_cache_misses_total',
|
|
help: 'Total geocoding cache misses',
|
|
registers: [register],
|
|
});
|
|
|
|
export const cm_geocode_requests_total = new client.Counter({
|
|
name: 'cm_geocode_requests_total',
|
|
help: 'Total geocoding requests',
|
|
labelNames: ['provider', 'status'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const cm_geocode_duration = new client.Histogram({
|
|
name: 'cm_geocode_duration_seconds',
|
|
help: 'Duration of geocoding requests',
|
|
labelNames: ['provider'],
|
|
buckets: [0.1, 0.5, 1, 2, 5, 10, 30],
|
|
registers: [register],
|
|
});
|
|
|
|
// --- Email Template Metrics ---
|
|
|
|
export const emailTemplatesUpdated = new client.Counter({
|
|
name: 'cm_email_templates_updated_total',
|
|
help: 'Email templates updated',
|
|
labelNames: ['template_key', 'user_role'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const emailTestSent = new client.Counter({
|
|
name: 'cm_email_test_sent_total',
|
|
help: 'Test emails sent',
|
|
labelNames: ['template_key', 'success'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const emailTemplateRollback = new client.Counter({
|
|
name: 'cm_email_template_rollback_total',
|
|
help: 'Template rollbacks',
|
|
labelNames: ['template_key'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const emailTemplateCacheHit = new client.Counter({
|
|
name: 'cm_email_template_cache_hit_total',
|
|
help: 'Template cache hits',
|
|
labelNames: ['template_key'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const emailTemplateCacheMiss = new client.Counter({
|
|
name: 'cm_email_template_cache_miss_total',
|
|
help: 'Template cache misses',
|
|
labelNames: ['template_key'],
|
|
registers: [register],
|
|
});
|
|
|
|
// --- Docs Editor Metrics ---
|
|
|
|
export const cm_docs_cache_hits = new client.Counter({
|
|
name: 'cm_docs_cache_hits_total',
|
|
help: 'Documentation cache hits',
|
|
labelNames: ['type'], // 'tree' or 'file'
|
|
registers: [register],
|
|
});
|
|
|
|
export const cm_docs_cache_misses = new client.Counter({
|
|
name: 'cm_docs_cache_misses_total',
|
|
help: 'Documentation cache misses',
|
|
labelNames: ['type'],
|
|
registers: [register],
|
|
});
|
|
|
|
export const cm_docs_operations = new client.Counter({
|
|
name: 'cm_docs_operations_total',
|
|
help: 'Documentation file operations',
|
|
labelNames: ['operation'], // 'read', 'write', 'create', 'delete', 'rename'
|
|
registers: [register],
|
|
});
|
|
|
|
// --- External Service Health ---
|
|
|
|
export const externalServiceUp = new client.Gauge({
|
|
name: 'cm_external_service_up',
|
|
help: 'Whether an external service is reachable (1=up, 0=down)',
|
|
labelNames: ['service'],
|
|
registers: [register],
|
|
});
|
|
|
|
// --- Helper Functions ---
|
|
|
|
export function recordEmailSent(campaignId: string) {
|
|
emailsSentTotal.inc({ campaign_id: campaignId });
|
|
}
|
|
|
|
export function recordEmailFailed(campaignId: string, errorType: string = 'unknown') {
|
|
emailsFailedTotal.inc({ campaign_id: campaignId, error_type: errorType });
|
|
}
|
|
|
|
export function setEmailQueueSize(size: number) {
|
|
emailQueueSize.set(size);
|
|
}
|
|
|
|
export function recordLoginAttempt(status: 'success' | 'failure') {
|
|
loginAttemptsTotal.inc({ status });
|
|
}
|
|
|
|
export function setActiveSessions(count: number) {
|
|
activeSessions.set(count);
|
|
}
|
|
|
|
export function recordCampaignEmail(campaignId: string) {
|
|
campaignEmailsTotal.inc({ campaign_id: campaignId });
|
|
}
|
|
|
|
export function recordResponseSubmission() {
|
|
responseSubmissionsTotal.inc();
|
|
}
|
|
|
|
export function recordCanvassVisit(outcome: string) {
|
|
canvassVisitsTotal.inc({ outcome });
|
|
}
|
|
|
|
export function setActiveCanvassSessions(count: number) {
|
|
activeCanvassSessions.set(count);
|
|
}
|
|
|
|
export function recordShiftSignup() {
|
|
shiftSignupsTotal.inc();
|
|
}
|
|
|
|
export function recordLocationQuery(endpoint: string, hasBounds: boolean, resultCount: number, durationSeconds: number) {
|
|
locationQueryCount.inc({ endpoint, has_bounds: hasBounds.toString() });
|
|
locationQueryDuration.observe({ endpoint, has_bounds: hasBounds.toString() }, durationSeconds);
|
|
locationResultCount.observe({ endpoint }, resultCount);
|
|
}
|
|
|
|
export function setServiceUp(service: string, up: boolean) {
|
|
externalServiceUp.set({ service }, up ? 1 : 0);
|
|
}
|
|
|
|
export function recordEmailTemplateUpdate(templateKey: string, userRole: string) {
|
|
emailTemplatesUpdated.inc({ template_key: templateKey, user_role: userRole });
|
|
}
|
|
|
|
export function recordEmailTest(templateKey: string, success: boolean) {
|
|
emailTestSent.inc({ template_key: templateKey, success: success.toString() });
|
|
}
|
|
|
|
export function recordTemplateRollback(templateKey: string) {
|
|
emailTemplateRollback.inc({ template_key: templateKey });
|
|
}
|
|
|
|
export function recordTemplateCacheHit(templateKey: string) {
|
|
emailTemplateCacheHit.inc({ template_key: templateKey });
|
|
}
|
|
|
|
export function recordTemplateCacheMiss(templateKey: string) {
|
|
emailTemplateCacheMiss.inc({ template_key: templateKey });
|
|
}
|
|
|
|
export { register };
|