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

Opaque 128-bit Trace identifier (W3C `trace-id` / OTel
`trace/api.md` §SpanContext TraceId, L231-L232).

The OTel spec defines a valid `TraceId` as a 16-byte array
with at least one non-zero byte (L231-L232). On the wire,
W3C Trace Context encodes it as a 32-character lowercase hex
string (`trace-id = 32HEXDIGLC`, §trace-id). Internally we
store it as a non-negative 128-bit integer and expose it
through `@opaque` so Dialyzer distinguishes it from
unrelated integers — and from `Otel.Trace.SpanId`.

Per spec L266 *"The API SHOULD NOT expose details about how
they are internally stored"* — callers go through `to_hex/1`
/ `to_bytes/1` rather than the raw integer. The
`to_integer/1` escape hatch exists for SDK code that needs
to perform bit arithmetic on the id.

## Public API

| Function | Role |
|---|---|
| `valid?/1` | **Application** (OTel API MUST) — IsValid for TraceId (L231-L232, L268-L271) |
| `to_hex/1` | **Application** (OTel API MUST) — Hex retrieval (L258-L262) |
| `to_bytes/1` | **Application** (OTel API MUST) — Binary retrieval (L263-L264) |
| `new/1` | **SDK** (SDK helper) — wrap a 128-bit integer from an ID generator |
| `to_integer/1` | **SDK** (SDK helper) — bit-arithmetic escape hatch for samplers |

## References

- OTel Trace API §SpanContext TraceId: `opentelemetry-specification/specification/trace/api.md` L231-L232, L256-L266
- W3C Trace Context Level 2 §trace-id: `w3c-trace-context/spec/20-http_request_header_format.md` §trace-id

# `t`

```elixir
@opaque t()
```

A 128-bit Trace identifier (W3C `trace-id`).

Stored as a `0..2^128 - 1` integer but declared `@opaque` so
callers cannot construct one with an arbitrary integer literal
from outside the module. Use `new/1` at construction
boundaries (e.g. random generation in the SDK id generator)
and `to_hex/1` / `to_bytes/1` for serialisation.

The all-zero value is reserved as the invalid sentinel meaning
"no trace"; `valid?/1` returns `false` for it (spec L231-L232 +
W3C §trace-id L103).

# `new`

```elixir
@spec new(integer :: 0..340_282_366_920_938_463_463_374_607_431_768_211_455) :: t()
```

**SDK** (SDK helper) — wrap a 128-bit unsigned integer as a
`t()`.

The opaque-boundary-respecting way to turn a raw integer (e.g.
from an ID generator) into a `TraceId.t()`. The `@spec` input
range is the type gate — Dialyzer flags literal out-of-range
callers; runtime-origin values are the caller's
responsibility.

# `to_bytes`

```elixir
@spec to_bytes(trace_id :: t()) :: &lt;&lt;_::128&gt;&gt;
```

**Application** (OTel API MUST) — "Binary Retrieval"
(`trace/api.md` L263-L264).

Returns the TraceId as a 16-byte big-endian binary.

# `to_hex`

```elixir
@spec to_hex(trace_id :: t()) :: &lt;&lt;_::256&gt;&gt;
```

**Application** (OTel API MUST) — "Hex Retrieval"
(`trace/api.md` L258-L262).

Returns the TraceId as a **32-character lowercase** hex string
(zero-padded). Matches the W3C `trace-id` wire format
(§trace-id: `32HEXDIGLC`).

# `to_integer`

```elixir
@spec to_integer(trace_id :: t()) :: non_neg_integer()
```

**SDK** (SDK helper) — underlying non-negative integer escape
hatch.

Exposed so SDK components can perform bit arithmetic on the
TraceId (e.g. `TraceIdRatioBased` takes the lower 64 bits as a
probability hash). Application code should prefer `to_hex/1`
or `to_bytes/1`.

# `valid?`

```elixir
@spec valid?(trace_id :: term()) :: boolean()
```

**Application** (OTel API MUST) — "IsValid for TraceId"
(`trace/api.md` L231-L232, L268-L271).

Returns `true` iff the TraceId has at least one non-zero byte.
Per spec the all-zero value
(`00000000000000000000000000000000`) is explicitly invalid
(W3C §trace-id L103).

Accepts any term as a robust predicate — returns `false` for
`0`, negatives, out-of-range integers, and non-integers.

---

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