src — metrics

Module: src-metrics Cohesion: 0.80 Members: 0

src — metrics

The src/metrics module provides a robust, centralized system for collecting, managing, and exporting application and system metrics. It's designed to give developers deep insights into the application's performance, resource usage, and operational health, supporting both real-time monitoring and historical analysis.

This module supports common metric types (Counters, Gauges, Histograms) and offers flexible export options, including Prometheus-compatible format, file-based logging, and integration with OpenTelemetry.

1. Core Concepts

The module revolves around three fundamental metric types:

All metric types support labels, which are key-value pairs that add dimensions to a metric, allowing for more granular analysis (e.g., requests_total{endpoint="/api/chat", method="POST"}).

2. Architecture Overview

The MetricsCollector class is the central hub for all metrics. It manages the lifecycle of individual Counter, Gauge, and Histogram instances, collects system-level metrics, and orchestrates the export process.

A singleton pattern is used to ensure a single, globally accessible MetricsCollector instance throughout the application, managed by initMetrics and getMetrics.

classDiagram
    direction LR
    class MetricsCollector {
        +init()
        +createCounter(name, help, unit)
        +createGauge(name, help, unit)
        +createHistogram(name, help, buckets, unit)
        +getSnapshot(): MetricsSnapshot
        +toPrometheus(): string
        +export()
        +requestsTotal: Counter
        +apiLatency: Histogram
        +memoryUsage: Gauge
        -collectSystemMetrics()
        -exportToFile(snapshot)
    }
    class Counter {
        +inc(labels, value)
        +getValues(): CounterValue[]
        -labelsToKey(labels)
    }
    class Gauge {
        +set(value, labels)
        +inc(labels, value)
        +dec(labels, value)
        +getValues(): GaugeValue[]
        -labelsToKey(labels)
    }
    class Histogram {
        +observe(value, labels)
        +startTimer(labels): () => number
        +getValues(): HistogramValue[]
        -labelsToKey(labels)
    }

    MetricsCollector "1" *-- "N" Counter : manages
    MetricsCollector "1" *-- "N" Gauge : manages
    MetricsCollector "1" *-- "N" Histogram : manages

    function initMetrics
    function getMetrics

    initMetrics --> MetricsCollector : creates singleton
    getMetrics --> MetricsCollector : retrieves singleton

3. Key Components

3.1. MetricsCollector Class

The MetricsCollector is the primary interface for interacting with the metrics system.

  1. Generates a MetricsSnapshot.
  2. Adds the snapshot to an in-memory history buffer (capped by maxHistorySize).
  3. If consoleExport is enabled, logs a summary to the console.
  4. If fileExport is enabled, calls exportToFile() to append the snapshot to a daily JSONL file.
  5. Emits an export event with the snapshot.

3.2. Counter Class

Represents a single counter metric.

3.3. Gauge Class

Represents a single gauge metric.

3.4. Histogram Class

Represents a single histogram metric.

3.5. Helper Functions

For convenience, the module provides global helper functions that interact with the singleton MetricsCollector instance:

3.6. Pre-defined Metrics

The MetricsCollector automatically initializes several common metrics:

These pre-defined metrics are directly accessible as properties of the MetricsCollector instance (e.g., metrics.requestsTotal.inc()).

4. Configuration (MetricsConfig)

The behavior of the MetricsCollector is configured via the MetricsConfig interface:

export interface MetricsConfig {
  consoleExport?: boolean; class="hl-cmt">// Enable console export (debug mode)
  fileExport?: boolean;    class="hl-cmt">// Enable file export
  filePath?: string;       class="hl-cmt">// File export path (default: ~/.codebuddy/metrics)
  exportInterval?: number; class="hl-cmt">// Export interval in milliseconds (default: 60000ms / 1 minute)
  otelExport?: boolean;    class="hl-cmt">// Enable OpenTelemetry export (handled by OpenTelemetryIntegration)
  defaultBuckets?: number[]; class="hl-cmt">// Default histogram buckets (default: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10])
  maxHistorySize?: number; class="hl-cmt">// Max metrics history size (default: 1000)
}

5. Usage Examples

import { initMetrics, getMetrics, measureTime, incCounter, setGauge } from './metrics';

class="hl-cmt">// 1. Initialize metrics (call once at application startup)
const metrics = initMetrics({
  consoleExport: true, class="hl-cmt">// Log summaries to console
  fileExport: true,    class="hl-cmt">// Export to daily JSONL files
  exportInterval: 30000, class="hl-cmt">// Export every 30 seconds
});

class="hl-cmt">// 2. Use pre-defined metrics
metrics.requestsTotal.inc({ endpoint: '/api/chat', method: 'POST' });
metrics.tokensUsed.inc({ type: 'prompt', model: 'gpt-4' }, 1500);
metrics.activeSessions.set(5); class="hl-cmt">// Set current active sessions

class="hl-cmt">// 3. Measure latency with a histogram timer
async function handleChatRequest() {
  const end = metrics.apiLatency.startTimer({ endpoint: '/api/chat' });
  try {
    class="hl-cmt">// Simulate API call
    await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));
  } finally {
    end(); class="hl-cmt">// Records the duration automatically
  }
}
handleChatRequest();

class="hl-cmt">// 4. Create and use custom metrics
const myCustomCounter = metrics.createCounter('my_app_events_total', 'Total custom application events');
myCustomCounter.inc({ event_type: 'user_login' });

const myCustomGauge = metrics.createGauge('my_app_queue_size', 'Current size of processing queue');
myCustomGauge.set(10);

class="hl-cmt">// 5. Using helper functions for convenience
incCounter('codebuddy_tool_executions_total', { tool_name: 'search' });
setGauge('codebuddy_active_connections', 100, { type: 'websocket' });

class="hl-cmt">// 6. Measure time with helper function
async function performComplexTask() {
  return measureTime('codebuddy_tool_duration_seconds', { tool_name: 'complex_analysis' }, async () => {
    class="hl-cmt">// Simulate complex task
    await new Promise(resolve => setTimeout(resolve, Math.random() * 5000));
    return 'task_completed';
  });
}
performComplexTask();

class="hl-cmt">// 7. Accessing current snapshot or Prometheus format
class="hl-cmt">// (Typically exposed via an HTTP endpoint for Prometheus scraping)
class="hl-cmt">// const prometheusMetrics = metrics.toPrometheus();
class="hl-cmt">// console.log(prometheusMetrics);

class="hl-cmt">// 8. Shutdown (e.g., on application exit)
class="hl-cmt">// await metrics.shutdown();

6. Integration Points

The metrics module is designed to be integrated throughout the codebase to provide comprehensive observability:

7. Prometheus Compatibility

The MetricsCollector.toPrometheus() method generates output that strictly adheres to the Prometheus text exposition format. This includes:

This allows any Prometheus server to easily scrape and ingest metrics from the application, enabling powerful dashboards and alerting.