Class: ScoutApm::CallSet
- Inherits:
-
Object
- Object
- ScoutApm::CallSet
- Defined in:
- lib/scout_apm/call_set.rb
Constant Summary collapse
- N_PLUS_ONE_MAGIC_NUMBER =
Fetch backtraces on this number of calls to a layer. The caller data is only collected on this call to limit overhead.
5
- N_PLUS_ONE_TIME_THRESHOLD =
Minimum time in seconds before we start performing any work. This is to prevent doing a lot of work on already fast calls.
150/1000.0
Instance Attribute Summary collapse
-
#call_count ⇒ Object
readonly
Returns the value of attribute call_count.
Instance Method Summary collapse
- #at_magic_number? ⇒ Boolean
-
#capture_backtrace? ⇒ Boolean
We’re selective on capturing a backtrace for two reasons: * Grouping ActiveRecord calls requires us to sanitize the SQL.
- #grouped_items ⇒ Object
-
#initialize ⇒ CallSet
constructor
A new instance of CallSet.
-
#past_time_threshold? ⇒ Boolean
Limit our workload if time across this set of calls is small.
-
#unique_name_for(item) ⇒ Object
Determine this items’ “hash key”.
- #update!(item = nil) ⇒ Object
Constructor Details
#initialize ⇒ CallSet
Returns a new instance of CallSet.
9 10 11 12 13 14 15 16 |
# File 'lib/scout_apm/call_set.rb', line 9 def initialize @items = [] # An array of Layer descriptions that are associated w/a single Layer name (ex: User/find). Note this may contain nil items. @grouped_items = Hash.new { |h, k| h[k] = [] } # items groups by their normalized name since multiple layers could have the same layer name. @call_count = 0 @captured = false # cached for performance @start_time = Time.now @past_start_time = false # cached for performance end |
Instance Attribute Details
#call_count ⇒ Object (readonly)
Returns the value of attribute call_count.
7 8 9 |
# File 'lib/scout_apm/call_set.rb', line 7 def call_count @call_count end |
Instance Method Details
#at_magic_number? ⇒ Boolean
44 45 46 |
# File 'lib/scout_apm/call_set.rb', line 44 def at_magic_number? grouped_items[unique_name_for(@items.last)].size >= N_PLUS_ONE_MAGIC_NUMBER end |
#capture_backtrace? ⇒ Boolean
We’re selective on capturing a backtrace for two reasons:
-
Grouping ActiveRecord calls requires us to sanitize the SQL. This isn’t cheap.
-
Capturing backtraces isn’t cheap.
38 39 40 41 42 |
# File 'lib/scout_apm/call_set.rb', line 38 def capture_backtrace? if !@captured && @call_count >= N_PLUS_ONE_MAGIC_NUMBER && past_time_threshold? && at_magic_number? @captured = true end end |
#grouped_items ⇒ Object
48 49 50 51 52 53 54 |
# File 'lib/scout_apm/call_set.rb', line 48 def grouped_items if @grouped_items.any? @grouped_items else @grouped_items.merge!(@items.group_by { |item| unique_name_for(item) }) end end |
#past_time_threshold? ⇒ Boolean
Limit our workload if time across this set of calls is small.
30 31 32 33 |
# File 'lib/scout_apm/call_set.rb', line 30 def past_time_threshold? return true if @past_time_threshold # no need to check again once past @past_time_threshold = (Time.now-@start_time) >= N_PLUS_ONE_TIME_THRESHOLD end |
#unique_name_for(item) ⇒ Object
Determine this items’ “hash key”
57 58 59 |
# File 'lib/scout_apm/call_set.rb', line 57 def unique_name_for(item) item.to_s end |
#update!(item = nil) ⇒ Object
18 19 20 21 22 23 24 25 26 27 |
# File 'lib/scout_apm/call_set.rb', line 18 def update!(item = nil) if @captured # No need to do any work if we've already captured a backtrace. return end @call_count += 1 @items << item if @grouped_items.any? # lazy grouping as normalizing items can be expensive. @grouped_items[unique_name_for(item)] << item end end |