# `OpentelemetryStatifier.Attributes`
[🔗](https://github.com/riddler/opentelemetry_statifier/blob/v0.10.0/lib/opentelemetry_statifier/attributes.ex#L1)

The uniform measurement/metadata-to-attribute mapping the design note
(statifier-ex `docs/opentelemetry.md`, "Attribute mapping") fixes, applied
to span events rather than re-decided per event name.

Every attribute lands under the `statifier.` namespace. Measurements are
numbers by contract and pass through as numeric attributes of the same
name. Metadata is mapped by shape:

  * `:effect` is never serialized - the raw struct is for in-VM
    consumers; a wire format is where "the struct rides verbatim" stops
    being cheap.
  * `:location` (a `%Statifier.Parser.Location{}`) flattens to
    `statifier.source.line`/`statifier.source.column` - the one place
    the bridge flattens a struct, because OTel attributes are scalar.
  * `:configuration` (already state-id strings by the ADR-0040 contract)
    becomes a sorted string-array attribute, bounded by the chart's
    state count.
  * `:new_value`, `:prior_value`, and `:datamodel` are the unbounded
    datamodel values: excluded unless the host opted in at setup with
    `record_datamodel_values: true`, and rendered with `inspect/1` when
    it did - they are arbitrary terms, and `inspect/1` is the only
    rendering that needs no per-type policy.
  * everything else is identity metadata: strings and integers pass
    through, atoms become strings, tuples (an `owner`, chart vocabulary
    of bounded shape) render with `inspect/1`, `nil` is omitted rather
    than encoded, and any other shape is dropped - a malformed value
    costs one attribute, never the event.

## Namespaces

The `statifier.` namespace above is the *default* mapping, not the only
one. A sibling family's events map under the sibling package's own
namespace - `statifier_persistence.`, `statifier_oban.` - with the
correlation key aliased onto the shared `statifier.session_id`, so one
attribute joins a step, a timer and a macrostep across all three
families. `mapping/0` and `mapping/2` build those, and every rule above
applies unchanged inside whichever namespace is in force
(`docs/adr/0004-sibling-setup-calls-and-bridge-owned-nesting.md`).

# `mapping`

```elixir
@type mapping() :: %{
  prefix: String.t(),
  aliases: %{required(atom()) =&gt; String.t()},
  drop: [atom()]
}
```

How one event family's keys become attribute names: a namespace
`prefix`, per-key `aliases` that win over it (a full attribute name,
not a prefix), and `drop`ped keys that never become attributes at all.

# `mapping`

```elixir
@spec mapping() :: mapping()
```

The default `statifier.` mapping, used for the
`[:statifier, :session, ...]` family.

# `mapping`

```elixir
@spec mapping(String.t(), %{required(atom()) =&gt; String.t()}) :: mapping()
```

A mapping under `prefix` with `aliases`. `caller_context` is dropped in
every mapping this builds: it is an opaque host term the bridge *uses*
(to link) and never flattens into attributes, a rule both sibling
contracts state as explicitly as the design note states it for the
interpreter family.

# `span_event_attributes`

```elixir
@spec span_event_attributes(map(), map(), OpentelemetryStatifier.Config.t()) :: map()
```

Maps one event's `measurements` and `metadata` into span-event
attributes under the rules above, honoring `config`'s
`record_datamodel_values` opt-in.

# `span_event_attributes`

```elixir
@spec span_event_attributes(
  map(),
  map(),
  OpentelemetryStatifier.Config.t(),
  mapping()
) :: map()
```

`span_event_attributes/3` under an explicit `mapping/2`.

---

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