> ## 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.

# Timing

> Server-Timing header middleware for performance monitoring.

## Overview

The `timing` middleware adds Server-Timing headers to responses, allowing you to measure and report server-side performance metrics. These metrics are visible in browser DevTools.

## Installation

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

## Quick Start

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

## Examples

### Basic Usage

```go theme={null}
app.Use(timing.New())

app.Get("/", func(c *mizu.Ctx) error {
    // Total time is automatically tracked
    return c.JSON(200, data)
})
// Response header: Server-Timing: total;dur=12.34
```

### Track Custom Metrics

```go theme={null}
app.Get("/users", func(c *mizu.Ctx) error {
    // Track database query time
    start := time.Now()
    users, err := db.GetUsers()
    timing.Add(c, "db", time.Since(start), "Database query")

    // Track serialization time
    start = time.Now()
    data := serialize(users)
    timing.Add(c, "serialize", time.Since(start), "JSON serialization")

    return c.JSON(200, data)
})
// Server-Timing: total;dur=45.67, db;dur=30.12;desc="Database query", serialize;dur=5.23;desc="JSON serialization"
```

### Using Start/Stop Pattern

```go theme={null}
app.Get("/data", func(c *mizu.Ctx) error {
    // Start a timing measurement
    stop := timing.Start(c, "external_api")

    resp, err := http.Get("https://api.example.com/data")
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    // Stop and record with description
    stop("External API call")

    return c.JSON(200, resp.Body)
})
```

### Using Track Helper

```go theme={null}
app.Get("/compute", func(c *mizu.Ctx) error {
    var result int

    // Track a function call
    timing.Track(c, "calculation", func() {
        result = expensiveCalculation()
    })

    return c.JSON(200, map[string]int{"result": result})
})
```

### Multiple Metrics

```go theme={null}
app.Get("/dashboard", func(c *mizu.Ctx) error {
    // Track multiple operations
    stopAuth := timing.Start(c, "auth")
    user := authenticateUser(c)
    stopAuth("Authentication")

    stopData := timing.Start(c, "data")
    dashboard := loadDashboard(user.ID)
    stopData("Load dashboard data")

    stopRender := timing.Start(c, "render")
    html := renderTemplate(dashboard)
    stopRender("Template rendering")

    return c.HTML(200, html)
})
// Server-Timing: total;dur=120.50, auth;dur=15.20;desc="Authentication", data;dur=80.30;desc="Load dashboard data", render;dur=25.00;desc="Template rendering"
```

## API Reference

```go theme={null}
func New() mizu.Middleware
func Add(c *mizu.Ctx, name string, duration time.Duration, description string)
func Start(c *mizu.Ctx, name string) func(description string)
func Track(c *mizu.Ctx, name string, fn func())
```

### Functions

| Function  | Description                                                 |
| --------- | ----------------------------------------------------------- |
| `New()`   | Creates the timing middleware                               |
| `Add()`   | Adds a metric with name, duration, and optional description |
| `Start()` | Starts timing and returns a stop function                   |
| `Track()` | Times a function execution                                  |

## Response Header Format

```
Server-Timing: <name>;dur=<milliseconds>;desc="<description>"
```

Multiple metrics are comma-separated:

```
Server-Timing: total;dur=150.00, db;dur=45.20;desc="Query users", cache;dur=2.10;desc="Redis lookup"
```

## Viewing in Browser

Open DevTools → Network → Select request → Timing tab to see:

* Total server processing time
* Individual metric breakdowns
* Descriptions for each metric

## Technical Details

### Implementation Architecture

The timing middleware uses a context-based storage mechanism to track performance metrics throughout the request lifecycle.

#### Core Components

1. **timingData Structure**
   * Thread-safe metric storage using `sync.Mutex`
   * Tracks request start time
   * Maintains a slice of custom metrics

2. **Context Integration**
   * Uses typed context key for type-safe storage
   * Stores timing data in request context
   * Enables metric collection across handler chain

3. **Metric Recording**
   * Metrics stored as `{name, duration, description}` tuples
   * Total duration calculated from request start time
   * All durations converted to milliseconds (microseconds/1000)

#### Header Generation

The middleware builds the Server-Timing header after handler execution:

* Total time is always included first
* Custom metrics appended in order of addition
* Format: `name;dur=<ms>;desc="<description>"`
* Multiple metrics joined with `, ` separator

#### Thread Safety

All metric operations are protected by mutex locks:

* `Add()` acquires lock before appending metrics
* Header generation locks before reading metrics
* Safe for concurrent metric recording

## Best Practices

* Track database queries, cache lookups, and external API calls
* Use descriptive names for metrics
* Add descriptions for clarity
* Keep metric names short and consistent
* Use the Start/Stop pattern for cleaner code

## Testing

### Test Coverage

| Test Case                 | Description                                     | Expected Behavior                                                           |
| ------------------------- | ----------------------------------------------- | --------------------------------------------------------------------------- |
| `TestNew`                 | Basic middleware functionality                  | Sets Server-Timing header with total duration after 10ms sleep              |
| `TestAdd`                 | Adding custom metrics with/without descriptions | Includes "db;dur=50" with description and "cache;dur=5" without description |
| `TestStart`               | Start/Stop pattern for timing operations        | Records operation duration (\~20ms) with "Long operation" description       |
| `TestTrack`               | Track helper for timing function execution      | Records compute duration (\~15ms) without description                       |
| `TestAdd_NoMiddleware`    | Graceful handling when middleware not installed | Add() doesn't panic, returns successfully                                   |
| `TestNew_MultipleMetrics` | Multiple metrics in single request              | Header contains 4 entries (total + 3 custom metrics)                        |

## Related Middlewares

* [requestid](/middlewares/requestid) - Request tracing
* [timeout](/middlewares/timeout) - Request timeout
