Class: ScoutApm::LayerConverters::ConverterBase
- Inherits:
-
Object
- Object
- ScoutApm::LayerConverters::ConverterBase
- Defined in:
- lib/scout_apm/layer_converters/converter_base.rb
Direct Known Subclasses
AllocationMetricConverter, ErrorConverter, JobConverter, MetricConverter, RequestQueueTimeConverter, SlowJobConverter, SlowRequestConverter
Constant Summary collapse
- MAX_METRICS =
To prevent huge traces from being generated, we should stop collecting detailed metrics as we go beyond some reasonably large count.
We should still add up the /all aggregates.
500
Instance Attribute Summary collapse
-
#request ⇒ Object
readonly
Returns the value of attribute request.
-
#root_layer ⇒ Object
readonly
Returns the value of attribute root_layer.
-
#walker ⇒ Object
readonly
Returns the value of attribute walker.
Instance Method Summary collapse
-
#attach_backtraces(metric_hash) ⇒ Object
Call this after you finish walking the layers, and want to take the set-aside backtraces and place them into the metas they match.
- #find_first_layer_of_type(layer_type) ⇒ Object
-
#initialize(request) ⇒ ConverterBase
constructor
A new instance of ConverterBase.
- #limited? ⇒ Boolean
-
#make_meta_options(layer) ⇒ Object
When we make MetricMeta records, we need to determine a few things from layer.
- #make_meta_options_desc_hash(layer, max_desc_length = 1000) ⇒ Object
- #make_meta_options_scope(layer) ⇒ Object
- #over_metric_limit?(metric_hash) ⇒ Boolean
-
#scope_layer ⇒ Object
Scope is determined by the first Controller we hit.
-
#setup_subscopable_callbacks ⇒ Object
Subscoping.
-
#skip_layer?(layer) ⇒ Boolean
Sometimes we start capturing a layer without knowing if we really want to make an entry for it.
-
#store_aggregate_metric(layer, metric_hash, allocation_metric_hash) ⇒ Object
Merged Metric - no specifics, just sum up by type (ActiveRecord, View, HTTP, etc).
-
#store_backtrace(layer, meta) ⇒ Object
Call this as you are processing each layer.
-
#store_specific_metric(layer, metric_hash, allocation_metric_hash) ⇒ Object
This is the detailed metric - type, name, backtrace, annotations, etc.
- #subscope_name ⇒ Object
- #subscoped?(layer) ⇒ Boolean
Constructor Details
#initialize(request) ⇒ ConverterBase
Returns a new instance of ConverterBase.
9 10 11 12 13 14 15 16 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 9 def initialize(request) @request = request @root_layer = request.root_layer @backtraces = [] @walker = DepthFirstWalker.new(root_layer) @limited = false end |
Instance Attribute Details
#request ⇒ Object (readonly)
Returns the value of attribute request.
6 7 8 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 6 def request @request end |
#root_layer ⇒ Object (readonly)
Returns the value of attribute root_layer.
7 8 9 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 7 def root_layer @root_layer end |
#walker ⇒ Object (readonly)
Returns the value of attribute walker.
5 6 7 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 5 def walker @walker end |
Instance Method Details
#attach_backtraces(metric_hash) ⇒ Object
Call this after you finish walking the layers, and want to take the set-aside backtraces and place them into the metas they match
96 97 98 99 100 101 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 96 def attach_backtraces(metric_hash) @backtraces.each do || metric_hash.keys.find { |k| k == }.backtrace = .backtrace end metric_hash end |
#find_first_layer_of_type(layer_type) ⇒ Object
29 30 31 32 33 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 29 def find_first_layer_of_type(layer_type) walker.walk do |layer| return layer if layer.type == layer_type end end |
#limited? ⇒ Boolean
123 124 125 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 123 def limited? !! @limited end |
#make_meta_options(layer) ⇒ Object
When we make MetricMeta records, we need to determine a few things from layer.
132 133 134 135 136 137 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 132 def (layer) scope_hash = (layer) desc_hash = (layer) scope_hash.merge(desc_hash) end |
#make_meta_options_desc_hash(layer, max_desc_length = 1000) ⇒ Object
158 159 160 161 162 163 164 165 166 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 158 def (layer, max_desc_length=1000) if layer.desc desc_s = layer.desc.to_s trimmed_desc = desc_s[0 .. max_desc_length] {:desc => trimmed_desc} else {} end end |
#make_meta_options_scope(layer) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 139 def (layer) # This layer is scoped under another thing. Typically that means this is a layer under a view. # Like: Controller -> View/users/show -> ActiveRecord/user/find # in that example, the scope is the View/users/show if subscoped?(layer) {:scope => subscope_name} # We don't scope the controller under itself elsif layer == scope_layer {} # This layer is a top level metric ("ActiveRecord", or "HTTP" or # whatever, directly under the controller), so scope to the # Controller else {:scope => scope_layer.legacy_metric_name} end end |
#over_metric_limit?(metric_hash) ⇒ Boolean
115 116 117 118 119 120 121 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 115 def over_metric_limit?(metric_hash) if metric_hash.size > MAX_METRICS @limited = true else false end end |
#scope_layer ⇒ Object
Scope is determined by the first Controller we hit. Most of the time there will only be 1 anyway. But if you have a controller that calls another controller method, we may pick that up:
def update
show
render :update
end
25 26 27 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 25 def scope_layer @scope_layer ||= find_first_layer_of_type("Controller") || find_first_layer_of_type("Job") end |
#setup_subscopable_callbacks ⇒ Object
Subscoping
Keep a list of subscopes, but only ever use the front one. The rest get pushed/popped in cases when we have many levels of subscopable layers. This lets us push/pop without otherwise keeping track very closely.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 42 def setup_subscopable_callbacks @subscope_layers = [] walker.before do |layer| if layer.subscopable? @subscope_layers.push(layer) end end walker.after do |layer| if layer.subscopable? @subscope_layers.pop end end end |
#skip_layer?(layer) ⇒ Boolean
Sometimes we start capturing a layer without knowing if we really want to make an entry for it. See ActiveRecord instrumentation for an example. We start capturing before we know if a query is cached or not, and want to skip any cached queries.
225 226 227 228 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 225 def skip_layer?(layer) return false if layer.annotations.nil? return true if layer.annotations[:ignorable] end |
#store_aggregate_metric(layer, metric_hash, allocation_metric_hash) ⇒ Object
Merged Metric - no specifics, just sum up by type (ActiveRecord, View, HTTP, etc)
202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 202 def store_aggregate_metric(layer, metric_hash, allocation_metric_hash) = MetricMeta.new("#{layer.type}/all") metric_hash[] ||= MetricStats.new(false) allocation_metric_hash[] ||= MetricStats.new(false) # timing stat = metric_hash[] stat.update!(layer.total_call_time, layer.total_exclusive_time) # allocations stat = allocation_metric_hash[] stat.update!(layer.total_allocations, layer.total_exclusive_allocations) end |
#store_backtrace(layer, meta) ⇒ Object
Call this as you are processing each layer. It will store off backtraces
84 85 86 87 88 89 90 91 92 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 84 def store_backtrace(layer, ) return unless layer.backtrace bt = ScoutApm::Utils::BacktraceParser.new(layer.backtrace).call if bt.any? .backtrace = bt @backtraces << end end |
#store_specific_metric(layer, metric_hash, allocation_metric_hash) ⇒ Object
This is the detailed metric - type, name, backtrace, annotations, etc.
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 174 def store_specific_metric(layer, metric_hash, allocation_metric_hash) return false if over_metric_limit?(metric_hash) = (layer) = MetricMeta.new(layer.legacy_metric_name, ) .extra.merge!(layer.annotations) if layer.annotations store_backtrace(layer, ) metric_hash[] ||= MetricStats.new(.has_key?(:scope)) allocation_metric_hash[] ||= MetricStats.new(.has_key?(:scope)) # timing stat = metric_hash[] stat.update!(layer.total_call_time, layer.total_exclusive_time) # allocations stat = allocation_metric_hash[] stat.update!(layer.total_allocations, layer.total_exclusive_allocations) if LimitedLayer === layer metric_hash[].call_count = layer.count allocation_metric_hash[].call_count = layer.count end end |
#subscope_name ⇒ Object
62 63 64 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 62 def subscope_name @subscope_layers.first.legacy_metric_name end |
#subscoped?(layer) ⇒ Boolean
58 59 60 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 58 def subscoped?(layer) @subscope_layers.first && layer != @subscope_layers.first # Don't scope under ourself. end |