> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Metrics

> Custom metrics collection middleware for application monitoring.

## Overview

The `metrics` middleware collects custom application metrics including request counts, latencies, and error rates.

Use it when you need:

* Application monitoring
* Custom metric collection
* Performance tracking

## Installation

```go theme={null}
import "github.com/go-mizu/mizu/middlewares/metrics"
```

## Quick Start

```go theme={null}
app := mizu.New()

m := metrics.New()
app.Use(m.Middleware())

// Expose metrics endpoint
app.Get("/metrics", m.Handler())
```

## Configuration

### Options

| Option      | Type        | Default  | Description      |
| ----------- | ----------- | -------- | ---------------- |
| `Namespace` | `string`    | `"http"` | Metric namespace |
| `Buckets`   | `[]float64` | Standard | Latency buckets  |

## Examples

### Basic Metrics

```go theme={null}
m := metrics.New()
app.Use(m.Middleware())
app.Get("/metrics", m.Handler())
```

### Custom Namespace

```go theme={null}
m := metrics.New(metrics.Options{
    Namespace: "myapp",
})
```

### Custom Buckets

```go theme={null}
m := metrics.New(metrics.Options{
    Buckets: []float64{0.01, 0.05, 0.1, 0.5, 1, 5},
})
```

### Add Custom Metrics

```go theme={null}
m := metrics.New()

// Counter
m.Counter("jobs_processed", "Total jobs processed")
m.Inc("jobs_processed")

// Gauge
m.Gauge("active_connections", "Active connections")
m.Set("active_connections", 42)

// Histogram
m.Histogram("job_duration", "Job duration", buckets)
m.Observe("job_duration", 1.5)
```

## Default Metrics

| Metric                          | Type      | Description     |
| ------------------------------- | --------- | --------------- |
| `http_requests_total`           | Counter   | Total requests  |
| `http_request_duration_seconds` | Histogram | Request latency |
| `http_requests_in_flight`       | Gauge     | Active requests |

## API Reference

### Functions

```go theme={null}
// New creates metrics collector
func New(opts ...Options) *Metrics

// Middleware returns metrics middleware
func (m *Metrics) Middleware() mizu.Middleware

// Handler returns metrics HTTP handler
func (m *Metrics) Handler() mizu.Handler

// Custom metrics
func (m *Metrics) Counter(name, help string)
func (m *Metrics) Gauge(name, help string)
func (m *Metrics) Histogram(name, help string, buckets []float64)
func (m *Metrics) Inc(name string)
func (m *Metrics) Set(name string, value float64)
func (m *Metrics) Observe(name string, value float64)
```

## Technical Details

### Core Components

The metrics middleware consists of the following key components:

#### Metrics Structure

* **RequestCount**: Total number of HTTP requests processed (atomic int64)
* **ErrorCount**: Total number of errors (4xx and 5xx status codes, atomic int64)
* **TotalDuration**: Cumulative duration of all requests in nanoseconds (atomic int64)
* **ActiveRequests**: Number of currently in-flight requests (atomic int64)
* **statusCodes**: Map tracking counts for each HTTP status code
* **pathCounts**: Map tracking request counts per URL path

#### Thread Safety

All counters use atomic operations (`atomic.AddInt64`, `atomic.LoadInt64`, `atomic.StoreInt64`) to ensure thread-safe concurrent access without explicit locking for the main counters. Maps (`statusCodes` and `pathCounts`) are protected by a `sync.RWMutex` to safely handle concurrent reads and writes.

#### Status Capture Mechanism

The middleware uses a custom `statusCapture` wrapper that implements `http.ResponseWriter` to intercept the status code before writing the response. This allows tracking of status codes even when they're set by downstream handlers.

#### Metrics Calculation

* **Average Duration**: Calculated as `TotalDuration / RequestCount` and converted to milliseconds
* **Error Detection**: Requests are counted as errors when `err != nil` or `statusCode >= 400`

### Output Formats

The middleware supports two output formats:

1. **JSON Format** (`Handler()`): Returns statistics as JSON with fields:
   * `request_count`, `error_count`, `active_requests`
   * `average_duration_ms`, `status_codes`, `path_counts`

2. **Prometheus Format** (`Prometheus()`): Exports metrics in Prometheus text format:
   * `http_requests_total` (counter)
   * `http_errors_total` (counter)
   * `http_active_requests` (gauge)

### Implementation Notes

* Uses custom `itoa()` function for integer to string conversion to avoid allocations
* Metrics can be reset using `Reset()` method which clears all counters and maps
* The middleware does not affect the response or request flow, only observes them

## Best Practices

* Use meaningful metric names
* Add labels for dimensions
* Set appropriate histogram buckets
* Monitor metric cardinality

## Testing

The metrics middleware includes comprehensive test coverage for all functionality:

| Test Case                     | Description                               | Expected Behavior                                                |
| ----------------------------- | ----------------------------------------- | ---------------------------------------------------------------- |
| `TestNew`                     | Basic initialization and request counting | Creates middleware, counts single request correctly              |
| `TestMetrics_StatusCodes`     | HTTP status code tracking                 | Tracks 200 and 500 status codes separately, counts 500 as error  |
| `TestMetrics_PathCounts`      | URL path request counting                 | Counts requests per path (3 to /api/users, 1 to /api/posts)      |
| `TestMetrics_Handler`         | JSON metrics endpoint                     | Returns metrics as JSON with correct Content-Type header         |
| `TestMetrics_Prometheus`      | Prometheus format export                  | Returns Prometheus-formatted metrics with http\_requests\_total  |
| `TestMetrics_Reset`           | Metrics reset functionality               | Resets all counters to zero after processing requests            |
| `TestMetrics_Concurrent`      | Thread-safe concurrent access             | Correctly counts 100 concurrent requests without race conditions |
| `TestMetrics_AverageDuration` | Duration measurement                      | Calculates positive average duration for requests                |
| `TestMetrics_JSON`            | JSON serialization                        | Marshals stats to JSON with request\_count field                 |

## Related Middlewares

* [prometheus](/middlewares/prometheus) - Prometheus format
* [timing](/middlewares/timing) - Server-Timing header
* [healthcheck](/middlewares/healthcheck) - Health checks
