Instrument Rails with OpenTelemetry
Send traces and logs from a Ruby on Rails app to Telemetry Machine with the OpenTelemetry Ruby SDK and its Rails instrumentation.
The OpenTelemetry Ruby SDK traces every request and sends your Rails.logger records as logs. This page sends traces and logs only, because Ruby's metrics SDK is still experimental.
Create the datasets
Each signal goes to its own dataset. Create two, and an ingest key that can write to both, with tm-cli or the MCP server:
$ tm-cli datasets create --name shop-prod-traces --type traces
$ tm-cli datasets create --name shop-prod-logs --type logs
$ tm-cli api-keys create --name shop-api --dataset shop-prod-traces --dataset shop-prod-logscreate_dataset { "name": "shop-prod-traces", "signal_type": "traces" }
create_dataset { "name": "shop-prod-logs", "signal_type": "logs" }
create_ingest_key {
"name": "shop-api",
"datasets": ["shop-prod-traces", "shop-prod-logs"]
}tm-cli shows the key once, in api_key.api_key. Over MCP, your agent gets it once and saves it in your app's configuration. In the app, create each dataset, then a key for both under API keys in your organization's settings.
Install
$ bundle add opentelemetry-sdk opentelemetry-exporter-otlp opentelemetry-instrumentation-all
$ bundle add opentelemetry-logs-sdk opentelemetry-exporter-otlp-logs opentelemetry-instrumentation-loggerAdd an initializer:
require "opentelemetry/sdk"
require "opentelemetry/exporter/otlp"
require "opentelemetry-logs-sdk"
require "opentelemetry/exporter/otlp_logs"
require "opentelemetry/instrumentation/all"
require "opentelemetry/instrumentation/logger"
OpenTelemetry::SDK.configure(&:use_all)
# Send what is still buffered when the server stops.
at_exit do
OpenTelemetry.tracer_provider.shutdown
OpenTelemetry.logger_provider.shutdown
endConfigure
export TM_INGEST_KEY='<ingest-key>'
export OTEL_SERVICE_NAME=shop-api
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.telemetrymachine.com
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_TRACES_HEADERS="X-API-Key=$TM_INGEST_KEY,X-Dataset-Name=shop-prod-traces"
export OTEL_EXPORTER_OTLP_LOGS_HEADERS="X-API-Key=$TM_INGEST_KEY,X-Dataset-Name=shop-prod-logs"Run
$ bin/rails serverCheck it arrived
Send your app a few requests, then open each explorer and choose the dataset:
- Traces,
shop-prod-traces: one server span per request, named after its route, such asGET /items/:id. - Logs,
shop-prod-logs: yourRails.loggerrecords, and Rails's own request lines, each with its request'strace.trace_id.
Or count spans by name with tm-cli or the MCP server:
$ tm-cli query shop-prod-traces --since 15m --select "name, count(*)" --group-by namerun_query {
"dataset": "shop-prod-traces",
"description": "Spans by name",
"since": "15m",
"select": "name, count(*)",
"group_by": "name"
}Troubleshooting
Use either use_all or use, but not both: to configure one instrumentation, pass its options touse_all, such asc.use_all("OpenTelemetry::Instrumentation::Rack" => { untraced_endpoints: ["/up"] }).- Log lines contain codes such as
[1m[36m: Rails colors its SQL log lines. Setconfig.colorize_logging = falseinconfig/application.rb.