Class: DeadBro::CacheSubscriber

Inherits:
Object
  • Object
show all
Defined in:
lib/dead_bro/cache_subscriber.rb

Constant Summary collapse

THREAD_LOCAL_KEY =
:dead_bro_cache_events
MAX_TRACKED_EVENTS =
1000
EVENTS =
[
  "cache_read.active_support",
  "cache_write.active_support",
  "cache_delete.active_support",
  "cache_exist?.active_support",
  "cache_fetch_hit.active_support",
  "cache_generate.active_support",
  "cache_read_multi.active_support",
  "cache_write_multi.active_support"
].freeze

Class Method Summary collapse

Class Method Details

.build_event(name, data, duration_ms, start_offset_ms = nil) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/dead_bro/cache_subscriber.rb', line 68

def self.build_event(name, data, duration_ms, start_offset_ms = nil)
  return nil unless data.is_a?(Hash)

  {
    event: name,
    duration_ms: duration_ms,
    start_offset_ms: start_offset_ms,
    key: safe_key(data[:key]),
    keys_count: safe_keys_count(data[:keys]),
    hit: infer_hit(name, data),
    store: safe_store_name(data[:store]),
    namespace: safe_namespace(data[:namespace]),
    at: Time.now.utc.to_i
  }
rescue
  nil
end

.infer_hit(name, data) ⇒ Object



119
120
121
122
123
124
125
126
127
128
# File 'lib/dead_bro/cache_subscriber.rb', line 119

def self.infer_hit(name, data)
  case name
  when "cache_fetch_hit.active_support"
    true
  when "cache_read.active_support"
    !!data[:hit]
  end
rescue
  nil
end

.safe_key(key) ⇒ Object



86
87
88
89
90
91
92
# File 'lib/dead_bro/cache_subscriber.rb', line 86

def self.safe_key(key)
  return nil if key.nil?
  s = key.to_s
  (s.length > 200) ? s[0, 200] + "" : s
rescue
  nil
end

.safe_keys_count(keys) ⇒ Object



94
95
96
97
98
99
100
# File 'lib/dead_bro/cache_subscriber.rb', line 94

def self.safe_keys_count(keys)
  if keys.respond_to?(:size)
    keys.size
  end
rescue
  nil
end

.safe_namespace(ns) ⇒ Object



113
114
115
116
117
# File 'lib/dead_bro/cache_subscriber.rb', line 113

def self.safe_namespace(ns)
  ns.to_s[0, 100]
rescue
  nil
end

.safe_store_name(store) ⇒ Object



102
103
104
105
106
107
108
109
110
111
# File 'lib/dead_bro/cache_subscriber.rb', line 102

def self.safe_store_name(store)
  return nil unless store
  if store.respond_to?(:name)
    store.name
  else
    store.class.name
  end
rescue
  nil
end

.should_continue_tracking?Boolean

Check if we should continue tracking based on count and time limits

Returns:

  • (Boolean)


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/dead_bro/cache_subscriber.rb', line 51

def self.should_continue_tracking?
  events = Thread.current[THREAD_LOCAL_KEY]
  return false unless events

  # Check count limit
  return false if events.length >= MAX_TRACKED_EVENTS

  # Check time limit
  start_time = Thread.current[DeadBro::TRACKING_START_TIME_KEY]
  if start_time
    elapsed_seconds = Time.now - start_time
    return false if elapsed_seconds >= DeadBro::MAX_TRACKING_DURATION_SECONDS
  end

  true
end

.start_request_trackingObject



40
41
42
# File 'lib/dead_bro/cache_subscriber.rb', line 40

def self.start_request_tracking
  Thread.current[THREAD_LOCAL_KEY] = []
end

.stop_request_trackingObject



44
45
46
47
48
# File 'lib/dead_bro/cache_subscriber.rb', line 44

def self.stop_request_tracking
  events = Thread.current[THREAD_LOCAL_KEY]
  Thread.current[THREAD_LOCAL_KEY] = nil
  events || []
end

.subscribe!Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/dead_bro/cache_subscriber.rb', line 21

def self.subscribe!
  EVENTS.each do |event_name|
    ActiveSupport::Notifications.subscribe(event_name) do |name, started, finished, _unique_id, data|
      next unless Thread.current[THREAD_LOCAL_KEY]

      duration_ms = ((finished - started) * 1000.0).round(2)
      tracking_start = Thread.current[DeadBro::TRACKING_START_TIME_KEY]
      start_offset_ms = tracking_start ? ((started - tracking_start) * 1000.0).round(2) : nil
      event = build_event(name, data, duration_ms, start_offset_ms)
      if event && should_continue_tracking?
        Thread.current[THREAD_LOCAL_KEY] << event
      end
    end
  rescue
  end
rescue
  # Never raise from instrumentation install
end