Skip to main content
This page covers instrumenting an Erlang or Elixir application with the OpenTelemetry SDK to send logs and traces to Bronto over OTLP/HTTP via a local OTel Collector. Logs are captured via the kernel logger handler automatically. Traces are created using the OTel API macros and functions.
If you don’t have a Collector and want to export directly from your application to Bronto, see Direct export to Bronto at the bottom of this page.

Prerequisites

Install dependencies

def deps do
  [
    {:opentelemetry_api, "~> 1.4"},
    {:opentelemetry, "~> 1.4"},
    {:opentelemetry_exporter, "~> 1.7"}
  ]
end
PackagePurpose
opentelemetry_apiCore OTel API
opentelemetrySDK — LoggerProvider, processors, kernel log handler
opentelemetry_exporterOTLP/HTTP exporter

Configure the log bridge

The OTel SDK ships an Erlang kernel logger handler (otel_log_handler) that captures all log events emitted via :logger (Erlang) or Logger (Elixir). Configure it in your application config.
import Config

config :opentelemetry,
  resource: [
    service: [
      name: "my-service",
      namespace: "my-team"
    ],
    "deployment.environment": "production"
  ],
  logs_exporter: :otlp

config :opentelemetry_exporter,
  otlp_protocol: :http_protobuf,
  otlp_logs_endpoint: "http://localhost:4318/v1/logs"
No code changes are required — the kernel logger handler is installed automatically when the opentelemetry application starts.

Set resource attributes

Resource attributes are attached to every log record exported from this process. Two attributes drive how Bronto organises incoming logs:
OTel attributeBronto conceptDescription
service.nameDatasetGroups logs from one service
service.namespaceCollectionGroups related services or a team’s services
These are set via the resource config key in the setup above.

Complete example

# Existing Logger calls work unchanged
require Logger

Logger.info("Application started")
Logger.warning("Low disk space", disk_free_gb: 2.1)
Logger.error("Database connection failed", reason: :timeout)
Existing Logger / :logger calls require no changes. The OTel handler runs alongside any existing handlers (console, file) configured in your kernel logger setup.

Verify log collection

After running your application, open the Search page in Bronto. Filter by the dataset name you set in service.name — your log records should appear within a few seconds. If no logs appear, check:
  • The OTel Collector is running and reachable at the configured endpoint.
  • The Collector’s pipeline includes a logs pipeline with an otlp receiver and the Bronto exporter — see Connect Open Telemetry to Bronto.
  • The opentelemetry application is started before your application (listed in extra_applications or applications in your .app.src/mix.exs).

Traces

Framework-specific instrumentation libraries are available for Phoenix, Ecto, LiveView, Absinthe, and more — add opentelemetry_phoenix, opentelemetry_ecto, etc. to your deps and they instrument those frameworks automatically. See Erlang/Elixir instrumentation libraries for the full list.

Configure tracing

Tracing is included in the same opentelemetry and opentelemetry_exporter packages — no additional dependencies are needed. Add the traces endpoint to your config:
config :opentelemetry,
  resource: [
    service: [name: "my-service", namespace: "my-team"],
    "deployment.environment": "production"
  ],
  traces_exporter: :otlp,
  logs_exporter: :otlp

config :opentelemetry_exporter,
  otlp_protocol: :http_protobuf,
  otlp_traces_endpoint: "http://localhost:4318/v1/traces",
  otlp_logs_endpoint: "http://localhost:4318/v1/logs"

Creating spans

require OpenTelemetry.Tracer, as: Tracer

Tracer.with_span "process-payment" do
  Tracer.set_attributes([{"payment.amount", 99.99}, {"payment.currency", "USD"}])
  Logger.info("Processing payment")  # trace_id and span_id injected automatically
end
Any log emitted inside a span will automatically have trace_id and span_id attached.

Direct export to Bronto

If you are not using an OTel Collector, export directly to Bronto by replacing the exporter endpoints and adding your API key:
config :opentelemetry_exporter,
  otlp_protocol: :http_protobuf,
  otlp_logs_endpoint: "https://ingestion.eu.bronto.io/v1/logs",
  otlp_traces_endpoint: "https://ingestion.eu.bronto.io/v1/traces",
  otlp_headers: [{"x-bronto-api-key", "<YOUR_API_KEY>"}]
RegionLogs endpointTraces endpoint
EUhttps://ingestion.eu.bronto.io/v1/logshttps://ingestion.eu.bronto.io/v1/traces
UShttps://ingestion.us.bronto.io/v1/logshttps://ingestion.us.bronto.io/v1/traces
See API Keys for how to create a key with ingestion permissions. No other changes to the rest of the setup are required.