Monitor OpenTelemetry Erlang/Elixir with Uptrace
This guide explains how to configure the OpenTelemetry Erlang/Elixir SDK to export telemetry data to Uptrace using OTLP/gRPC. You'll learn how to set up comprehensive monitoring for your Erlang and Elixir applications with distributed tracing capabilities.
Prerequisites
Before you begin, ensure you have:
- An Erlang/Elixir application running on Erlang 23+ and Elixir 1.13+
- An Uptrace account with a valid DSN (Data Source Name)
- Basic familiarity with your application's supervision tree
Install dependencies
Add the necessary OpenTelemetry packages to your project dependencies:
# mix.exs
defp deps do
[
{:opentelemetry, "~> 1.3"},
{:opentelemetry_api, "~> 1.2"},
{:opentelemetry_exporter, "~> 1.6"}
]
end
Run the appropriate command to install dependencies:
# For Elixir projects
mix deps.get
# For Erlang projects
rebar3 compile
Basic configuration
The OpenTelemetry SDK starts its supervision tree on application boot, so initial configuration must be done through application configuration or environment variables.
# config/config.exs or config/runtime.exs
config :opentelemetry,
span_processor: :batch,
traces_exporter: :otlp
config :opentelemetry_exporter,
otlp_protocol: :grpc,
otlp_compression: :gzip,
otlp_endpoint: "https://api.uptrace.dev:4317",
otlp_headers: [{"uptrace-dsn", "<YOUR_UPTRACE_DSN>"}]
Replace <YOUR_UPTRACE_DSN>
with your actual Uptrace DSN from your project settings.
For a complete list of available configuration options, see the official OpenTelemetry Exporter documentation.
Environment variables
You can also configure OpenTelemetry using environment variables, which is particularly useful for:
- Docker deployments and containerized environments
- CI/CD pipelines
- Production configurations where credentials shouldn't be hardcoded
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.uptrace.dev:4317
export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_TRACES_COMPRESSION=gzip
export OTEL_EXPORTER_OTLP_TRACES_HEADERS="uptrace-dsn=<YOUR_UPTRACE_DSN>"
For a complete list of supported environment variables, see the OpenTelemetry environment configuration documentation.
Application configuration
Configure OpenTelemetry to start as a temporary application to prevent crashes from affecting your main application:
# mix.exs
def project do
[
app: :my_app,
# ... other config
releases: [
my_app: [
applications: [opentelemetry: :temporary]
]
]
]
end
This ensures that if OpenTelemetry terminates, your main application continues running without telemetry rather than crashing entirely.
Phoenix framework integration
To instrument Phoenix applications with OpenTelemetry, add the Phoenix instrumentation library:
# mix.exs
defp deps do
[
# ... existing deps
{:opentelemetry_phoenix, "~> 1.1"},
{:opentelemetry_cowboy, "~> 0.2"}
]
end
Configure Phoenix instrumentation in your application start function:
# lib/my_app/application.ex
def start(_type, _args) do
# Setup instrumentation before starting supervision tree
:opentelemetry_cowboy.setup()
OpentelemetryPhoenix.setup(adapter: :cowboy2)
children = [
{Phoenix.PubSub, name: MyApp.PubSub},
MyAppWeb.Endpoint
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
Ensure your endpoint includes the telemetry plug:
# lib/my_app_web/endpoint.ex
defmodule MyAppWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :my_app
plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]
# ... other plugs
end
This setup provides automatic instrumentation for:
- HTTP requests and responses with timing
- Phoenix controller actions and parameters
- Template rendering performance
- Phoenix channels and WebSocket connections
- Error tracking and status codes
For additional configuration options, see the OpenTelemetry Phoenix documentation.
Ecto database integration
OpenTelemetry Ecto provides comprehensive database operation tracing for Ecto-based applications, automatically instrumenting:
- Database queries with execution time and parameters
- Query performance metrics and slow query detection
- Database connection pool utilization
- Transaction boundaries and rollbacks
- Database-specific operations and adapters
Setup
Add the Ecto instrumentation library:
# mix.exs
defp deps do
[
# ... existing deps
{:opentelemetry_ecto, "~> 1.2"}
]
end
Configure Ecto instrumentation in your application start function:
# lib/my_app/application.ex
def start(_type, _args) do
# Setup Ecto instrumentation for your repositories
# Use the telemetry prefix from your repo configuration
OpentelemetryEcto.setup([:my_app, :repo])
children = [
MyApp.Repo,
# ... other children
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
The telemetry prefix should match your repository's telemetry configuration. For most applications, this follows the pattern [:app_name, :repo]
, but check your repository module for the exact prefix:
# lib/my_app/repo.ex
defmodule MyApp.Repo do
use Ecto.Repo,
otp_app: :my_app,
adapter: Ecto.Adapters.Postgres
# The telemetry prefix defaults to [:my_app, :repo]
end
For advanced configuration options including query sanitization and custom attributes, see the OpenTelemetry Ecto documentation.
Manual instrumentation
For custom spans and manual instrumentation, use the OpenTelemetry API:
require OpenTelemetry.Tracer
def process_important_task(data) do
OpenTelemetry.Tracer.with_span "process_task" do
# Add custom attributes
OpenTelemetry.Tracer.set_attribute("task.data_size", byte_size(data))
# Your business logic here
result = do_complex_work(data)
# Add more attributes based on results
OpenTelemetry.Tracer.set_attribute("task.result_count", length(result))
result
end
end
Verifying your setup
After configuration, your application will automatically start sending telemetry data to Uptrace. To verify the setup:
- Start your application with the new configuration
- Generate activity by making HTTP requests, database queries, or triggering your instrumented code paths
- Check the Uptrace dashboard for incoming traces within 1-2 minutes
- Review trace details to ensure spans are being created with proper attributes
Troubleshooting
If traces don't appear in Uptrace:
- Verify DSN: Double-check your Uptrace DSN in the configuration
- Check connectivity: Ensure your application can reach
https://api.uptrace.dev:4317
- Review logs: Look for OpenTelemetry error messages in your application logs
- Test configuration: Use the stdout exporter for local testing:
# config/dev.exs
config :opentelemetry,
traces_exporter: {:otel_exporter_stdout, []}