Class: ScoutApm::LayerConverters::ConverterBase
- Inherits:
-
Object
- Object
- ScoutApm::LayerConverters::ConverterBase
- Defined in:
- lib/scout_apm/layer_converters/converter_base.rb
Direct Known Subclasses
AllocationMetricConverter, DatabaseConverter, ErrorConverter, Histograms, JobConverter, MetricConverter, RequestQueueTimeConverter, SlowJobConverter, SlowRequestConverter, TraceConverter
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
-
#context ⇒ Object
readonly
Returns the value of attribute context.
-
#layer_finder ⇒ Object
readonly
Returns the value of attribute layer_finder.
-
#request ⇒ Object
readonly
Returns the value of attribute request.
-
#root_layer ⇒ Object
readonly
Returns the value of attribute root_layer.
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.
-
#initialize(context, request, layer_finder, store = nil) ⇒ 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 = 32768) ⇒ Object
- #make_meta_options_scope(layer) ⇒ Object
- #over_metric_limit?(metric_hash) ⇒ Boolean
-
#register_hooks(walker) ⇒ Object
Subscoping.
- #scope_layer ⇒ Object
-
#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(context, request, layer_finder, store = nil) ⇒ ConverterBase
Returns a new instance of ConverterBase.
10 11 12 13 14 15 16 17 18 19 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 10 def initialize(context, request, layer_finder, store=nil) @context = context @request = request @layer_finder = layer_finder @store = store @root_layer = request.root_layer @backtraces = [] @limited = false end |
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
5 6 7 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 5 def context @context end |
#layer_finder ⇒ Object (readonly)
Returns the value of attribute layer_finder.
8 9 10 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 8 def layer_finder @layer_finder end |
#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 |
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
86 87 88 89 90 91 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 86 def attach_backtraces(metric_hash) @backtraces.each do || metric_hash.keys.find { |k| k == }.backtrace = .backtrace end metric_hash end |
#limited? ⇒ Boolean
113 114 115 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 113 def limited? !! @limited end |
#make_meta_options(layer) ⇒ Object
When we make MetricMeta records, we need to determine a few things from layer.
122 123 124 125 126 127 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 122 def (layer) scope_hash = (layer) desc_hash = (layer) scope_hash.merge(desc_hash) end |
#make_meta_options_desc_hash(layer, max_desc_length = 32768) ⇒ Object
148 149 150 151 152 153 154 155 156 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 148 def (layer, max_desc_length=32768) 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
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 129 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
105 106 107 108 109 110 111 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 105 def over_metric_limit?(metric_hash) if metric_hash.size > MAX_METRICS @limited = true else false end end |
#register_hooks(walker) ⇒ 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.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 32 def register_hooks(walker) @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 |
#scope_layer ⇒ Object
21 22 23 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 21 def scope_layer layer_finder.scope 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.
215 216 217 218 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 215 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)
192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 192 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
74 75 76 77 78 79 80 81 82 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 74 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.
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 164 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
52 53 54 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 52 def subscope_name @subscope_layers.first.legacy_metric_name end |
#subscoped?(layer) ⇒ Boolean
48 49 50 |
# File 'lib/scout_apm/layer_converters/converter_base.rb', line 48 def subscoped?(layer) @subscope_layers.first && layer != @subscope_layers.first # Don't scope under ourself. end |