35+ Years Experience Netherlands Based ⚡ Fast Response Times Ruby on Rails Experts AI-Powered Development Fixed Pricing Available Senior Architects Dutch & English 35+ Years Experience Netherlands Based ⚡ Fast Response Times Ruby on Rails Experts AI-Powered Development Fixed Pricing Available Senior Architects Dutch & English
OpenTelemetry in Rails 8: Productie-Observability Opzetten in 30 Minuten

OpenTelemetry in Rails 8: Productie-Observability Opzetten in 30 Minuten

roger
devops
Een stap-voor-stap handleiding voor het instrumenteren van een Rails 8 applicatie met OpenTelemetry voor traces, metrics en logs. Inclusief gem-configuratie, auto-instrumentatie, custom spans en exporter-setup.

Voeg de opentelemetry-sdk gem toe aan je Rails 8 app, configureer auto-instrumentatie, en binnen 30 minuten stromen je distributed traces naar je backend. Zo werkt het.

Waarom OpenTelemetry in Plaats van Vendor Lock-in

Traditionele APM-tools (New Relic, Datadog, Scout) vereisen vendor-specifieke agents. Wil je wisselen van provider — of telemetry naar meerdere backends sturen — dan moet je alle instrumentatiecode herschrijven. OpenTelemetry (OTel) is de CNCF-standaard die instrumentatie loskoppelt van export. Je instrumenteert één keer en routeert signalen waarheen je wilt.

Ik heb vorige maand een productie Rails 8.0.1 app gemigreerd van Scout APM naar OpenTelemetry. De migratie duurde een middag, en de flexibiliteit was direct merkbaar: traces gaan naar Jaeger voor development en Grafana Tempo in productie, met dezelfde instrumentatiecode.

Stap 1: Gems Toevoegen

In je Gemfile:

# OpenTelemetry core
gem "opentelemetry-sdk", "~> 1.4"
gem "opentelemetry-exporter-otlp", "~> 0.29"

# Auto-instrumentatie (pikt Rails, ActiveRecord, etc. op)
gem "opentelemetry-instrumentation-all", "~> 0.68"

Draai bundle install. De opentelemetry-instrumentation-all meta-gem haalt instrumentors binnen voor Rails, ActiveRecord, Action Pack, Action View, Net::HTTP, Faraday, Redis, Sidekiq en zo’n 30 andere libraries. Wil je meer controle, kies dan individuele gems zoals opentelemetry-instrumentation-rails en opentelemetry-instrumentation-active_record.

Stap 2: SDK Configureren

Maak config/initializers/opentelemetry.rb:

require "opentelemetry/sdk"
require "opentelemetry/exporter/otlp"
require "opentelemetry/instrumentation/all"

OpenTelemetry::SDK.configure do |c|
  c.service_name = "my-rails-app"
  c.service_version = ENV.fetch("GIT_SHA", "unknown")

  c.use_all(
    "OpenTelemetry::Instrumentation::Rack" => {
      untraced_endpoints: ["/up", "/healthz"]
    },
    "OpenTelemetry::Instrumentation::ActiveRecord" => {
      db_statement: :obfuscate
    }
  )
end

Een paar punten:

db_statement: :obfuscate vervangt query-parameterwaarden door ? in trace spans. Zonder dit bevatten je traces rauwe SQL met gebruikersdata — een beveiligings- en complianceprobleem. Sla dit niet over.

untraced_endpoints filtert health check-ruis. Kubernetes probes die elke 10 seconden /up raken genereren duizenden nutteloze spans per dag.

service_version gekoppeld aan GIT_SHA laat je performance-regressies correleren aan specifieke deploys. Als je deployt met Kamal 2, geef de SHA mee als omgevingsvariabele in je deploy-configuratie.

Stap 3: Omgevingsvariabelen Instellen

De OTLP exporter leest configuratie standaard uit omgevingsvariabelen:

# Waar telemetry naartoe gaat
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318

# Resource attributes (verschijnt in je backend UI)
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production,host.name=web-1

Voor een lokale collector tijdens development:

OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_TRACES_EXPORTER=otlp
OTEL_LOG_LEVEL=debug

Het debug log level print elke geëxporteerde span naar stdout — handig om te verifiëren dat instrumentatie werkt, maar je wilt het snel weer uitzetten.

Stap 4: Custom Spans Toevoegen Waar Het Ertoe Doet

Auto-instrumentatie dekt HTTP-requests, database-queries, cache-operaties en template rendering. Maar je interessantste performancedata zit in applicatie-specifieke code: betalingsverwerking, PDF-generatie, externe API-calls naar services zonder HTTP-instrumentatie.

class InvoiceGenerator
  def generate(order)
    tracer = OpenTelemetry.tracer_provider.tracer("invoice-generator")

    tracer.in_span("generate_invoice", attributes: {
      "order.id" => order.id,
      "order.line_items" => order.line_items.count
    }) do |span|
      pdf = render_pdf(order)

      span.set_attribute("invoice.pages", pdf.page_count)
      span.set_attribute("invoice.size_bytes", pdf.bytesize)

      upload_to_s3(pdf)
    end
  end
end

Houd custom span-namen kort en consistent. Gebruik dot-notatie voor attributen (order.id, niet orderId). De OpenTelemetry semantic conventions definiëren standaard attribuutnamen voor veelvoorkomende operaties.

Stap 5: Lokale Collector voor Development

Richt je development Rails server niet direct op een productie Grafana-instantie. Draai een lokale OpenTelemetry Collector die exporteert naar Jaeger:

