class ScoutApm::Utils::ActiveRecordMetricName
Constants
- BEGIN_STATEMENT
- COMMIT
- COUNT
- COUNT_LABEL
- DEFAULT_METRIC
- DELETE_LABEL
- DELETE_REGEX
- FROM
- INSERT_LABEL
- INSERT_REGEX
- INTO
- NON_GREEDY_CONSUME
- REGEX_OPERATION
- SELECT_LABEL
- SELECT_REGEX
- TABLE
- UNKNOWN_LABEL
- UPDATE_LABEL
- UPDATE_REGEX
- WHITE_SPACE
-
Regex based naming #
Attributes
Public Class Methods
Source
# File lib/scout_apm/utils/active_record_metric_name.rb, line 7 def initialize(sql, name) @sql = sql || "" @name = name.to_s end
Public Instance Methods
Source
# File lib/scout_apm/utils/active_record_metric_name.rb, line 48 def eql?(o) self.class == o.class && name.downcase == o.name.downcase end
For the layer lookup. Reminder: eql?
is for Hash equality: returns true if obj and other refer to the same hash key.
Source
# File lib/scout_apm/utils/active_record_metric_name.rb, line 41 def hash h = name.downcase.hash h end
For the layer lookup.
Source
# File lib/scout_apm/utils/active_record_metric_name.rb, line 31 def model parts.first end
This only returns a value if a name is provided via initialize
.
Source
# File lib/scout_apm/utils/active_record_metric_name.rb, line 36 def normalized_operation parse_operation end
This only returns a value if a name is provided via initialize
.
Source
# File lib/scout_apm/utils/active_record_metric_name.rb, line 20 def to_s return @to_s if @to_s parsed = parse_operation if parsed @to_s = "#{model}/#{parsed}" else @to_s = regex_name(sql) end end
Converts an SQL string and the name (typically assigned automatically by rails) into a Scout metric_name.
This prefers to use the ActiveRecord-provided name over parsing SQL as parsing is slower.
sql: SELECT “places”.* FROM
“places” ORDER BY “places”.“position” ASC name: Place Load metric_name: Place/find
Private Instance Methods
Source
# File lib/scout_apm/utils/active_record_metric_name.rb, line 58 def operation if parts.length >= 2 parts[1].downcase end end
This only returns a value if a name is provided via initialize
.
Source
# File lib/scout_apm/utils/active_record_metric_name.rb, line 71 def parse_operation case operation when 'indexes', 'columns' then nil # not under developer control when 'load' then 'find' when 'destroy', 'find', 'save', 'create', 'exists' then operation when 'update' then 'save' else if model == 'Join' operation end end end
Returns nil if no match Returns nil if the operation wasn’t under developer control (and hence isn’t interesting to report)
Source
# File lib/scout_apm/utils/active_record_metric_name.rb, line 65 def parts name.split(" ") end
This only returns a value if a name is provided via initialize
.
Source
# File lib/scout_apm/utils/active_record_metric_name.rb, line 122 def regex_name(sql) # We rely on the ActiveSupport inflections code here. Bail early if we can't use it. return UNKNOWN_LABEL unless UNKNOWN_LABEL.respond_to?(:classify) if match = SELECT_REGEX.match(sql) operation = if match[2] COUNT_LABEL else SELECT_LABEL end "#{match[3].gsub(/\W/,'').classify}/#{operation}" elsif match = UPDATE_REGEX.match(sql) "#{match[2].classify}/#{UPDATE_LABEL}" elsif match = INSERT_REGEX.match(sql) "#{match[2].classify}/#{INSERT_LABEL}" elsif match = DELETE_REGEX.match(sql) "#{match[2].classify}/#{DELETE_LABEL}" elsif sql == BEGIN_STATEMENT "SQL/#{BEGIN_STATEMENT.downcase}" elsif sql == COMMIT "SQL/#{COMMIT.downcase}" else UNKNOWN_LABEL end rescue UNKNOWN_LABEL end
Attempt to do some basic parsing of SQL via regexes to extract the SQL verb (select, update, etc) and the table being operated on.
This is a fallback from what ActiveRecord gives us, we prefer its names. But sometimes it is giving us a no-name query, and we have to attempt to figure it out ourselves.
This relies on ActiveSupport’s classify method. If it’s not present, just skip the attempt to rename here. This could happen in a Grape or Sinatra application that doesn’t import ActiveSupport. At this point, you’re already using ActiveRecord, so it’s likely loaded anyway.