Skip to content

Elixir OpenTelemetry instrumentation

Instrument a Phoenix application with OpenTelemetry using the opentelemetry_phoenix and opentelemetry_ecto libraries. They subscribe to the :telemetry events Phoenix and Ecto already emit and turn them into spans, so incoming requests and database queries are traced with no changes to your controllers.

  • A Phoenix application.
  • Elixir 1.14 or newer with OTP 25+.
  • Your Osuite ingest token and region.
  1. Add the OpenTelemetry packages to deps in mix.exs, then run mix deps.get.

    {:opentelemetry_api, "~> 1.4"},
    {:opentelemetry, "~> 1.5"},
    {:opentelemetry_exporter, "~> 1.8"},
    {:opentelemetry_phoenix, "~> 2.0"},
    {:opentelemetry_cowboy, "~> 1.0"},
    {:opentelemetry_ecto, "~> 1.2"}
  2. Wire up the instrumentation in application.ex, at the start of start/2 before the supervisor children start. Pass your Ecto repo’s telemetry prefix to OpentelemetryEcto.setup/1.

    def start(_type, _args) do
    :opentelemetry_cowboy.setup()
    OpentelemetryPhoenix.setup(adapter: :cowboy2)
    OpentelemetryEcto.setup([:my_app, :repo])
    children = [
    # ... your existing children
    ]
    Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
    end
  3. Configure the OTLP exporter in config/runtime.exs so it reads your ingest credentials at boot.

    config :opentelemetry, traces_exporter: :otlp
    config :opentelemetry_exporter,
    otlp_protocol: :grpc,
    otlp_endpoint: "https://ingest.<region>.osuite.io:443",
    otlp_headers: [{"x-osuite-ingest-token", "<your-ingest-token>"}]

    Set the service name and environment as resource attributes, either here or with the standard OTEL_SERVICE_NAME=<service-name> and OTEL_RESOURCE_ATTRIBUTES=service.environment=production environment variables. The https:// scheme on otlp_endpoint is required — Osuite only accepts OTLP over TLS.

What you should see

Send a request to any route. The service appears in APM within a minute with a trace per request, showing the Phoenix endpoint, the controller action, and Ecto queries as nested spans.

If no traces appear, confirm the setup calls run at application start and that config/runtime.exs is evaluated in your release (it is, by default). A common miss is calling OpentelemetryEcto.setup/1 with the wrong telemetry prefix — it must match your repo’s [:otp_app, :repo], not the module name.

No data in Osuite after a few minutes? Work through these checks.

  • Endpoint — confirm the exporter targets exactly ingest.<region>.osuite.io:443 for your region, over TLS.
  • Token — confirm the ingest header carries a valid <your-ingest-token> and has not been rotated.
  • Pipeline — confirm the signal you expect (traces, logs, or metrics) is wired into an active pipeline with the otlp/osuite exporter attached.
  • Export errors — check the application or Collector logs for OTLP export failures (auth, DNS, TLS, connection refused).
  • Network — confirm the host has outbound access to the ingest endpoint on port 443.
  • Timing — allow up to a minute for the first data to appear before assuming a failure.

Still stuck? Ask the Investigation Agent or contact support.