npm package: @jamx-framework/metrics
Description: JAMX Framework â€” Performance metrics
Author: Stiven-21
Latest version: 1.0.0

# @jamx-framework/metrics

## Descripción
Módulo de métricas y monitoreo de salud para JAMX Framework. Proporciona una API para recolectar, agregar y exponer métricas de aplicación (latencia, throughput, errores, uso de recursos) y health checks. Soporta múltiples backends de almacenamiento (Prometheus, StatsD, CloudWatch) y puede exponer endpoints HTTP para scrapers de métricas.

## Cómo funciona
El módulo implementa un sistema de observabilidad:

1. **Metrics**: Clase principal que registra contadores, gauges, histogramas y timers
2. **Health**: Sistema de health checks que evalúa el estado de dependencias (DB, cache, colas)
3. **Middleware**: Middleware HTTP que automáticamente registra métricas de requests
4. **Exporters**: Exportadores a formatos estándar (Prometheus, OpenTelemetry)

## Componentes principales
- **src/metrics.ts**: Clase `Metrics` que gestiona contadores, gauges, histogramas
- **src/health.ts**: Clase `Health` que ejecuta y agrupa health checks
- **src/middleware.ts**: Middleware HTTP para registrar métricas de requests
- **src/types.ts**: Tipos compartidos (Metric, HealthCheck, etc.)
- **src/index.ts**: Punto de exportación

## Uso básico
```typescript
import { Metrics, Health } from '@jamx-framework/metrics';

// Crear instancia
const metrics = new Metrics();
const health = new Health();

// Registrar contador
const requestsCounter = metrics.counter('http_requests_total', {
  help: 'Total HTTP requests',
  labels: ['method', 'path', 'status'],
});

// Incrementar contador
requestsCounter.increment({ method: 'GET', path: '/api/users', status: 200 });

// Registrar gauge (valor que sube/baja)
const activeConnections = metrics.gauge('active_connections', {
  help: 'Current active connections',
});
activeConnections.set(42);

// Registrar timer (latencia)
const requestDuration = metrics.histogram('http_request_duration_seconds', {
  help: 'HTTP request duration',
  buckets: [0.1, 0.5, 1, 2, 5],
});
requestDuration.observe(0.234);

// Health checks
health.register('database', async () => {
  const ok = await db.ping();
  return { status: ok ? 'healthy' : 'unhealthy', details: { latency: '10ms' } };
});

health.register('redis', async () => {
  const ok = await cache.ping();
  return { status: ok ? 'healthy' : 'unhealthy' };
});

// Ejecutar todos los health checks
const result = await health.checkAll();
console.log('Estado general:', result.status); // 'healthy' | 'degraded' | 'unhealthy'
```

## Ejemplos
### Middleware HTTP automático
```typescript
import { MetricsMiddleware } from '@jamx-framework/metrics';
import { Server } from '@jamx-framework/server';

const server = new Server();

// Añadir middleware de métricas
server.use(MetricsMiddleware(metrics, {
  // Configuración opcional
  durationMetric: 'http_request_duration_seconds',
  countMetric: 'http_requests_total',
  labels: {
    method: true,   // incluir método HTTP
    path: true,     // incluir path (cuidado con cardinalidad alta)
    status: true,   // incluir código de estado
    userAgent: false, // no incluir user-agent
  },
}));

// Las métricas se registran automáticamente en cada request
```

### Exportar a Prometheus
```typescript
import { Metrics } from '@jamx-framework/metrics';
import * as promClient from 'prom-client';

const metrics = new Metrics();

// Registrar métricas personalizadas
metrics.counter('custom_requests', { labels: ['endpoint'] });
metrics.gauge('queue_size', { labels: ['queue'] });

// Exponer endpoint /metrics
server.get('/metrics', async (req, res) => {
  const registry = promClient.register;
  
  // Convertir métricas JAMX a formato Prometheus
  for (const metric of metrics.getAll()) {
    // Lógica de conversión...
  }
  
  res.text(await registry.metrics());
});
```

### Health checks compuestos
```typescript
import { Health } from '@jamx-framework/metrics';

const health = new Health();

// Check de base de datos
health.register('database', {
  check: async () => {
    try {
      await db.ping();
      return { status: 'healthy', details: { version: db.version } };
    } catch (error) {
      return { status: 'unhealthy', details: { error: error.message } };
    }
  },
  timeout: 5000, // 5 segundos timeout
  dependencies: ['redis'], // depende de que redis esté healthy
});

// Check de Redis
health.register('redis', {
  check: async () => {
    const pong = await cache.ping();
    return { status: pong === 'PONG' ? 'healthy' : 'unhealthy' };
  },
});

// Check de disco
health.register('disk', {
  check: async () => {
    const stats = await fs.statvfs('/');
    const freePercent = (stats.f_bavail / stats.f_blocks) * 100;
    return {
      status: freePercent > 10 ? 'healthy' : 'unhealthy',
      details: { freePercent },
    };
  },
});

// Endpoint de health
server.get('/health', async (req, res) => {
  const result = await health.checkAll();
  const status = result.status === 'healthy' ? 200 : 503;
  res.json(result, status);
});
```

### Timers y contextos
```typescript
import { Metrics } from '@jamx-framework/metrics';

const metrics = new Metrics();
const timer = metrics.timer('function_execution_seconds', {
  labels: ['function_name'],
});

async function processOrder(orderId: string) {
  const stop = timer.start({ function_name: 'processOrder' });
  
  try {
    // Lógica de procesamiento
    await orderService.process(orderId);
    stop(); // Registrar duración
  } catch (error) {
    stop(); // Registrar duración incluso en error
    throw error;
  }
}
```

