Packages

Opinionated OpenTelemetry agent for Elixir apps by Mirego

Current section

Files

Jump to

README.md

# MiregoElixirOtelAgent
Drop-in **OpenTelemetry agent** for Elixir apps.
This is not an official OTEL distribution. It's an opinionated drop-in library
to quickly set up a standard Elixir/Phoenix application that follows semantic
conventions. Traces are provided by the official `opentelemetry_*` libraries
while metrics are provided by `Telemetry.Metrics` and exported by
an internal OTLP metric exporter. Some default metrics are provided by this library.
**Goal:** this library is intended to be temporary. Once the official OpenTelemetry
Elixir libraries include proper metrics support, and the official
instrumentation libraries include their own metrics, this library should be
deprecated in favor of those upstream solutions.
## Installation
```elixir
def deps do
[
{:mirego_elixir_otel_agent, "~> 0.1"}
]
end
```
Since the official `:opentelemetry` and `:opentelemetry_exporter` applications
are configured directly by the host app, they can be started normally by the
release. No special restart handling is required.
## Configuration
Configure the official SDK and exporter directly, just as you would without
this library:
```elixir
# config/runtime.exs
if endpoint = System.get_env("OTEL_EXPORTER_OTLP_ENDPOINT") do
config :opentelemetry,
resource: [
{"service.name", "my-app"},
{"service.version", Application.spec(:my_app, :vsn) |> to_string()}
],
traces_exporter: :otlp,
span_processor: :batch
config :opentelemetry_exporter,
otlp_protocol: :http_protobuf,
otlp_endpoint: endpoint
config :mirego_elixir_otel_agent,
enabled: true,
metric_export_period: 30_000,
phoenix_adapter: :bandit,
metric_exporter: [
resource: %{"service.namespace" => "my-team"},
otlp_headers: %{"x-api-key" => System.fetch_env!("OTLP_API_KEY")},
otlp_timeout: 15_000
]
end
```
## App module
```elixir
defmodule MyApp.OpenTelemetry do
use MiregoElixirOtelAgent,
ecto_prefixes: [[:my_app, :repo]]
import Telemetry.Metrics
@impl true
def on_start do
# Phoenix, Ecto, Bandit/Cowboy, Absinthe, and Oban instrumentations are
# attached automatically when their modules are present. Use this callback
# for any custom setup that the automatic instrumentation does not cover.
:ok
end
@impl true
def extra_metrics do
[
counter("my_app.custom.metric",
event_name: [:my_app, :custom_metric],
measurement: :count,
tags: [:success]
)
]
end
end
```
## Supervision tree
In `MyApp.Application`, start the agent as one of the first children:
```elixir
children = [
MyApp.OpenTelemetry,
MyApp.Repo,
MyAppWeb.Endpoint
]
```
## Callbacks
| Callback | Required | Role |
|---|---|---|
| `on_start/0` | no | Custom startup hook. The built-in Phoenix, Ecto, server adapter, Absinthe, and Oban instrumentations are attached automatically. |
| `extra_metrics/0` | no | App-specific metrics defined with `Telemetry.Metrics` |
## `use` options
| Option | Default | Purpose |
|---|---|---|
| `:ecto_prefixes` | `[]` | Prefixes for baseline DB metrics **and** `OpentelemetryEcto.setup/1` (e.g. `[[:my_app, :repo]]`) |
| `:baseline_metrics` | `true` | `true` / `false` / `[vm: true, http: true, ecto: true, graphql: true]` when Absinthe is loaded, otherwise `graphql: false` |
| `:auto_instrument` | `true` | When `true`, attaches Phoenix, Ecto, server adapter, Absinthe, and Oban instrumentations automatically. Set to `false` to do it yourself in `on_start/0`. |
## Agent config options
| Option | Default | Purpose |
|---|---|---|
| `:enabled` | `false` | When not `true`, `start_link/1` returns `:ignore` |
| `:metric_export_period` | `30_000` | Metrics export interval in ms |
| `:phoenix_adapter` | `:bandit` | Adapter passed to `OpentelemetryPhoenix.setup/1` (`:bandit` or `:cowboy2`) |
| `:metric_exporter` | `[]` | Internal metrics-exporter options; see [Metric exporter configuration](#metric-exporter-configuration) |
## Instrumentations
The following instrumentation libraries are **attached automatically** when
`:auto_instrument` is `true` (the default) and their modules are present in the
host app. Automatic attachment does not necessarily mean automatic installation:
`opentelemetry_phoenix` and `opentelemetry_ecto` are installed transitively with
this library, while the optional instrumentations below must be added directly
to the host application's dependencies.
- `opentelemetry_phoenix` — attached via `OpentelemetryPhoenix.setup/1` using
the `:phoenix_adapter` config (`:bandit` by default).
- `opentelemetry_bandit` or `opentelemetry_cowboy` — optional host-app
dependencies; attached based on `:phoenix_adapter` (`:bandit` or `:cowboy2`).
- `opentelemetry_ecto` — attached via `OpentelemetryEcto.setup/1` for each
`:ecto_prefixes` entry.
- `opentelemetry_absinthe` — an optional host-app dependency; attached when
Absinthe is present.
- `opentelemetry_oban` — attached when Oban is present.
Add the optional instrumentation libraries you need to your host app dependencies;
the agent will detect and attach them on start:
```elixir
def deps do
[
{:mirego_elixir_otel_agent, "~> 0.1"},
{:opentelemetry_oban, "~> 1.2"},
{:opentelemetry_absinthe, "~> 2.3"}
]
end
```
Set `:auto_instrument` to `false` and attach the instrumentations yourself in
`on_start/0` if you need custom setup options.
## Metric exporter configuration
Metrics use the internal exporter vendored in this package. It reads connection
settings from `:opentelemetry_exporter`, so the OTLP endpoint used for traces is
also used for metrics. The agent passes those settings directly when it starts
the exporter; it does not modify `:opentelemetry_exporter` application config.
Use `:metric_exporter` only for metric-specific overrides that cannot live in
the official exporter config. For example:
```elixir
config :mirego_elixir_otel_agent,
metric_exporter: [
resource: %{
"service.namespace" => "my-team",
"deployment.environment.name" => "production"
},
otlp_headers: %{"x-api-key" => System.fetch_env!("OTLP_API_KEY")},
otlp_timeout: 15_000,
otlp_compression: :gzip
]
```
Supported internal options are:
| Key | Default | Purpose |
|---|---|---|
| `:resource` | `%{}` | Additional OTLP resource attributes. Nested maps are flattened with dot-separated keys. |
| `:otlp_headers` | `%{}` | Request headers, merged with headers from the official exporter config. |
| `:otlp_timeout` | `10_000` | OTLP request timeout in milliseconds. |
| `:otlp_compression` | `:gzip` | Request compression; `:gzip` or `nil`. |
The exporter currently supports only OTLP/HTTP protobuf. Its fallback defaults
are `otlp_protocol: :http_protobuf` and `otlp_compression: :gzip`.
## License
`MiregoElixirOtelAgent` is © 2026 [Mirego](https://www.mirego.com) and may be freely distributed under the [New BSD license](http://opensource.org/licenses/BSD-3-Clause). See the [`LICENSE.md`](https://github.com/mirego/mirego_elixir_otel_agent/blob/main/LICENSE.md) file.
## About Mirego
[Mirego](https://www.mirego.com) is a team of passionate people who believe that work is a place where you can innovate and have fun. We’re a team of [talented people](https://life.mirego.com) who imagine and build beautiful Web and mobile applications. We come together to share ideas and [change the world](http://www.mirego.org).
We also [love open-source software](https://open.mirego.com) and we try to give back to the community as much as we can.