Class: ScoutRailsProxy::Store
- Inherits:
-
Object
- Object
- ScoutRailsProxy::Store
- Defined in:
- lib/scout_rails_proxy/store.rb
Overview
The store encapsolutes the logic that (1) saves instrumented data by Metric name to memory and (2) maintains a stack (just an Array) of instrumented methods that are being called. It’s accessed via ScoutRailsProxy::Agent.instance.store
.
Instance Attribute Summary collapse
-
#metric_hash ⇒ Object
Returns the value of attribute metric_hash.
-
#sample ⇒ Object
Returns the value of attribute sample.
-
#stack ⇒ Object
Returns the value of attribute stack.
-
#transaction_hash ⇒ Object
Returns the value of attribute transaction_hash.
-
#transaction_sample_lock ⇒ Object
readonly
Returns the value of attribute transaction_sample_lock.
Instance Method Summary collapse
-
#aggregate_calls(metrics, parent_meta) ⇒ Object
Takes a metric_hash of calls and generates aggregates for ActiveRecord and View calls.
-
#categories(metrics) ⇒ Object
Returns the top-level category names used in the
metrics
hash. - #ignore_transaction! ⇒ Object
-
#initialize ⇒ Store
constructor
A new instance of Store.
-
#merge_data(old_data) ⇒ Object
Combines old and current data.
-
#merge_data_and_clear(old_data) ⇒ Object
Merges old and current data, clears the current in-memory metric hash, and returns the merged data.
-
#record(metric_name) ⇒ Object
Called at the start of Tracer#instrument: (1) Either finds an existing MetricStats object in the metric_hash or initialize a new one.
-
#reset_transaction! ⇒ Object
Called when the last stack item completes for the current transaction to clear for the next run.
- #stop_recording(sanity_check_item, options = {}) ⇒ Object
-
#store_sample(uri, transaction_hash, parent_meta, parent_stat, options = {}) ⇒ Object
Stores the slowest transaction.
-
#track!(metric_name, call_time, options = {}) ⇒ Object
Finds or creates the metric w/the given name in the metric_hash, and updates the time.
Constructor Details
#initialize ⇒ Store
Returns a new instance of Store.
10 11 12 13 14 15 16 17 18 |
# File 'lib/scout_rails_proxy/store.rb', line 10 def initialize @metric_hash = Hash.new # Stores aggregate metrics for the current transaction. When the transaction is finished, metrics # are merged with the +metric_hash+. @transaction_hash = Hash.new @stack = Array.new # ensure background thread doesn't manipulate transaction sample while the store is. @transaction_sample_lock = Mutex.new end |
Instance Attribute Details
#metric_hash ⇒ Object
Returns the value of attribute metric_hash.
4 5 6 |
# File 'lib/scout_rails_proxy/store.rb', line 4 def metric_hash @metric_hash end |
#sample ⇒ Object
Returns the value of attribute sample.
7 8 9 |
# File 'lib/scout_rails_proxy/store.rb', line 7 def sample @sample end |
#stack ⇒ Object
Returns the value of attribute stack.
6 7 8 |
# File 'lib/scout_rails_proxy/store.rb', line 6 def stack @stack end |
#transaction_hash ⇒ Object
Returns the value of attribute transaction_hash.
5 6 7 |
# File 'lib/scout_rails_proxy/store.rb', line 5 def transaction_hash @transaction_hash end |
#transaction_sample_lock ⇒ Object (readonly)
Returns the value of attribute transaction_sample_lock.
8 9 10 |
# File 'lib/scout_rails_proxy/store.rb', line 8 def transaction_sample_lock @transaction_sample_lock end |
Instance Method Details
#aggregate_calls(metrics, parent_meta) ⇒ Object
Takes a metric_hash of calls and generates aggregates for ActiveRecord and View calls.
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/scout_rails_proxy/store.rb', line 100 def aggregate_calls(metrics,) categories = categories(metrics) aggregates = {} categories.each do |cat| =ScoutRailsProxy::MetricMeta.new("#{cat}/all") .scope = .metric_name agg_stats = ScoutRailsProxy::MetricStats.new metrics.each do |,stats| if .metric_name =~ /\A#{cat}\// agg_stats.combine!(stats) end end # metrics.each aggregates[] = agg_stats unless agg_stats.call_count.zero? end # categories.each aggregates end |
#categories(metrics) ⇒ Object
Returns the top-level category names used in the metrics
hash.
88 89 90 91 92 93 94 95 96 97 |
# File 'lib/scout_rails_proxy/store.rb', line 88 def categories(metrics) cats = Set.new metrics.keys.each do || next if .scope.nil? # ignore controller if match=.metric_name.match(/\A([\w|\d]+)\//) cats << match[1] end end # metrics.each cats end |
#ignore_transaction! ⇒ Object
29 30 31 |
# File 'lib/scout_rails_proxy/store.rb', line 29 def ignore_transaction! Thread::current[:ignore_transaction] = true end |
#merge_data(old_data) ⇒ Object
Combines old and current data
141 142 143 144 145 146 147 148 149 150 |
# File 'lib/scout_rails_proxy/store.rb', line 141 def merge_data(old_data) old_data.each do |,old_stats| if stats = metric_hash[] metric_hash[] = stats.combine!(old_stats) else metric_hash[] = old_stats end end metric_hash end |
#merge_data_and_clear(old_data) ⇒ Object
Merges old and current data, clears the current in-memory metric hash, and returns the merged data
154 155 156 157 158 |
# File 'lib/scout_rails_proxy/store.rb', line 154 def merge_data_and_clear(old_data) merged = merge_data(old_data) self.metric_hash = {} merged end |
#record(metric_name) ⇒ Object
Called at the start of Tracer#instrument: (1) Either finds an existing MetricStats object in the metric_hash or initialize a new one. An existing MetricStats object is present if this metric_name
has already been instrumented. (2) Adds a StackItem to the stack. This StackItem is returned and later used to validate the item popped off the stack when an instrumented code block completes.
38 39 40 41 42 |
# File 'lib/scout_rails_proxy/store.rb', line 38 def record(metric_name) item = ScoutRailsProxy::StackItem.new(metric_name) stack << item item end |
#reset_transaction! ⇒ Object
Called when the last stack item completes for the current transaction to clear for the next run.
22 23 24 25 26 27 |
# File 'lib/scout_rails_proxy/store.rb', line 22 def reset_transaction! Thread::current[:ignore_transaction] = nil Thread::current[:scout_scope_name] = nil @transaction_hash = Hash.new @stack = Array.new end |
#stop_recording(sanity_check_item, options = {}) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/scout_rails_proxy/store.rb', line 44 def stop_recording(sanity_check_item, ={}) item = stack.pop stack_empty = stack.empty? # if ignoring the transaction, the item is popped but nothing happens. if Thread::current[:ignore_transaction] return end # unbalanced stack check - unreproducable cases have seen this occur. when it does, sets a Thread variable # so we ignore further recordings. +Store#reset_transaction!+ resets this. if item != sanity_check_item ScoutRailsProxy::Agent.instance.logger.warn "Scope [#{Thread::current[:scout_scope_name]}] Popped off stack: #{item.inspect} Expected: #{sanity_check_item.inspect}. Aborting." ignore_transaction! return end duration = Time.now - item.start_time if last=stack.last last.children_time += duration end = ScoutRailsProxy::MetricMeta.new(item.metric_name, :desc => [:desc]) .scope = nil if stack_empty # add backtrace for slow calls ... how is exclusive time handled? if duration > 0.5 and !stack_empty .extra = {:backtrace => caller.find_all { |c| c =~ /\/app\//}} end stat = transaction_hash[] || ScoutRailsProxy::MetricStats.new(!stack_empty) stat.update!(duration,duration-item.children_time) transaction_hash[] = stat # Uses controllers as the entry point for a transaction. Otherwise, stats are ignored. if stack_empty and .metric_name.match(/\AController\//) aggs=aggregate_calls(transaction_hash.dup,) store_sample([:uri],transaction_hash.dup.merge(aggs),,stat) # deep duplicate duplicate = aggs.dup duplicate.each_pair do |k,v| duplicate[k.dup] = v.dup end merge_data(duplicate.merge({.dup => stat.dup})) # aggregrates + controller end end |
#store_sample(uri, transaction_hash, parent_meta, parent_stat, options = {}) ⇒ Object
Stores the slowest transaction. This will be sent to the server.
118 119 120 121 122 123 124 |
# File 'lib/scout_rails_proxy/store.rb', line 118 def store_sample(uri,transaction_hash,,parent_stat, = {}) @transaction_sample_lock.synchronize do if parent_stat.total_call_time >= 2 and (@sample.nil? or (@sample and parent_stat.total_call_time > @sample.total_call_time)) @sample = ScoutRailsProxy::TransactionSample.new(uri,.metric_name,parent_stat.total_call_time,transaction_hash.dup) end end end |
#track!(metric_name, call_time, options = {}) ⇒ Object
Finds or creates the metric w/the given name in the metric_hash, and updates the time. Primarily used to record sampled metrics. For instrumented methods, #record and #stop_recording are used.
Options: :scope => If provided, overrides the default scope. :exclusive_time => Sets the exclusive time for the method. If not provided, uses call_time
.
132 133 134 135 136 137 138 |
# File 'lib/scout_rails_proxy/store.rb', line 132 def track!(metric_name,call_time, = {}) = ScoutRailsProxy::MetricMeta.new(metric_name) .scope = [:scope] if .has_key?(:scope) stat = metric_hash[] || ScoutRailsProxy::MetricStats.new stat.update!(call_time,[:exclusive_time] || call_time) metric_hash[] = stat end |