### Métricas personalizadas con etiquetas
```typescript
const ordersCreated = metrics.counter('orders_created_total', {
  labels: ['payment_method', 'country'],
});

// Incrementar con etiquetas específicas
ordersCreated.increment({
  payment_method: 'credit_card',
  country: 'US',
});

// Consultar métrica actual
const current = ordersCreated.getValue({
  payment_method: 'credit_card',
  country: 'US',
});
console.log('Órdenes con tarjeta en US:', current);
```

### Uso con inyección de dependencias
```typescript
import { Container } from '@jamx-framework/core';
import { Metrics, Health } from '@jamx-framework/metrics';

// Registrar en contenedor
Container.registerSingleton('metrics', () => new Metrics());
Container.registerSingleton('health', () => new Health());

// Resolver y usar
const metrics = Container.resolve<Metrics>('metrics');
const health = Container.resolve<Health>('health');

// Registrar métrica
const apiCalls = metrics.counter('api_calls_total');
apiCalls.increment();

// Verificar salud
const status = await health.check('database');
```

## Flujo interno
1. **Inicialización**: Se crean instancias de `Metrics` y `Health`
2. **Registro**: Se registran contadores, gauges, histogramas con nombres y etiquetas
3. **Recolección**: Durante la ejecución, se invoca `.increment()`, `.set()`, `.observe()`
4. **Agregación**: Las métricas se agregan por etiquetas en memoria
5. **Exportación**: Se pueden exportar a Prometheus, StatsD, CloudWatch, etc.
6. **Health checks**: Se ejecutan checks registrados (DB, cache, disco) y se agrupan resultados
7. **Middleware**: El middleware HTTP automáticamente registra duración y conteo de requests

## API Reference (Resumen)
### Metrics
- `counter(name, options)`: Crea un contador (solo incrementa)
- `gauge(name, options)`: Crea un gauge (setea valor)
- `histogram(name, options)`: Crea un histograma (distribución de valores)
- `timer(name, options)`: Crea un timer (mide duración)
- `getAll(): Metric[]`: Obtiene todas las métricas registradas
- `reset()`: Limpia todas las métricas

### Health
- `register(name, check)`: Registra un health check
- `check(name?)`: Ejecuta check específico o todos
- `checkAll(): Promise<HealthResult>`: Ejecuta todos y agrupa
- `getStatus(): 'healthy' | 'degraded' | 'unhealthy'`

### Metric (interface)
- `name: string`
- `type: 'counter' | 'gauge' | 'histogram' | 'timer'`
- `help?: string`
- `labels?: string[]`
- `value: number | Map<string, number>`

### HealthCheck (interface)
- `name: string`
- `check: () => Promise<HealthStatus>`
- `timeout?: number`
- `dependencies?: string[]`

## Performance Considerations
- **In-memory aggregation**: Las métricas se agregan en memoria, sin I/O en cada registro
- **Lock-free**: Usa estructuras atómicas cuando es posible
- **Sampling**: Se puede configurar sampling para alto volumen
- **Batch export**: Exportación en batch para reducir overhead
- **Histogram buckets**: Elegir buckets apropiados para no gastar memoria

## Configuration Options
```typescript
const metrics = new Metrics({
  // Configuración global
  prefix: 'jamx_',        // prefijo para nombres de métricas
  defaultLabels: { env: 'production' }, // labels por defecto
  sampling: 1.0,          // 1.0 = 100%, 0.1 = 10%
  autoFlush: true,       // flush automático a backend
  flushInterval: 5000,   // ms entre flushes
});

const health = new Health({
  timeout: 10000,        // timeout por defecto para checks
  parallel: true,        // ejecutar checks en paralelo
  cacheDuration: 30000,  // cachear resultados por 30s
});
```

## Testing
Tests en `packages/metrics/tests/unit/`:

```bash
pnpm test
```

Cubre:
- Creación de contadores, gauges, histogramas
- Incrementos y observaciones
- Health checks simples y compuestos
- Middleware HTTP
- Exportación a formatos

## Compatibility
- Compatible con Node.js 18+
- Exporta a Prometheus text format
- Integra con OpenTelemetry (opcional)
- Funciona en Windows, macOS, Linux

## CLI Integration
- `jamx metrics:export <format>`: Exporta métricas a formato específico
- `jamx health:check`: Ejecuta health checks y muestra resultado
- `jamx metrics:reset`: Limpia métricas acumuladas
- `jamx metrics:tail`: Muestra métricas en tiempo real (como `top`)

## Best Practices
1. **Usar nombres consistentes**: `http_requests_total`, `db_query_duration_seconds`
2. **Limitar cardinalidad**: Evitar etiquetas con alta cardinalidad (user_id, session_id)
3. **Health checks rápidos**: Los checks deben terminar en segundos, no minutos
4. **Dependencias claras**: Documentar dependencias entre health checks
5. **Alertas basadas en métricas**: Configurar alertas en Prometheus/Grafana
6. **Métricas de negocio**: Además de técnicas, registrar métricas de negocio (signups, purchases)
7. **Sampling en producción**: Para alto tráfico, usar sampling para reducir overhead

This metrics module provides comprehensive observability for JAMX applications, enabling developers to monitor performance, detect issues, and understand application behavior in production environments.