# docker-compose.otel.yml
services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib:0.96.0
    ports:
      - "4318:4318"   # OTLP HTTP receiver
      - "4317:4317"   # OTLP gRPC receiver
    volumes:
      - ./otel-collector-config.yml:/etc/otelcol-contrib/config.yaml

  jaeger:
    image: jaegertracing/all-in-one:1.54
    ports:
      - "16686:16686" # Jaeger UI
      - "4317"        # Ontvangt van collector

Collector configuratie:

# otel-collector-config.yml
receivers:
  otlp:
    protocols:
      http:
        endpoint: 0.0.0.0:4318
      grpc:
        endpoint: 0.0.0.0:4317

processors:
  batch:
    timeout: 5s
    send_batch_size: 1024

exporters:
  otlp/jaeger:
    endpoint: jaeger:4317
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp/jaeger]

Draai docker compose -f docker-compose.otel.yml up, start je Rails server, doe wat requests, en open Jaeger op http://localhost:16686. Je ziet traces met spans voor elke controller action, database query en view render.

Stap 6: Productie Collector Architectuur

In productie zit de collector tussen je app en je observability backend. Dit geeft je:

  • Buffering — de collector batcht en herprobeert, zodat je app nooit blokkeert op telemetry-export
  • Sampling — verwijder low-value traces voordat ze je betaalde backend bereiken
  • Routing — stuur traces naar Tempo, metrics naar Prometheus, logs naar Loki, allemaal vanuit één pipeline

Voor een Rails app die 500 requests/seconde verwerkt, gebruik ik tail-based sampling in de collector om 100% van error traces en trage requests (>2s) te behouden, terwijl ik 10% van succesvolle snelle requests sample. Dit bespaart ruwweg 80% op opslagkosten zonder de data te verliezen die er echt toe doet.

processors:
  tail_sampling:
    decision_wait: 10s
    policies:
      - name: errors
        type: status_code
        status_code: {status_codes: [ERROR]}
      - name: slow-requests
        type: latency
        latency: {threshold_ms: 2000}
      - name: baseline
        type: probabilistic
        probabilistic: {sampling_percentage: 10}

Aansluiten op Je Bestaande Stack

Als je al GitHub Actions CI/CD hebt opgezet voor je Rails app, kun je een stap toevoegen om OpenTelemetry-initialisatie te verifiëren in je testsuite:

# test/test_helper.rb
require "opentelemetry/sdk"

OpenTelemetry::SDK.configure do |c|
  c.service_name = "my-rails-app-test"
  c.add_span_processor(
    OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(
      OpenTelemetry::SDK::Trace::Export::InMemorySpanExporter.new
    )
  )
end

Voor background job monitoring maken de Sidekiq en Solid Queue auto-instrumentors automatisch parent spans aan voor elke job-uitvoering, gelinkt aan het web request dat de job in de wachtrij plaatste.

Performance Impact

Op de productie-app die ik eerder noemde (Rails 8.0.1, Ruby 3.3.6, ~500 req/s): OpenTelemetry auto-instrumentatie voegt ruwweg 1-2ms overhead toe per request. Het geheugengebruik steeg met ongeveer 15MB per Puma worker. De OTLP exporter batcht spans en verstuurt ze asynchroon, dus exportlatentie beïnvloedt de responstijden niet.

Als je GC-getuned Puma workers draait, houd dan rekening met de extra objectallocaties door span-creatie. In mijn benchmarks voegde OTel ~200 allocaties per request toe met auto-instrumentatie ingeschakeld. Niet nul, maar ruim acceptabel voor de zichtbaarheid die je krijgt.

FAQ

Werkt OpenTelemetry met Solid Queue in Rails 8?

Ja. De opentelemetry-instrumentation-active_job gem instrumenteert elke Active Job backend, inclusief Solid Queue. Elke job-uitvoering krijgt zijn eigen trace span die gelinkt is aan het bovenliggende request. Installeer het via de opentelemetry-instrumentation-all meta-gem of voeg het individueel toe.

Kan ik OpenTelemetry naast een bestaande APM-agent gebruiken?

Dat kan, maar ik zou het niet aanraden voor de lange termijn. Beide draaien betekent dubbele instrumentatie-overhead en mogelijk conflicterende monkey-patches. Een betere aanpak: migreer naar OpenTelemetry en gebruik de OTLP exporter om data naar je bestaande APM-vendor te sturen (de meeste accepteren nu OTLP — Datadog, New Relic, Honeycomb en Grafana Cloud allemaal).

Hoeveel vertraagt OpenTelemetry mijn Rails app?

In mijn productiemetingen: 1-2ms per request met volledige auto-instrumentatie en ongeveer 15MB extra geheugen per Puma worker. De async batch exporter zorgt ervoor dat telemetry-export de requestverwerking niet blokkeert.

Moet ik de OTLP HTTP of gRPC exporter gebruiken?

Gebruik HTTP (opentelemetry-exporter-otlp gem, poort 4318) tenzij je een specifieke reden hebt voor gRPC. HTTP is eenvoudiger te debuggen, werkt door meer proxies en load balancers heen, en het prestatieverschil is verwaarloosbaar voor de meeste Rails-applicaties.

#rails #opentelemetry #observability #monitoring #devops #productie
r

About the Author

Roger Heykoop is een senior Ruby on Rails ontwikkelaar met 19+ jaar Rails ervaring en 35+ jaar ervaring in softwareontwikkeling. Hij is gespecialiseerd in Rails modernisering, performance optimalisatie, en AI-ondersteunde ontwikkeling.

Get in Touch

Share this article

Need Expert Rails Development?

Let's discuss how we can help you build or modernize your Rails application with 19+ years of expertise

Schedule a Free Consultation