> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squasher.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Elixir & Erlang

> Send errors, logs, and traces from Elixir and Phoenix apps to Squasher with OpenTelemetry or the HTTP API.

## Recommended: OpenTelemetry SDK

Use the official Erlang/Elixir OTel SDK for auto-instrumentation of Phoenix, Ecto, and other libraries.

### 1. Install

```elixir theme={null}
# mix.exs
defp deps do
  [
    {:opentelemetry, "~> 1.4"},
    {:opentelemetry_exporter, "~> 1.7"},
    {:opentelemetry_phoenix, "~> 1.2"},
    {:opentelemetry_ecto, "~> 1.2"},
  ]
end
```

### 2. Configure

```elixir theme={null}
# config/runtime.exs
config :opentelemetry,
  span_processor: :batch,
  traces_exporter: :otlp

config :opentelemetry_exporter,
  otlp_protocol: :http_protobuf,
  otlp_endpoint: "https://ingest.squasher.ai",
  otlp_headers: [{"x-squasher-key", "sq_pk_your_api_key"}]
```

### 3. Setup Instrumentation

```elixir theme={null}
# lib/my_app/application.ex
def start(_type, _args) do
  OpentelemetryPhoenix.setup()
  OpentelemetryEcto.setup([:my_app, :repo])

  children = [
    MyApp.Repo,
    MyAppWeb.Endpoint,
  ]

  Supervisor.start_link(children, strategy: :one_for_one)
end
```

All uncaught exceptions in Phoenix controllers and Ecto query errors are automatically captured.

## Alternative: Direct HTTP API

```elixir theme={null}
defmodule Squasher do
  @endpoint "https://ingest.squasher.ai/v1/ingest/#{System.get_env("SQUASHER_PROJECT_ID")}"
  @api_key System.get_env("SQUASHER_API_KEY")

  def capture_error(%{__exception__: true} = error, tags \\ %{}) do
    payload = %{
      message: Exception.message(error),
      type: error.__struct__ |> to_string() |> String.split(".") |> List.last(),
      level: "error",
      stack: Exception.format_stacktrace(__STACKTRACE__),
      environment: System.get_env("MIX_ENV", "prod"),
      tags: tags
    }

    Task.start(fn ->
      Req.post!(@endpoint,
        json: payload,
        headers: [
          {"content-type", "application/json"},
          {"x-squasher-key", @api_key}
        ]
      )
    end)
  end

  def log(level, message, tags \\ %{}) do
    payload = %{message: message, level: to_string(level), tags: tags}

    Task.start(fn ->
      Req.post!(@endpoint,
        json: payload,
        headers: [
          {"content-type", "application/json"},
          {"x-squasher-key", @api_key}
        ]
      )
    end)
  end
end
```

### Usage

```elixir theme={null}
try do
  process_order(order)
rescue
  e ->
    Squasher.capture_error(e, %{order_id: order.id})
    reraise e, __STACKTRACE__
end

Squasher.log(:info, "Deployment completed", %{version: "v1.2.3"})
```

## Agent handoff

```text theme={null}
For Elixir or Phoenix, prefer OpenTelemetry instrumentation for Phoenix and Ecto. Keep keys in runtime config or secrets, verify one exception or error log, and use direct HTTP only for custom fallback hooks.
```
