Class: Coverband::Collectors::QueryBurstTracker
- Inherits:
-
AbstractTracker
- Object
- AbstractTracker
- Coverband::Collectors::QueryBurstTracker
- Defined in:
- lib/coverband/collectors/query_burst_tracker.rb
Overview
Lightweight SQL burst tracker for production runtime behavior. Aggregates per controller action / job class and persists compact stats.
Constant Summary collapse
- REPORT_ROUTE =
"query_bursts_tracker"- TITLE =
"Query Bursts"- CONTEXT_STACK_KEY =
:coverband_query_burst_context_stack- IGNORED_SQL_NAMES =
%w[SCHEMA CACHE TRANSACTION].freeze
Instance Attribute Summary
Attributes inherited from AbstractTracker
#ignore_patterns, #logger, #store, #target
Instance Method Summary collapse
- #all_keys ⇒ Object
- #as_json ⇒ Object
-
#initialize(options = {}) ⇒ QueryBurstTracker
constructor
A new instance of QueryBurstTracker.
- #railtie! ⇒ Object
- #save_report ⇒ Object
- #track_key(payload) ⇒ Object
- #unused_keys(_used_keys = nil) ⇒ Object
- #used_key_stats ⇒ Object
- #used_keys ⇒ Object
Methods inherited from AbstractTracker
#clear_key!, #keys_to_record, #logged_keys, #reset_recordings, #route, supported_version?, #title, #tracking_since
Constructor Details
#initialize(options = {}) ⇒ QueryBurstTracker
Returns a new instance of QueryBurstTracker.
17 18 19 20 |
# File 'lib/coverband/collectors/query_burst_tracker.rb', line 17 def initialize( = {}) super @pending_stats = {} end |
Instance Method Details
#all_keys ⇒ Object
79 80 81 |
# File 'lib/coverband/collectors/query_burst_tracker.rb', line 79 def all_keys [] end |
#as_json ⇒ Object
83 84 85 86 87 88 89 90 91 92 |
# File 'lib/coverband/collectors/query_burst_tracker.rb', line 83 def as_json { tracking_since: tracking_since, thresholds: { query_count: query_count_threshold, sql_time_ms: sql_time_threshold_ms }, used_keys: used_key_stats }.to_json end |
#railtie! ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/coverband/collectors/query_burst_tracker.rb', line 22 def railtie! ActiveSupport::Notifications.subscribe("start_processing.action_controller") do |_name, _start, _finish, _id, payload| start_context(:controller, controller_key(payload)) end ActiveSupport::Notifications.subscribe("process_action.action_controller") do |_name, _start, _finish, _id, payload| finish_context(:controller, controller_key(payload)) end ActiveSupport::Notifications.subscribe("perform_start.active_job") do |_name, _start, _finish, _id, payload| start_context(:job, job_key(payload)) end ActiveSupport::Notifications.subscribe("perform.active_job") do |_name, _start, _finish, _id, payload| finish_context(:job, job_key(payload)) end ActiveSupport::Notifications.subscribe("sql.active_record") do |_name, start, finish, _id, payload| next if ignore_sql_event?(payload) record_sql_event(duration_ms(start, finish)) end end |
#save_report ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/coverband/collectors/query_burst_tracker.rb', line 94 def save_report return unless redis_store return if @pending_stats.empty? redis_store.set(tracker_time_key, Time.now.to_i) unless @one_time_timestamp || tracker_time_key_exists? @one_time_timestamp = true existing_stats = redis_store.hgetall(tracker_key) merged = @pending_stats.each_with_object({}) do |(key, pending), h| existing = parse_stats(existing_stats[key]) h[key] = merge_stats(existing, pending).to_json end redis_store.hset(tracker_key, merged) if merged.any? @pending_stats.clear rescue => e logger&.error "Coverband: #{self.class.name} failed to store, error #{e.class.name} info #{e.}" end |
#track_key(payload) ⇒ Object
46 47 48 49 50 51 52 53 |
# File 'lib/coverband/collectors/query_burst_tracker.rb', line 46 def track_key(payload) key = payload[:key] || payload["key"] return unless key queries = (payload[:queries] || payload["queries"] || 0).to_i sql_time_ms = (payload[:sql_time_ms] || payload["sql_time_ms"] || 0.0).to_f record_observation(key, queries, sql_time_ms) end |
#unused_keys(_used_keys = nil) ⇒ Object
75 76 77 |
# File 'lib/coverband/collectors/query_burst_tracker.rb', line 75 def unused_keys(_used_keys = nil) [] end |
#used_key_stats ⇒ Object
65 66 67 68 69 70 71 72 73 |
# File 'lib/coverband/collectors/query_burst_tracker.rb', line 65 def used_key_stats return {} unless redis_store stats_hash = redis_store.hgetall(tracker_key) stats_hash .transform_values { |stats_json| parse_stats(stats_json) } .sort_by { |key, stats| [-stats["threshold_hits"].to_i, -stats["total_sql_time_ms"].to_f, key] } .to_h end |
#used_keys ⇒ Object
55 56 57 58 59 60 61 62 63 |
# File 'lib/coverband/collectors/query_burst_tracker.rb', line 55 def used_keys return {} unless redis_store stats_hash = redis_store.hgetall(tracker_key) stats_hash.each_with_object({}) do |(key, stats_json), used| stats = parse_stats(stats_json) used[key] = stats["last_seen"].to_i end end |