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) ⇒ Object



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

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

  {
    event: name,
    duration_ms: duration_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



116
117
118
119
120
121
122
123
124
125
# File 'lib/dead_bro/cache_subscriber.rb', line 116

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



83
84
85
86
87
88
89
# File 'lib/dead_bro/cache_subscriber.rb', line 83

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



91
92
93
94
95
96
97
# File 'lib/dead_bro/cache_subscriber.rb', line 91

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

.safe_namespace(ns) ⇒ Object



110
111
112
113
114
# File 'lib/dead_bro/cache_subscriber.rb', line 110

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

.safe_store_name(store) ⇒ Object



99
100
101
102
103
104
105
106
107
108
# File 'lib/dead_bro/cache_subscriber.rb', line 99

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)


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

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



38
39
40
# File 'lib/dead_bro/cache_subscriber.rb', line 38

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

.stop_request_trackingObject



42
43
44
45
46
# File 'lib/dead_bro/cache_subscriber.rb', line 42

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
# 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)
      event = build_event(name, data, duration_ms)
      if event && should_continue_tracking?
        Thread.current[THREAD_LOCAL_KEY] << event
      end
    end
  rescue
  end
rescue
  # Never raise from instrumentation install
end