Class: ScoutApm::Layaway
- Inherits:
-
Object
- Object
- ScoutApm::Layaway
- Defined in:
- lib/scout_apm/layaway.rb
Overview
Stores metrics in a file before sending them to the server. Two uses:
-
A centralized store for multiple Agent processes. This way, only 1 checkin is sent to Scout rather than 1 per-process.
-
Bundling up reports from multiple timeslices to make updates more efficent server-side.
Data is stored in a Hash, where the keys are Time.to_i on the minute. The value is a Hash => Hash, :slow_transactions => Array. When depositing data, the new data is either merged with an existing time or placed in a new key.
Instance Attribute Summary collapse
-
#file ⇒ Object
Returns the value of attribute file.
Instance Method Summary collapse
- #deposit_and_deliver ⇒ Object
-
#initialize ⇒ Layaway
constructor
A new instance of Layaway.
- #log_deposited_metrics(new_metrics) ⇒ Object
- #log_deposited_slow_transactions(new_slow_transactions) ⇒ Object
- #log_saved_data(old_data, new_metrics) ⇒ Object
-
#slot ⇒ Object
Data is stored under timestamp-keys (without the second).
-
#validate_data(data) ⇒ Object
Ensures the data we’re sending to the server isn’t stale.
Constructor Details
#initialize ⇒ Layaway
Returns a new instance of Layaway.
9 10 11 |
# File 'lib/scout_apm/layaway.rb', line 9 def initialize @file = ScoutApm::LayawayFile.new end |
Instance Attribute Details
#file ⇒ Object
Returns the value of attribute file.
8 9 10 |
# File 'lib/scout_apm/layaway.rb', line 8 def file @file end |
Instance Method Details
#deposit_and_deliver ⇒ Object
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/scout_apm/layaway.rb', line 13 def deposit_and_deliver new_metrics = ScoutApm::Agent.instance.store.metric_hash log_deposited_metrics(new_metrics) log_deposited_slow_transactions(ScoutApm::Agent.instance.store.slow_transactions) to_deliver = {} file.read_and_write do |old_data| old_data ||= Hash.new # merge data # if (1) there's data in the file and (2) there isn't any data yet for the current minute, this means we've # collected all metrics for the previous slots and we're ready to deliver. # # Example w/2 processes: # # 12:00:34 --- # Process 1: old_data.any? => false, so deposits. # Process 2: old_data_any? => true and old_data[12:00].nil? => false, so deposits. # # 12:01:34 --- # Process 1: old_data.any? => true and old_data[12:01].nil? => true, so delivers metrics. # Process 2: old_data.any? => true and old_data[12:01].nil? => false, so deposits. if old_data.any? and old_data[slot].nil? to_deliver = old_data old_data = Hash.new elsif old_data.any? ScoutApm::Agent.instance.logger.debug "Not yet time to deliver payload for slot [#{Time.at(old_data.keys.sort.last).strftime("%m/%d/%y %H:%M:%S %z")}]" else ScoutApm::Agent.instance.logger.debug "There is no data in the layaway file to deliver." end old_data[slot]=ScoutApm::Agent.instance.store.merge_data_and_clear(old_data[slot] || {:metrics => {}, :slow_transactions => []}) log_saved_data(old_data,new_metrics) old_data end to_deliver.any? ? validate_data(to_deliver) : {} end |
#log_deposited_metrics(new_metrics) ⇒ Object
74 75 76 77 78 79 80 81 82 |
# File 'lib/scout_apm/layaway.rb', line 74 def log_deposited_metrics(new_metrics) controller_count = 0 new_metrics.each do |,stats| if .metric_name =~ /\AController/ controller_count += stats.call_count end end ScoutApm::Agent.instance.logger.debug "Depositing #{controller_count} requests into #{Time.at(slot).strftime("%m/%d/%y %H:%M:%S %z")} slot." end |
#log_deposited_slow_transactions(new_slow_transactions) ⇒ Object
84 85 86 |
# File 'lib/scout_apm/layaway.rb', line 84 def log_deposited_slow_transactions(new_slow_transactions) ScoutApm::Agent.instance.logger.debug "Depositing #{new_slow_transactions.size} slow transactions into #{Time.at(slot).strftime("%m/%d/%y %H:%M:%S %z")} slot." end |
#log_saved_data(old_data, new_metrics) ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/scout_apm/layaway.rb', line 88 def log_saved_data(old_data,new_metrics) ScoutApm::Agent.instance.logger.debug "Saving the following #{old_data.size} time slots locally:" old_data.each do |k,v| controller_count = 0 new_metrics.each do |,stats| if .metric_name =~ /\AController/ controller_count += stats.call_count end end ScoutApm::Agent.instance.logger.debug "#{Time.at(k).strftime("%m/%d/%y %H:%M:%S %z")} => #{controller_count} requests and #{v[:slow_transactions].size} slow transactions" end end |
#slot ⇒ Object
Data is stored under timestamp-keys (without the second).
68 69 70 71 72 |
# File 'lib/scout_apm/layaway.rb', line 68 def slot t = Time.now t -= t.sec t.to_i end |
#validate_data(data) ⇒ Object
Ensures the data we’re sending to the server isn’t stale. This can occur if the agent is collecting data, and app server goes down w/data in the local storage. When it is restarted later data will remain in local storage but it won’t be for the current reporting interval.
If the data is stale, an empty Hash is returned. Otherwise, the data from the most recent slot is returned.
53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/scout_apm/layaway.rb', line 53 def validate_data(data) data = data.to_a.sort now = Time.now if (most_recent = data.first.first) < now.to_i - 2*60 ScoutApm::Agent.instance.logger.debug "Local Storage is stale (#{Time.at(most_recent).strftime("%m/%d/%y %H:%M:%S %z")}). Not sending data." {} else data.first.last end rescue ScoutApm::Agent.instance.logger.debug $!. ScoutApm::Agent.instance.logger.debug $!.backtrace end |