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

# OpenTelemetry

> OpenTelemetry integration middleware for distributed tracing and metrics.

## Overview

The `otel` middleware integrates with OpenTelemetry for distributed tracing, metrics, and observability.

Use it when you need:

* Distributed tracing
* OpenTelemetry integration
* Observability platforms (Jaeger, Zipkin, etc.)

## Installation

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

## Quick Start

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

// Initialize OpenTelemetry
shutdown := otel.Init(otel.Options{
    ServiceName: "my-service",
    Endpoint:    "localhost:4317",
})
defer shutdown()

app.Use(otel.Middleware())
```

## Configuration

### Options

| Option        | Type       | Default  | Description         |
| ------------- | ---------- | -------- | ------------------- |
| `ServiceName` | `string`   | Required | Service name        |
| `Endpoint`    | `string`   | Required | Collector endpoint  |
| `Insecure`    | `bool`     | `false`  | Skip TLS            |
| `Propagators` | `[]string` | W3C      | Propagation formats |

## Examples

### Basic Setup

```go theme={null}
shutdown := otel.Init(otel.Options{
    ServiceName: "api",
    Endpoint:    "localhost:4317",
})
defer shutdown()

app.Use(otel.Middleware())
```

### With Jaeger

```go theme={null}
shutdown := otel.Init(otel.Options{
    ServiceName: "api",
    Endpoint:    "jaeger:4317",
    Propagators: []string{"jaeger", "w3c"},
})
```

### Custom Spans

```go theme={null}
app.Get("/process", func(c *mizu.Ctx) error {
    ctx, span := otel.StartSpan(c, "process-data")
    defer span.End()

    // Add attributes
    span.SetAttributes(
        attribute.String("user.id", userID),
    )

    // Do work
    result := processData(ctx)

    return c.JSON(200, result)
})
```

### Propagate to Downstream

```go theme={null}
app.Get("/", func(c *mizu.Ctx) error {
    req, _ := http.NewRequestWithContext(c.Context(), "GET", url, nil)
    otel.Inject(c.Context(), req.Header)
    // Make request...
})
```

## API Reference

### Functions

```go theme={null}
// Init initializes OpenTelemetry
func Init(opts Options) func()

// Middleware creates OTel middleware
func Middleware() mizu.Middleware

// StartSpan creates child span
func StartSpan(c *mizu.Ctx, name string) (context.Context, trace.Span)

// Inject propagates context
func Inject(ctx context.Context, headers http.Header)
```

## Technical Details

### Architecture

The otel middleware is a lightweight OpenTelemetry-compatible implementation that provides distributed tracing without external dependencies. It implements the OpenTelemetry specification for trace context propagation.

### Components

**SpanContext**: Holds the trace context with TraceID (16 bytes), SpanID (8 bytes), TraceFlags, and optional TraceState.

**Span**: Represents a single operation with metadata including:

* Name (HTTP method + path)
* Parent/child relationships
* Start/end timestamps
* Status (Unset, OK, Error)
* Attributes (key-value pairs)
* Events (timestamped logs)
* Links (connections to other spans)

**SpanProcessor**: Interface for processing completed spans. Implementations include:

* `InMemoryProcessor`: Stores spans in memory for testing
* `PrintProcessor`: Prints spans to stdout
* Custom processors can export to external systems

### Propagation Formats

**W3C Trace Context (default)**:

* Header: `Traceparent: 00-{traceId}-{spanId}-{flags}`
* Optional: `Tracestate` for vendor-specific data
* Format: `version-traceId-spanId-flags`

**B3 Propagation**:

* Single header: `B3: {traceId}-{spanId}-{sampled}`
* Multi-header: `X-B3-Traceid`, `X-B3-Spanid`, `X-B3-Sampled`
* Compatible with Zipkin and other B3-based systems

### ID Generation

* TraceID: 128-bit (16 bytes) cryptographically random hex string
* SpanID: 64-bit (8 bytes) cryptographically random hex string
* Generated using `crypto/rand` for uniqueness

### Request Flow

1. Extract parent context from incoming request headers
2. Create new span with inherited TraceID or generate new one
3. Generate new SpanID for current span
4. Add default HTTP attributes (method, URL, status, etc.)
5. Call OnStart hook if configured
6. Inject trace context into response headers
7. Store span in request context
8. Execute handler
9. Set final status and attributes based on response
10. Call OnEnd hook and SpanProcessor

### Thread Safety

* Span methods use mutex locks for concurrent access
* InMemoryProcessor is thread-safe with mutex protection
* Safe for use with concurrent requests

## Best Practices

* Use consistent service names
* Add meaningful span attributes
* Propagate context to all calls
* Sample appropriately in production

## Testing

The otel middleware includes comprehensive test coverage for all features:

| Test Case                      | Description                   | Expected Behavior                                                                                        |
| ------------------------------ | ----------------------------- | -------------------------------------------------------------------------------------------------------- |
| `TestNew`                      | Basic middleware creation     | Creates middleware with default options and processes requests successfully                              |
| `TestSpanCreation`             | Span generation               | Creates span with correct name (HTTP method + path), generates TraceID and SpanID                        |
| `TestSpanAttributes`           | Attribute collection          | Captures service.name, service.version, http.method, http.status\_code, http.user\_agent                 |
| `TestW3CTracePropagation`      | W3C Trace Context propagation | Inherits TraceID from parent, generates new SpanID, sets parent relationship, injects traceparent header |
| `TestB3Propagation`            | B3 single header format       | Extracts trace context from B3 header, injects B3 headers in response                                    |
| `TestB3MultiHeaderPropagation` | B3 multi-header format        | Extracts trace context from X-B3-\* headers, maintains compatibility                                     |
| `TestSkipPaths`                | Path filtering                | Skips configured paths (e.g., /health), traces non-skipped paths                                         |
| `TestSampler`                  | Custom sampling               | Respects sampler function, only creates spans for sampled requests                                       |
| `TestErrorStatus`              | Error handling                | Sets StatusError for HTTP 4xx/5xx responses, captures error attributes                                   |
| `TestOnStartOnEnd`             | Lifecycle hooks               | Calls OnStart when span begins, OnEnd when span completes                                                |
| `TestGetSpan`                  | Context access                | Retrieves span from context, allows custom attributes and events                                         |
| `TestSpanDuration`             | Timing measurement            | Calculates span duration, sets end time correctly                                                        |
| `TestSpanContextIsValid`       | Context validation            | Validates SpanContext has TraceID and SpanID                                                             |
| `TestSpanContextIsSampled`     | Sampling flag check           | Correctly interprets trace flags for sampling decision                                                   |
| `TestInMemoryProcessor`        | Span processing               | Stores spans, retrieves all spans, clears span storage                                                   |

## Related Middlewares

* [trace](/middlewares/trace) - Simple tracing
* [prometheus](/middlewares/prometheus) - Prometheus metrics
* [sentry](/middlewares/sentry) - Error tracking
