# `Otel.Trace.SpanExporter`
[🔗](https://github.com/yangbancode/otel/blob/main/lib/otel/trace/span_exporter.ex#L1)

Trace export pipeline — timer-driven take from `SpanStorage` +
OTLP encode + HTTP POST. Single GenServer absorbing what was
previously split between `SpanProcessor` (queue + timer + drain)
and a HTTP-only Exporter.

## Lifecycle

| Trigger | Action |
|---|---|
| `:loop` self-message every `@scheduled_delay_ms` | take one batch (`@max_export_batch_size`) of `:completed` spans, encode, POST |
| `force_flush/1` | drain *all* completed spans synchronously |
| `terminate/2` | drain remaining spans before exit |

## OTLP HTTP transport

POSTs OTLP/protobuf via [`Req`](https://hex.pm/packages/req).
User config is read from
`Application.get_env(:otel, :req_options, [])` on every export
and forwarded to `Req.post/1` — anything Req accepts (TLS,
auth, timeouts, retry overrides, mock plugs) works.

The SDK only forces `:body` (the encoded protobuf). Defaults
via `Keyword.put_new`:

- `:base_url` → `http://localhost:4318` if absent
- `:url` → `/v1/traces` if absent
- `:retry` → predicate matching the OTLP-spec retryable
  response codes (`opentelemetry-proto/docs/specification.md`
  L564-575: 429 / 502 / 503 / 504 SHOULD be retried, all
  other 4xx / 5xx MUST NOT) plus network-level exceptions.
  Backoff strategy (exponential + jitter) and `Retry-After`
  honoring come from Req's default `:retry_delay`, which
  satisfies the spec MUST in
  `opentelemetry-specification/specification/protocol/exporter.md`
  L182-202.
- `content-type: application/x-protobuf` and `user-agent`
  headers merged into the user's `:headers`

`:max_retries` is left to Req's default (3 retries = 4
attempts) — the OTLP spec mandates the *strategy* but not a
specific attempt count.

## References

- OTel Trace SDK §Batching processor: `opentelemetry-specification/specification/trace/sdk.md` L1086-L1118
- OTel Trace SDK §SpanExporter: `opentelemetry-specification/specification/trace/sdk.md` L1119-L1207
- OTLP retryable response codes: `opentelemetry-proto/docs/specification.md` L565-L573

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `force_flush`

```elixir
@spec force_flush(timeout :: timeout()) :: :ok
```

# `start_link`

```elixir
@spec start_link(opts :: keyword()) :: GenServer.on_start()
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
