Dash0 OpenTelemetry Distribution for Ruby
An opinionated, zero-code OpenTelemetry distribution
for Ruby, published as the dash0-opentelemetry gem. It is a thin wrapper around
upstream OpenTelemetry Ruby that ships a batteries-included auto-instrumentation
setup for Dash0.
Intended use
This distribution is primarily intended to be injected into Ruby workloads by the
Dash0 Kubernetes operator, which
instruments them without code changes. It is required at process startup via
RUBYOPT, the Ruby analog of Node.js's NODE_OPTIONS=--require:
RUBYOPT="-r dash0-opentelemetry" ruby your_app.rb
RUBYOPT="-r dash0-opentelemetry" rails server
Everything runs as a side effect of requiring the gem — there is no API to call.
Because it is loaded before the application's own libraries, instrumentation is
installed lazily (via a TracePoint) as each supported library is loaded, so no
particular load order is required.
Requirements
- Ruby >= 3.3. On an unsupported Ruby the distribution stands down cleanly (it logs a message and does nothing) rather than interfering with the app.
Installation
gem install dash0-opentelemetry
Install it outside the application's bundle (it loads OpenTelemetry from its
own gem path, not from the app's Gemfile).
What it does
On startup the distribution:
- exports traces, metrics, and logs over OTLP (HTTP/protobuf) to the Dash0
collector at
${DASH0_OTEL_COLLECTOR_BASE_URL}/v1/{traces,metrics,logs}; - enables all instrumentations from
opentelemetry-instrumentation-all, installed lazily as their target libraries load; - adds resource attributes: the upstream defaults (process, SDK, and any
OTEL_SERVICE_NAME/OTEL_RESOURCE_ATTRIBUTES), the container detector (container.id), a Kubernetes pod-uid detector (k8s.pod.uid), a service-name fallback (service.name), and the distribution identity (telemetry.distro.name = dash0-ruby,telemetry.distro.version).
Configuration
Behavior is driven entirely by environment variables: DASH0_* for
distribution-specific switches and standard OTEL_* for the rest.
DASH0_* variables
| Variable | Description |
|---|---|
DASH0_OTEL_COLLECTOR_BASE_URL |
Required. Base URL of the OpenTelemetry collector to export to; each signal is sent to <base>/v1/{traces,metrics,logs}. If unset, the distribution stands down and exports nothing. (The Dash0 operator sets this for you.) |
DASH0_DISABLE |
Set to true to disable the distribution entirely. |
DASH0_AUTOMATIC_SERVICE_NAME |
Set to false to opt out of the automatic service.name fallback (see below). |
DASH0_BOOTSTRAP_SPAN |
If set to a non-empty string, a single internal span with that name is emitted immediately at startup. Useful for confirming the distribution is active. |
DASH0_FLUSH_ON_SIGTERM_SIGINT |
Set to true to install SIGTERM/SIGINT handlers that flush pending telemetry (timeboxed) before re-raising the signal. Do not use if the application installs its own handlers for these signals. |
DASH0_FLUSH_ON_EXIT |
Telemetry is flushed on normal process exit by default (via an at_exit hook). Set to false to disable this. |
DASH0_DEBUG |
Set to true for additional debug logging on stderr. |
DASH0_DEBUG_PRINT_SPANS |
Set to true to also print every span to stdout via a console exporter (in addition to exporting over OTLP). |
Automatic service name
If no service name has been configured, the distribution derives one from the application's own identity, in order of preference:
- the app module in
config/application.rborconfig/app.rb(Rails, Hanami) — e.g.module DemoApp→demo_app; config.ru— therun <AppClass>target or an inline application class (modular Sinatra, Roda, plain Rack, single-file Rails);- the entry script name, when it is not a known launcher/wrapper (e.g.
ruby my_worker.rb→my_worker).
Because the distribution loads at interpreter startup, the entry point is usually
a wrapper (bundle, puma, rackup, …); these are deliberately ignored rather
than reported as the service name. When none of the above yields a name, the
distribution reports nothing and the SDK's unknown_service default stands.
This fallback is skipped entirely when a service name is already set via
OTEL_SERVICE_NAME, via a service.name in OTEL_RESOURCE_ATTRIBUTES, or when
DASH0_AUTOMATIC_SERVICE_NAME=false.
OTEL_* variables
Standard OpenTelemetry variables are honored because the distribution uses the stock OpenTelemetry SDK, exporters, and processors. Commonly useful ones:
| Variable | Description |
|---|---|
OTEL_SERVICE_NAME |
Sets service.name explicitly (and disables the automatic fallback). |
OTEL_RESOURCE_ATTRIBUTES |
Additional resource attributes as key=value pairs. A service.name here also disables the automatic fallback. |
OTEL_RUBY_ENABLED_INSTRUMENTATIONS |
Comma-separated allowlist of instrumentations to enable (by snake_case name, e.g. net_http,rack). When unset, all supported instrumentations are enabled. |
OTEL_EXPORTER_OTLP_ENDPOINT |
Overrides the OTLP endpoint. Defaulted from DASH0_OTEL_COLLECTOR_BASE_URL; set explicitly only to override. |
OTEL_EXPORTER_OTLP_PROTOCOL |
OTLP protocol; defaults to http/protobuf (the only protocol supported by the Ruby SDK's default path). |
OTEL_EXPORTER_OTLP_HEADERS |
Extra headers for the OTLP exporter (e.g. an authorization token when exporting directly to Dash0 rather than through the operator's collector). |
OTEL_METRIC_EXPORT_INTERVAL / OTEL_METRIC_EXPORT_TIMEOUT |
Periodic metric reader interval / timeout, in milliseconds. |
Standard batch-processor variables (OTEL_BSP_*, OTEL_BLRP_*) and
OTEL_SDK_DISABLED are honored by the underlying SDK as well.
DISALLOWED_LIB_PATH (advanced)
A comma-separated list of bundled non-opentelemetry-* gems the distribution
should not put on the load path when injected. Its main use is the escape
hatch for a google-protobuf version clash: when instrumenting an app that uses
its own google-protobuf at runtime and breaks because the bundled version wins
set DISALLOWED_LIB_PATH=google-protobuf so the distribution defers to the app's
copy. Works while the app's protobuf is within the exporter's supported range;
otherwise the distribution stands down rather than crash.
Development
See CONTRIBUTING.md. Releasing is documented in RELEASING.md.