import { CloudWatchClient, PutMetricDataCommand, StandardUnit } from '@aws-sdk/client-cloudwatch'; import { getMonitoringConfig } from './config'; let client: CloudWatchClient | null = null; function getClient(): CloudWatchClient | null { if (client) return client; const config = getMonitoringConfig(); const region = process.env.AWS_REGION || 'us-east-1'; try { client = new CloudWatchClient({ region }); return client; } catch { console.warn('[CloudWatch] Metrics client initialization skipped'); return null; } } export interface MetricDataPoint { MetricName: string; Dimensions?: { Name: string; Value: string }[]; Value: number; Unit?: string; Timestamp?: Date; } const NAMESPACE = 'ShieldAI'; export async function emitMetric( serviceName: string, metricName: string, value: number, unit: StandardUnit = 'Count', dimensions?: Record ) { const cw = getClient(); if (!cw) return; const dims: { Name: string; Value: string }[] = [ { Name: 'service', Value: serviceName }, ...(dimensions ? Object.entries(dimensions).map(([n, v]) => ({ Name: n, Value: v })) : []), ]; const command = new PutMetricDataCommand({ Namespace: NAMESPACE, MetricData: [ { MetricName: metricName, Dimensions: dims, Value: value, Unit: unit, }, ], }); try { await cw.send(command); } catch (err) { console.warn('[CloudWatch] Metric emit failed:', (err as Error).message); } } export async function emitLatency( serviceName: string, latencyMs: number, percentile: 'p50' | 'p95' | 'p99' ) { await emitMetric( serviceName, 'api_latency', latencyMs, 'Milliseconds' as StandardUnit, { percentile } ); } export async function emitRequestCount(serviceName: string, statusCode: number) { await emitMetric( serviceName, 'api_requests', 1, 'Count' as StandardUnit, { status_class: String(Math.floor(statusCode / 100)) + 'xx' } ); } export async function emitError(serviceName: string, errorType: string) { await emitMetric( serviceName, 'api_errors', 1, 'Count' as StandardUnit, { error_type: errorType } ); }