# Telemetry

Rebask does not collect or export telemetry itself. It emits OpenTelemetry traces and metrics
through `@opentelemetry/api`, which are no-ops until your app registers an SDK.

## Instrumentation

Rebask calls the `register()` export from an auto-detected `instrumentation.{ts,mts,mjs,js}` file in
the project root before the server starts. Register an SDK, context manager, and propagator there:

```ts
// instrumentation.ts
import { context, metrics, propagation, trace } from "@opentelemetry/api"
import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks"
import { W3CTraceContextPropagator } from "@opentelemetry/core"
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http"
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http"
import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics"
import { BasicTracerProvider, BatchSpanProcessor } from "@opentelemetry/sdk-trace-base"

export function register() {
  trace.setGlobalTracerProvider(
    new BasicTracerProvider({
      spanProcessors: [new BatchSpanProcessor(new OTLPTraceExporter())],
    }),
  )
  context.setGlobalContextManager(new AsyncLocalStorageContextManager())
  propagation.setGlobalPropagator(new W3CTraceContextPropagator())
  metrics.setGlobalMeterProvider(
    new MeterProvider({
      readers: [
        new PeriodicExportingMetricReader({
          exporter: new OTLPMetricExporter(),
        }),
      ],
    }),
  )
}
```

The example uses OTLP/HTTP exporters for traces and metrics. Install the OpenTelemetry packages used
by your exporters.

Server-side, Rebask continues traces across services: incoming propagation headers become the parent
of `rebask.request`, and outgoing `fetch` requests send the active trace context to downstream
services.

## Client traces

Set [`clientTraceMetadata`](./configuration.md#rebask-clienttracemetadata) to expose propagation
headers to the browser:

```ts
rebask({ clientTraceMetadata: ["traceparent"] })
```

The browser sends those headers on navigations, prefetch, and
[Server Function requests](./server-functions.md), so they join the same trace.

## Spans

| Span                   | Covers                                                                |
| ---------------------- | --------------------------------------------------------------------- |
| `rebask.request`       | Incoming requests                                                     |
| `rebask.cache.lookup`  | Page and segment cache lookups                                        |
| `rebask.render`        | Page and segment rendering                                            |
| `rebask.fetch`         | Outgoing `fetch` requests                                             |
| `rebask.use_cache`     | [`"use cache"`](./caching/server-components.md#use-cache) calls       |
| `rebask.durable_cache` | [`durableCache()`](./caching/server-components.md#durablecache) calls |
| `rebask.revalidation`  | [Background revalidations](./caching/cache-lifetimes.md)              |

## Metrics

Rebask emits these metrics when a `MeterProvider` is registered, as in the instrumentation example
above:

| Metric                         | Type      | Measures                        |
| ------------------------------ | --------- | ------------------------------- |
| `rebask.fetch.duration`        | Histogram | Fetch latency                   |
| `rebask.render.duration`       | Histogram | Render latency                  |
| `rebask.cache.lookup.duration` | Histogram | Cache lookup latency            |
| `rebask.revalidation.duration` | Histogram | Background revalidation latency |
| `rebask.cache.hits`            | Counter   | Cache hits                      |
| `rebask.cache.misses`          | Counter   | Cache misses                    |

Durations are in milliseconds.
