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

# Wire OpenTelemetry Tracing

> theauth-go ships a pluggable Tracer adapter.

theauth-go ships a pluggable `Tracer` adapter. The library has zero hard dependency on OpenTelemetry or any other tracing vendor. You wire your own adapter at startup.

## How the adapter works

The library calls `hooks.Tracer.Start(ctx, spanName, attrs...)` at the entry point of every instrumented operation, then records the outcome with `span.RecordError(err)` (on failure) and `span.SetAttributes(...)` before calling `span.End()`. The `Tracer` and `Span` interfaces are defined in `theauth.Tracer` and `theauth.Span` (re-exported from `internal/observability`).

## Write an OpenTelemetry adapter

```go theme={"dark"}
package otelbridge

import (
    "context"

    "github.com/glincker/theauth-go/v2"
    "go.opentelemetry.io/otel/attribute"
    "go.opentelemetry.io/otel/codes"
    oteltrace "go.opentelemetry.io/otel/trace"
)

type otelTracer struct{ t oteltrace.Tracer }

func New(t oteltrace.Tracer) theauth.Tracer { return &otelTracer{t: t} }

// Start implements theauth.Tracer.
func (o *otelTracer) Start(ctx context.Context, name string, attrs ...theauth.Attr) (context.Context, theauth.Span) {
    otelAttrs := make([]attribute.KeyValue, len(attrs))
    for i, a := range attrs {
        otelAttrs[i] = attribute.String(a.Key, fmt.Sprint(a.Value))
    }
    ctx, span := o.t.Start(ctx, name, oteltrace.WithAttributes(otelAttrs...))
    return ctx, &otelSpan{span: span}
}

type otelSpan struct{ span oteltrace.Span }

// SetAttributes implements theauth.Span.
func (s *otelSpan) SetAttributes(attrs ...theauth.Attr) {
    otelAttrs := make([]attribute.KeyValue, len(attrs))
    for i, a := range attrs {
        otelAttrs[i] = attribute.String(a.Key, fmt.Sprint(a.Value))
    }
    s.span.SetAttributes(otelAttrs...)
}

// RecordError implements theauth.Span.
func (s *otelSpan) RecordError(err error) {
    if err == nil {
        return
    }
    s.span.RecordError(err)
    s.span.SetStatus(codes.Error, err.Error())
}

// End implements theauth.Span. Note it takes no arguments: the library
// reports outcome via RecordError/SetAttributes before calling End.
func (s *otelSpan) End() {
    s.span.End()
}
```

## Wire the adapter

```go theme={"dark"}
import (
    "go.opentelemetry.io/otel"
    "github.com/glincker/theauth-go/v2"
    otelbridge "myapp/internal/otelbridge"
)

hooks := &theauth.Hooks{
    Tracer: otelbridge.New(otel.Tracer("theauth-go")),
}

a, _ := theauth.New(theauth.Config{
    Storage:       store,
    BaseURL:       "https://myapp.com",
    Observability: hooks,
})
```

## Span catalog

See [Spans Reference](/go/reference/spans) for the full list of span names and their attributes. Span names are also exported as constants (`theauth.SpanOAuthToken`, etc.) so dashboards can reference them by symbol.

## Example adapter

A reference OpenTelemetry adapter ships in the repository at `examples/observability-otel/`. It is not a published package; copy it into your codebase and adjust as needed.

## Adding metrics alongside tracing

To add Prometheus metrics alongside OpenTelemetry traces, also wire a `Metrics` adapter. See the `Hooks` struct:

```go theme={"dark"}
hooks := &theauth.Hooks{
    Tracer:  otelbridge.New(otel.Tracer("theauth-go")),
    Metrics: prombridge.New(prometheus.DefaultRegisterer),
}
```

See [Metrics Reference](/go/reference/metrics) for the full metric catalog.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.