# `Impact`

Impact is an OpenTelemetry-native SDK for capturing LLM/AI traces from Elixir
applications and exporting them to Impact via OTLP.

The Elixir SDK is the BEAM-side peer of `impact-sdk` (Python) and `impact-sdk-js`
(JavaScript/TypeScript). The three SDKs share a canonical attribute schema:

  * `impact.context.<key>` for app-supplied request context
  * `impact.trace.{type,name,path,input,output}` for manual spans

## Quick start

    Impact.init(
      api_key: System.fetch_env!("IMPACT_API_KEY"),
      endpoint: System.get_env("IMPACT_BASE_URL"),
      mode: :auto
    )

    Impact.context(
      user_id: "u_123",
      interaction_id: "int_abc",
      attributes: %{team: "growth"}
    )

    Impact.trace [type: :workflow, name: "checkout"] do
      do_work()
    end

## Runtime modes

Mirrors the Python and JS SDKs:

  * `:auto` (default) — attach to an existing tracer provider if one is configured,
    otherwise bootstrap.
  * `:bootstrap` — always (re)configure `:opentelemetry` exporter + batch processor.
  * `:attach` — never replace caller-configured providers; raises if no usable
    provider is found.

# `init_opt`

```elixir
@type init_opt() ::
  {:api_key, String.t() | nil}
  | {:endpoint, String.t() | nil}
  | {:service_name, String.t() | nil}
  | {:mode, :auto | :bootstrap | :attach}
  | {:capture_content, boolean()}
  | {:diag_log_level, :none | :error | :warn | :info | :debug | :verbose}
```

# `add_event`
*macro* 

Add a timestamped event to the currently active span. Useful for marking
notable points within a long-running span (state transitions, retries,
cache hits, etc).

    Impact.add_event("cache_miss", %{key: cache_key})

# `context`

```elixir
@spec context(keyword() | map()) :: :ok
```

Attach context to the current execution. Keys are emitted as `impact.context.<key>`
span attributes for every span created under this process / OTel context.

Reserved keys are flattened from `:attributes`. The canonical reserved keys are:
`:user_id`, `:interaction_id`, `:version_id`.

# `flush`

```elixir
@spec flush(timeout :: pos_integer()) :: :ok
```

Flush pending spans synchronously. Useful in scripts, Lambda-style runtimes,
and tests.

# `init`

```elixir
@spec init([init_opt()]) :: :ok | {:error, term()}
```

Initialize Impact. Idempotent — calling twice replays the last configuration.

# `instrumentation_results`

```elixir
@spec instrumentation_results() :: %{optional(atom()) =&gt; :ok | {:error, term()}}
```

Returns the deterministic outcome of optional instrumentation activation,
aligned with `impact.instrumentationResults` in the JS SDK.

# `set_attributes`
*macro* 

Add attributes to the currently active span. Useful for response-side
attributes that are only known after an operation completes.

    Impact.trace [type: :llm, name: "bedrock_call", attributes: request_attrs] do
      result = call_llm()
      Impact.set_attributes(%{"gen_ai.usage.input_tokens" => result.tokens})
      result
    end

Thin macro over `OpenTelemetry.Tracer.set_attributes/1` — re-exported so
apps don't need to add `:opentelemetry_api` to their deps just to set
mid-span attributes.

# `set_status`
*macro* 

Set the status of the currently active span. `code` is `:ok` | `:error` |
`:unset`. `message` is an optional string (typically required for `:error`).

    Impact.trace [type: :task, name: "do_thing"] do
      case do_thing() do
        {:ok, _} = ok -> ok
        {:error, reason} = err ->
          Impact.set_status(:error, inspect(reason))
          err
      end
    end

# `shutdown`

```elixir
@spec shutdown(timeout :: pos_integer()) :: :ok
```

Flush and shut down Impact's exporter / batch processor. Safe to call from
`Application.stop/1`.

# `trace`
*macro* 

Wrap an expression in a manual Impact span.

Both block and function forms are supported. Block form is a macro so the
block body is evaluated lazily inside the span:

    require Impact

    Impact.trace [type: :task, name: "payment.authorize"] do
      authorize(order_id)
    end

Function form for non-block use:

    Impact.trace([type: :task, name: "payment.authorize"], fn ->
      authorize(order_id)
    end)

---

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