Skip to content

Conversation

@solnic
Copy link
Collaborator

@solnic solnic commented Nov 6, 2025

After introducing enable_db_query_source in Rails that's enabled by default ActiveRecord tracing may have potentially became slower, or much slower, depending on the use cases. I believe this is the main culprit causing #2595.

This PR optimizes how query source information is obtained by:

  1. Replacing re-parsing of source line and instantiating Sentry::Backtrace::Line manually based on the location object that we already have
  2. Caching instantiated line objects

This makes a significant difference according to various benchmarks I ran:

master - disabled enable_db_query_source vs enabled

Warming up --------------------------------------
            disabled     1.000  i/100ms
enabled, threshold=0ms
                         1.000  i/100ms
Calculating -------------------------------------
            disabled      1.344  (± 0.0%) i/s -      7.000 
enabled, threshold=0ms
                          0.718  (± 0.0%) i/s -      4.000  in   5.579486s

Comparison:
            disabled:        1.3 i/s
enabled, threshold=0ms:        0.7 i/s - 1.87x slower

Calculating -------------------------------------
            disabled   129.429M memsize (    11.868M retained)
                         1.452M objects (    74.837k retained)
                        50.000  strings (    50.000  retained)
enabled, threshold=0ms
                       490.249M memsize (    12.676M retained)
                         3.118M objects (    84.908k retained)
                        50.000  strings (    50.000  retained)

Comparison:
            disabled:  129429394 allocated
enabled, threshold=0ms:  490249058 allocated - 3.79x more

this PR - same benchmark disabled enabled_db_query_source vs enabled

± bundle exec ruby benchmarks/db_query_source_benchmark.rb

Warming up --------------------------------------
            disabled     1.000  i/100ms
enabled, threshold=0ms
                         1.000  i/100ms
Calculating -------------------------------------
            disabled      1.269  (± 0.0%) i/s -      7.000  in   5.522006s
enabled, threshold=0ms
                          1.103  (± 0.0%) i/s -      6.000  in   5.454174s

Comparison:
            disabled:        1.3 i/s
enabled, threshold=0ms:        1.1 i/s - 1.15x slower

Calculating -------------------------------------
            disabled   129.869M memsize (    11.893M retained)
                         1.457M objects (    75.050k retained)
                        50.000  strings (    50.000  retained)
enabled, threshold=0ms
                       158.062M memsize (    11.901M retained)
                         1.923M objects (    75.121k retained)
                        50.000  strings (    50.000  retained)

Comparison:
            disabled:  129869394 allocated
enabled, threshold=0ms:  158062090 allocated - 1.22x more

This shows a much smaller impact both in terms of execution time and memory usage.

Rails app benchmarks

I tested this with a simple rails app that just does a bunch of AR queries.

Low intensity

Screenshot 2025-11-07 at 16 08 37 Screenshot 2025-11-07 at 16 08 27

High intensity

Screenshot 2025-11-07 at 16 06 54 Screenshot 2025-11-07 at 16 07 46

Closes #2595

@codecov
Copy link

codecov bot commented Nov 6, 2025

Codecov Report

❌ Patch coverage is 68.42105% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.15%. Comparing base (7755dab) to head (c39b896).

Files with missing lines Patch % Lines
sentry-ruby/lib/sentry/backtrace.rb 27.27% 16 Missing ⚠️
...b/sentry/rails/tracing/active_record_subscriber.rb 22.22% 7 Missing ⚠️
sentry-ruby/lib/sentry/backtrace/line.rb 97.77% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2769      +/-   ##
==========================================
- Coverage   90.28%   90.15%   -0.13%     
==========================================
  Files         131      132       +1     
  Lines        5258     5281      +23     
==========================================
+ Hits         4747     4761      +14     
- Misses        511      520       +9     
Components Coverage Δ
sentry-ruby 97.20% <74.62%> (-0.40%) ⬇️
sentry-rails 55.68% <22.22%> (+0.33%) ⬆️
sentry-sidekiq 95.05% <ø> (ø)
sentry-resque 94.44% <ø> (ø)
sentry-delayed_job 94.68% <ø> (ø)
sentry-opentelemetry 99.31% <ø> (ø)
Files with missing lines Coverage Δ
sentry-ruby/lib/sentry/backtrace/line.rb 97.77% <97.77%> (ø)
...b/sentry/rails/tracing/active_record_subscriber.rb 35.55% <22.22%> (+2.22%) ⬆️
sentry-ruby/lib/sentry/backtrace.rb 63.82% <27.27%> (-32.84%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@solnic solnic force-pushed the solnic/optimize-source-location branch 3 times, most recently from 47c1e3a to cff0932 Compare November 7, 2025 14:26
@solnic solnic force-pushed the solnic/optimize-source-location branch from cff0932 to 160e343 Compare November 7, 2025 15:15
@solnic solnic changed the title Optimize source location [rails] improve AR tracing performance Nov 7, 2025
@solnic solnic marked this pull request as ready for review November 7, 2025 15:34
@solnic solnic requested a review from sl0thentr0py November 7, 2025 15:34
# Only JRuby has namespace in the backtrace
span.set_data(Span::DataConventions::NAMESPACE, backtrace_line.module_name) if backtrace_line.module_name
if record_query_source && duration >= query_source_threshold
backtrace_line = Backtrace.source_location(backtrace_cleaner)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Missing require "sentry/backtrace" causes NameError when calling Backtrace.source_location.
Severity: CRITICAL | Confidence: 1.00

🔍 Detailed Analysis

The Backtrace.source_location method is called at sentry-rails/lib/sentry/rails/tracing/active_record_subscriber.rb:69 without an explicit require "sentry/backtrace" statement. This will result in a NameError: uninitialized constant Backtrace when SUPPORT_SOURCE_LOCATION is true (Ruby 3.2+ with clean_frame method), Sentry.configuration.rails.enable_db_query_source is enabled, and a database query exceeds db_query_source_threshold_ms.

💡 Suggested Fix

Add require "sentry/backtrace" to sentry-rails/lib/sentry/rails/tracing/active_record_subscriber.rb to ensure the Backtrace constant is defined.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: sentry-rails/lib/sentry/rails/tracing/active_record_subscriber.rb#L69

Potential issue: The `Backtrace.source_location` method is called at
`sentry-rails/lib/sentry/rails/tracing/active_record_subscriber.rb:69` without an
explicit `require "sentry/backtrace"` statement. This will result in a `NameError:
uninitialized constant Backtrace` when `SUPPORT_SOURCE_LOCATION` is true (Ruby 3.2+ with
`clean_frame` method), `Sentry.configuration.rails.enable_db_query_source` is enabled,
and a database query exceeds `db_query_source_threshold_ms`.

Did we get this right? 👍 / 👎 to inform future reviews.

index = label.index("#") || label.index(".")
module_name = label[0, index] if index

new(file, number, method, module_name, in_app_pattern)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Ruby VersionGuard for Module Name Extraction

The from_source_location method extracts module_name from location.label on all Ruby versions, but the tests and CHANGELOG indicate this should only happen on Ruby 3.4+. Earlier Ruby versions don't include namespace information in the label format, so extracting it may produce incorrect results. The extraction logic needs a Ruby version check to match the documented behavior.

Fix in Cursor Fix in Web

@solnic solnic requested a review from dingsdax November 7, 2025 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sentry-rails 5.23.0 ActiveRecord overhead

2 participants