# Deno's built-in OpenTelemetry

> Turn on OTEL_DENO so Deno creates spans for Deno.serve and fetch and sends console output as logs; the no-retry limitation and how to work around it.

Deno 2 has OpenTelemetry built in. With one variable it creates a server span for every `Deno.serve` request, a client span for every `fetch`, sends `console.*` output as log records with the active trace id, and exports with the [standard variables](https://belvador.dev/en/docs/otel/quickstart#2-set-the-standard-variables). No packages to install.

> **Tested on 2026-10-24** with deno 2.6.10: traces passed, logs passed, logs carry the request's trace and span. Proven limitation: no retry on 429/503.

## Run

```bash
export OTEL_DENO=true
deno run --allow-net --allow-env main.ts
```

Deno 2.2 and 2.3 also needed the `--unstable-otel` flag; current versions do not.

## Logs

`console.log` becomes an `INFO` record, `console.warn` a `WARN` record and `console.error` an `ERROR` record, each with the trace id and span id of the request it ran in. Output still goes to the terminal as before.

## Limitation: no retry

Belvador's run shows that Deno's built-in exporter does **not** send a batch again after a `429` or `503` answer — that batch is lost. Belvador answers those codes only when your quota or rate limit is reached or the edge is briefly unable to take data, but if losing a batch then matters, run a local [Collector](https://belvador.dev/en/docs/otel/collector) next to the app and point Deno at it; the Collector queues and retries:

```bash
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
unset OTEL_EXPORTER_OTLP_HEADERS   # the Collector holds the Belvador key
```

This check runs on every certification, so the note disappears when Deno starts retrying.

## Deno Deploy

Deno Deploy configures its own telemetry; sending it to Belvador has not been tested.
