# `LangChain.OpenTelemetry.SpanHandler`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/open_telemetry/span_handler.ex#L4)

Telemetry handler that creates OpenTelemetry spans from LangChain telemetry events.

Spans follow a subset of the GenAI Semantic Conventions (v1.40+) — see
`LangChain.OpenTelemetry.Attributes` for the attributes that are emitted:

| Telemetry Event                       | OTel Span Name              | Kind       | `gen_ai.operation.name` |
|---------------------------------------|-----------------------------|------------|------------------------|
| `[:langchain, :chain, :execute, ...]` | `invoke_agent llm_chain`    | `:internal` | `invoke_agent`          |
| `[:langchain, :llm, :call, ...]`      | `chat {model}`              | `:client`  | `chat`                 |
| `[:langchain, :tool, :call, ...]`     | `execute_tool {tool_name}`  | `:internal` | `execute_tool`          |

Span hierarchy is automatic for synchronous work: chain → LLM call → tool call
run in the same process, so parent context propagation works via the process
dictionary.

> #### Async tools {: .info}
>
> Tools declared with `async: true` execute in a separate `Task` process, and
> the OpenTelemetry context is **not** inherited across a process boundary. For
> tools run by `LLMChain`'s built-in executor this is handled automatically —
> the chain captures the current context before spawning each async tool and
> re-attaches it inside the `Task`, so async tool spans nest under the chain
> span. If you spawn your own processes running LangChain operations, do the
> same yourself: capture `OpenTelemetry.Ctx.get_current/0` before spawning and
> `OpenTelemetry.Ctx.attach/1` inside the process (e.g. via the
> `:on_tool_pre_execution` callback).

## Usage

This module is used internally by `LangChain.OpenTelemetry.setup/1`. You
typically don't need to interact with it directly.

# `events`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/open_telemetry/span_handler.ex#L52)

```elixir
@spec events() :: [[atom()]]
```

Returns the list of telemetry events this handler attaches to.

# `handle_event`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/open_telemetry/span_handler.ex#L78)

```elixir
@spec handle_event([atom()], map(), map(), LangChain.OpenTelemetry.Config.t()) :: :ok
```

Telemetry handler callback. Dispatches to the appropriate handler based on the event.

# `handler_id`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/open_telemetry/span_handler.ex#L72)

```elixir
@spec handler_id() :: String.t()
```

Returns the telemetry handler ID prefix used for attaching/detaching.

---

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