Rails Sentry: Foutbewaking Instellen, Aangepaste Contexten en Performance Tracing voor Rails 8 in Productie
Rails Sentry instellen voor Rails 8: foutopsporing, aangepaste contexten, performance tracing, sampling en het uitfilteren van ruis in productie-apps.
Een SaaS-klant van mij verwerkte de Europese btw gedurende zes maanden foutief voor zevenendertig zakelijke klanten. De bug zat in een deling-door-nul in een belastingberekening die alleen optrad wanneer een factureringsperiode een fiscaal jaareinde overlapte en het land van de klant een niet-geheel btw-tarief had. De fout gooide een ZeroDivisionError, die door hun globale rescue-handler werd opgevangen en stilzwijgend naar nul werd omgezet. Facturen gingen eruit met een regelitem van €0,00 btw. De klanten betaalden. Er ging geen alert af, er verscheen geen uitzondering in Slack, niemand merkte het totdat de boekhouder van een klant het ontdekte tijdens een audit.
Het engineeringteam had logging. Elk verzoek produceerde gestructureerde JSON-logs die naar CloudWatch werden gestuurd. De fout stond in die logs — tienduizend keer, één voor elke getroffen factuurrun. Niemand las CloudWatch-logs op het detailniveau dat nodig was om één fouttype te ontdekken, begraven in een zee van INFO-berichten.
Rails Sentry had bij het eerste optreden een alert gegenereerd en elke volgende keer onder hetzelfde issue gegroepeerd. Het engineeringteam had het binnen minuten geweten, niet maanden later.
Waarom Gestructureerde Foutbewaking Niet Optioneel Is
Logging is pull: je moet al weten dat er iets mis is voordat je gaat kijken. Foutbewaking is push: het vertelt je wanneer er iets fout is en hoe erg. Dat zijn fundamenteel verschillende dingen in productieoperaties.
Sentry doet ook iets wat logs niet kunnen: aggregeren. Wanneer een bug duizend gebruikers treft, wil je geen duizend afzonderlijke Slack-meldingen. Je wilt één alert die zegt: “deze fout is 1.000 keer opgetreden, treft 37 unieke gebruikers, en de teller versnelt.” Die aggregatie is wat je in staat stelt intelligent te prioriteren — je ziet meteen of dit een cosmetische edge case is die één gratis gebruiker raakt, of een fout die data corrumpeert bij je grootste enterprise-klanten.
Na negentien jaar Rails-applicaties in productie draaien, heb ik nog nooit gewerkt aan een codebase die foutbewaking uitzette nadat het eenmaal was ingericht. Ik heb wel gewerkt aan codebases die het nog niet hadden, en de verhalen van die projecten zijn precies de reden waarom ik foutbewaking nu behandel als infrastructuur — iets wat je op dag één instelt, naast de database en de deployment-pipeline, en niet een plugin die je inschakelt als het al mis gaat.
sentry-ruby en sentry-rails Installeren in Rails 8
Sentry verdeelt zijn Ruby SDK over gefocuste gems. Voeg ze in één keer toe:
# Gemfile
gem "sentry-ruby"
gem "sentry-rails"
# Voeg toe als je deze gebruikt:
gem "sentry-sidekiq" # Foutopvang voor Sidekiq-jobs
sentry-ruby is de kern-SDK — verwerking van het HTTP-transport, event-serialisatie, scope-management en de Sentry.*-API. sentry-rails haakt in op het Rails-notificatiesysteem en voegt automatische opvang toe van request-context, controllernamen, breadcrumbs van ActiveSupport::Notifications en exception-handling middleware die alles opvangt voordat er een 500 wordt teruggegeven.
Maak de initializer aan:
# config/initializers/sentry.rb
Sentry.init do |config|
config.dsn = ENV["SENTRY_DSN"]
config.breadcrumbs_logger = [:active_support_logger, :http_logger]
config.environment = Rails.env
config.enabled_environments = %w[staging production]
config.release = ENV.fetch("CURRENT_REVISION", nil) || `git rev-parse --short HEAD 2>/dev/null`.strip
config.send_default_pii = false
end
breadcrumbs_logger: [:active_support_logger] legt elke ActiveSupport::Notification vast — elke SQL-query, elke cache-hit, elke view-render — als breadcrumb bij het fout-event. Wanneer je een uitzondering in Sentry bekijkt, zie je de laatste twintig dingen die de applicatie deed vóór de crash, inclusief de specifieke query die een onverwacht resultaat opleverde. http_logger legt uitgaande HTTP-verzoeken vast. Beide zijn onmisbaar voor debuggen.
send_default_pii: false is de juiste standaard overal. Het verwijdert cookies, sessiedata en request-bodies van events vóór verzending. Wachtwoorden en tokens van je gebruikers verlaten je proces niet. Als je specifieke velden uit de request-body aan een event wilt koppelen, voeg je ze expliciet toe als extra op dat individuele event.
release koppelt Sentry aan je deployment-pipeline. Wanneer vijftig fouten allemaal beginnen om 14:32 UTC en je laatste release was abc123f, weet je precies welke deployment de bug introduceerde. In Kamal 2 — dat ik uitgebreid heb behandeld in de Rails 8 Kamal deployment-gids — geef je CURRENT_REVISION mee aan de container bij de deployment:
# config/deploy.yml (Kamal 2)
env:
CURRENT_REVISION: <%= `git rev-parse --short HEAD`.strip %>
Gebruikerscontext en Aangepaste Tags Instellen
Een fout-event zonder gebruikerscontext is een raadsel. Een fout-event met user_id: 4829, email: "enterprise@acme.com", plan: "enterprise" is een supportticket dat in vijf minuten kan worden opgelost.
Voeg dit toe aan je basiscontroller:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_sentry_context
private
def set_sentry_context
return unless current_user
Sentry.set_user(
id: current_user.id,
email: current_user.email,
username: current_user.username
)
Sentry.set_tags(
plan: current_account&.plan,
account_id: current_account&.id
)
end
end
Sentry.set_tags accepteert een hash en koppelt elk sleutel-waardepaar aan alle events die worden gegenereerd binnen de huidige request-scope. Tags zijn geïndexeerd en doorzoekbaar in Sentry — je kunt je foutenfeed filteren op plan:enterprise om te zien welke bugs je belangrijkste klanten raken, of op account_id:123 wanneer een specifiek account je supportlijn belt.
Voor achtergrond-jobs is er geen request-scope en geen current_user. Stel de context expliciet in aan het begin van de job:
class ProcessPaymentJob < ApplicationJob
def perform(payment_id)
payment = Payment.find(payment_id)
Sentry.set_tags(account_id: payment.account_id, payment_id: payment.id)
Sentry.set_user(id: payment.user_id)
PaymentProcessor.new(payment).call
end
end
Als je Solid Queue gebruikt — de standaard achtergrond-jobbackend van Rails 8 — haakt sentry-rails automatisch in op ActiveJob en omhult elke uitvoering in een Sentry-transactie. Je krijgt performance tracing voor achtergrond-jobs zonder extra configuratie.
Voeg breadcrumbs toe in langlopende operaties om een leesbaar spoor te creëren:
class MultiStepImportJob < ApplicationJob
def perform(import_id)
import = DataImport.find(import_id)
voeg_breadcrumb_toe("Import geladen", data: { id: import.id, row_count: import.row_count })
import.validate_source_schema!
voeg_breadcrumb_toe("Schema gevalideerd")
import.process_rows!
voeg_breadcrumb_toe("Verwerking voltooid", data: { ingevoegd: import.inserted_count })
end
private
def voeg_breadcrumb_toe(bericht, data: {})
Sentry.add_breadcrumb(
Sentry::Breadcrumb.new(message: bericht, data: data, level: "info")
)
end
end
Als deze job stukgaat op process_rows!, toont het breadcrumb-spoor in Sentry welke validatie slaagde, welke stap misliep en wat de importstatus op elk moment was. Debuggen wordt het lezen van een gestructureerd logboek in plaats van gissen.
Performance Tracing: Trage Verzoeken Vinden Voordat je Gebruikers Dat Doen
Rails Sentry bevat een performance-bewakingslaag die elk verzoek en elke job instrueert als een transactie, opgesplitst in spans: de SQL-queries, render-tijd van views, uitgaande HTTP-calls en Redis-operaties. Schakel het in met een samplepercentage:
Sentry.init do |config|
# ...bestaande config...
# Leg 5% van alle transacties vast
config.traces_sample_rate = 0.05
end
Een vast percentage werkt prima voor applicaties met weinig verkeer. Voor productie-apps met uiteenlopende verkeerspatronen — health checks die elke paar seconden /up raken, webhook-endpoints met hoog volume, zeldzame adminflows — gebruik je een sampler:
Sentry.init do |config|
# ...
config.traces_sampler = lambda do |sampling_context|
path = sampling_context.dig("rack_env", "PATH_INFO").to_s
return 0 if path.match?(%r{\A/(up|health|ping)}) # nooit
return 0.01 if path.start_with?("/api/v1/webhooks") # hoog volume, weinig waarde
return 1.0 if path.start_with?("/admin") # altijd admin tracen
0.05 # 5% van al het overige
end
end
Voor het instrumenteren van je eigen code — externe API-calls, trage bedrijfslogica, diensten van derden — omhul je de operatie in een child span:
class BtwCalculator
def bereken(factuur)
Sentry.with_child_span(op: "tax.calculate", description: "BTW opzoeken en berekenen") do |span|
span.set_data("factuur_id", factuur.id)
span.set_data("landcode", factuur.country_code)
tarieven = BelastingTariefService.ophalen(factuur.country_code)
resultaat = tarieven.toepassen(factuur.subtotaal)
span.set_data("effectief_tarief", tarieven.effectief_tarief)
resultaat
end
end
end
In het Sentry performance-dashboard verschijnt deze span in de transactietijdlijn van het verzoek. Je ziet in één oogopslag of de btw-berekening 800ms van een 900ms-verzoek verbruikt, en je kunt inzoomen op de data-attributen om de landcode te vinden die de piek veroorzaakt.
Ruis Filteren: Wat Je Niet Wilt Rapporteren
Een Sentry-dashboard vol ActionController::RoutingError van bots die /wp-admin proberen is waardeloos. Het doel is een bruikbare foutenfeed waarbij elk open issue een echte bug in je code vertegenwoordigt.
Gebruik before_send om events te verwijderen voordat ze het proces verlaten:
Sentry.init do |config|
# ...
config.before_send = lambda do |event, hint|
exception = hint[:exception]
if exception
return nil if exception.is_a?(ActiveRecord::RecordNotFound)
return nil if exception.is_a?(ActionController::RoutingError)
return nil if exception.is_a?(ActionController::UnknownFormat)
return nil if exception.is_a?(ActionController::InvalidAuthenticityToken)
end
event
end
end
Een noot over RecordNotFound: ik filter dit globaal weg voor webverzoeken, maar bewaar het voor API-endpoints die zijn geverifieerd met een API-sleutel. Wanneer een geverifieerde client consequent 404’s genereert, is dat een bug in diens integratie en wil ik dat weten. Het filter kan conditioneel zijn:
config.before_send = lambda do |event, hint|
exception = hint[:exception]
if exception.is_a?(ActiveRecord::RecordNotFound)
return event if event.request&.url.to_s.include?("/api/")
return nil
end
event
end
Filter ook health check-routes uit het performance-dashboard — ze domineren de transactielijst en bevatten geen inzicht:
config.traces_before_send = lambda do |event, _hint|
return nil if event.transaction&.match?(%r{\A/(up|health|ping)})
event
end
Uitzonderingen Handmatig Vastleggen met Context
De automatische opvang verwerkt alles wat onbehandeld doorborrelt naar de Rack-middleware. Je hebt Sentry.capture_exception nodig voor uitzonderingen die je expliciet opvangt maar alsnog wilt bijhouden — time-outs van betalingsverwerkers die je gracieus afhandelt, externe API-fouten die een herpoging triggeren, validatiefouten in een importjob die je omzet naar een gebruikersfoutmelding:
class ExterneFeedImporter
def importeer(feed_url)
response = Faraday.get(feed_url)
verwerk_en_sla_op(response.body)
rescue Faraday::ConnectionFailed => e
Sentry.capture_exception(e,
level: "warning",
extra: {
feed_url: feed_url,
pogingen: @retry_count
},
tags: { integratie: "external_feed" }
)
plan_herpoging
rescue ParseError => e
raise # Niet herstelbaar — laat doorborrelen voor automatische opvang
end
end
level: "warning" markeert het event als verwacht-maar-zorgwekkend in plaats van een volledige fout. Gebruik level: "error" (de standaard) voor echte bugs. Gebruik level: "warning" voor situaties die je gracieus afhandelt maar wilt tellen. Gebruik level: "info" voor bedrijfsgebeurtenissen die je wilt observeren — bijvoorbeeld bijhouden hoe vaak een dure fallback-codepad wordt geactiveerd.
Sentry vs Honeybadger vs AppSignal: Een Eerlijk Oordeel
Ik heb alle drie gebruikt in productie op clientcodebases. Dit is mijn eerlijke vergelijking.
Honeybadger is de juiste keuze voor een soloontwikkelaar of een klein team dat “waarschuw me als er iets stukgaat” wil zonder een complexe configuratie of een dure licentie. De interface is eenvoudig, de Ruby-integratie is solide en de gratis tier is echt bruikbaar in productie. Er is geen performance tracing, de foutgroepering is minder geavanceerd dan Sentry’s, en polyglot-stacks worden niet ondersteund. Voor een team van twee Rails-ontwikkelaars: Honeybadger.
AppSignal is gebouwd exclusief voor Ruby en Elixir, en dat merk je. De Rails-integratie begrijpt ActiveRecord, Sidekiq en Solid Queue op manieren die een taalonafhankelijk hulpmiddel niet zomaar kan repliceren. Hostmonitoring — geheugen, CPU, schijf — is inbegrepen bij applicatiemonitoring. N+1-querydetectie werkt automatisch zonder Bullet of expliciete instrumentatie. De dashboards zijn mooi en het supportteam reageert uitzonderlijk snel. Ik raad AppSignal aan voor pure Rails-shops die één tool willen die zowel de applicatie als de host dekt. De prijs weerspiegelt de diepgang.
Sentry wint wanneer je stack polyglot is — een Rails-API, een React-frontend, een Python-datapijplijn, een serverloze Node-functie. Elk onderdeel rapporteert naar één dashboard, fouten van de frontend en de API kunnen worden gecorreleerd via een gedeeld trace_id, en release-tracking overspant alle diensten tegelijkertijd. De open-source zelfgehoste optie is ook een echte optie: als je dataresiduatievereisten hebt of je bewakingsinfrastructuur zelf wilt beheren, draai je Sentry op eigen hardware. Voor teams die Sentry al elders gebruiken voor andere stacks zijn de netwerkeffecten van alles op één plek aanzienlijk.
Mijn aanbeveling: Sentry voor polyglot-stacks of teams die Sentry elders al gebruiken. AppSignal voor pure Rails-shops die de sterkste native integratie willen. Honeybadger voor zeer kleine teams die iets betrouwbaars willen zonder enige afstelling.
Sentry Verbinden met het Bredere Observabiliteitsplaatje
Foutbewaking en observabiliteit zijn complementaire hulpmiddelen, geen alternatieven voor elkaar. Ik schreef over gestructureerde logging en de debugworkflow in de Rails logging-post, en over het instellen van OpenTelemetry voor gedistribueerd traceren in de Rails 8 productie-observabiliteitspost.
De combinatie die ik tegenwoordig op de meeste clientproductiesystemen draai: Rails Sentry voor foutaggregatie en gebruikersgerichte performance-bewaking, OpenTelemetry met zelfgehoste Grafana Tempo voor gedistribueerde traces over diensten heen, en gestructureerde logging naar CloudWatch of Loki voor de ruwe stroom. Elk hulpmiddel doet wat het beste doet. Sentry is de eerste alert en het eerste debugoppervlak. De gedistribueerde trace is wat je raadpleegt wanneer de foutcontext alleen niet voldoende is.
Veelgestelde Vragen
Wat is het verschil tussen automatische opvang door Sentry en handmatig aanroepen van Sentry.capture_exception?
sentry-rails vangt automatisch elke uitzondering op die onbehandeld naar het Rack-middlewareniveau doorborrelt — niet-afgehandelde fouten in controllers, jobs zonder rescue-blocks, alles wat anders een 500-respons zou opleveren. Sentry.capture_exception gebruik je voor uitzonderingen die je expliciet opvangt maar alsnog wilt bijhouden: time-outs van betalingsverwerkers die je met een herpoging afhandelt, externe API-fouten die je omzet naar gebruikersberichten, importvalidatiefouten die je in de database schrijft. Automatische opvang dekt bugs die je niet verwachtte; handmatige opvang dekt situaties die je verwacht maar wilt meten.
Hoe voorkom ik dat Sentry wachtwoorden of API-sleutels logt?
config.send_default_pii = false verwijdert cookies en sessies. Voor request-bodies — waar wachtwoorden in loginformulieren reizen — respecteert sentry-rails de filter_parameters-lijst van Rails:
# config/application.rb
config.filter_parameters += [:password, :password_confirmation, :token, :secret, :api_key]
Elke parameternaam die overeenkomt met deze lijst wordt vervangen door [FILTERED] in Sentry-events voordat ze het proces verlaten. Breid filter_parameters uit in plaats van eigen scrubbing-logica te schrijven in before_send — het Rails-mechanisme dekt zowel je logs als Sentry op één plek en gaat minder snel afwijken.
Kan Sentry N+1-queries detecteren?
Niet als een benoemde categorie. Sentry’s performance tracing toont elke SQL-query die tijdens een verzoek wordt uitgevoerd als een afzonderlijke span in de transactietijdlijn, wat het direct duidelijk maakt wanneer een controlleractie 150 queries uitvoert in plaats van 3 — je ziet het herhalende patroon in de spanlijst. Maar het markeert “dit is een N+1” niet zoals Bullet dat doet tijdens ontwikkeling. Voor proactieve N+1-preventie combineer ik Sentry met Rails strict loading in ontwikkeling; dat workflow behandelde ik uitgebreid in de strict loading-post. Sentry vertelt je dat het probleem zich in productie voordoet; strict loading voorkomt dat het überhaupt wordt uitgeleverd.
Hoe werkt Rails Sentry met Solid Queue-achtergrond-jobs?
sentry-rails haakt in op ActiveJob, de interface die Solid Queue gebruikt. Elke jobuitvoering wordt automatisch een Sentry-transactie. Als de job een fout gooit, wordt de uitzondering vastgelegd met het volledige breadcrumb-spoor, de jobklassenaam, de wachtrij en de geserialiseerde argumenten. Het enige wat je handmatig moet toevoegen is gebruikers- en accountcontext aan het begin van jobs die gebruikersdata verwerken — Sentry.set_user en Sentry.set_tags in de perform-methode, vóór de eerste regel bedrijfslogica. Zonder dat verschijnen uitzonderingen uit achtergrond-jobs zonder context en kosten ze veel meer tijd om te koppelen aan een specifieke gebruiker of account.
Een productie-Rails-applicatie zonder foutbewaking is een black box die problemen pas meldt wanneer een klant belt. Na negentien jaar Rails-productieondersteuning heb ik nog nooit gezien dat het alternatief betrouwbaar werkt. TTB Software richt Rails Sentry, observabiliteit en alertering in als onderdeel van elke productie-opdracht — want het uur dat je aan deze setup besteedt, verdien je terug bij de eerste keer dat een alert afgaat voordat een klant het merkt.
Related Articles
Rails Sorbet: Geleidelijke typeveiligheid toevoegen aan legacy Rails-applicaties met sig, tapioca en CI
Rails Sorbet gids: voeg geleidelijke typeveiligheid toe aan legacy Rails-apps met sig, tapioca RBI-generatie, srb tc,...
Rails Systeemtests met Capybara: End-to-End Testing, CI-configuratie en Flaky Tests Elimineren
Rails systeemtests met Capybara: headless Chrome instellen, betrouwbare end-to-end specs schrijven, snel draaien in C...
Rails LLM Structured Output: Betrouwbare JSON van Claude en OpenAI met Schema Validatie
Rails LLM structured output gids: betrouwbare JSON van Claude en OpenAI met schema mode, response validatie en retrie...