brainzlab 0.1.35 → 0.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/lib/brainzlab/beacon/client.rb +6 -4
  4. data/lib/brainzlab/configuration.rb +272 -301
  5. data/lib/brainzlab/cortex/client.rb +6 -4
  6. data/lib/brainzlab/debug.rb +6 -6
  7. data/lib/brainzlab/dendrite/client.rb +6 -4
  8. data/lib/brainzlab/development/logger.rb +2 -2
  9. data/lib/brainzlab/development/store.rb +4 -2
  10. data/lib/brainzlab/devtools/middleware/error_page.rb +1 -1
  11. data/lib/brainzlab/errors.rb +12 -5
  12. data/lib/brainzlab/flux/client.rb +1 -1
  13. data/lib/brainzlab/instrumentation/action_cable.rb +4 -4
  14. data/lib/brainzlab/instrumentation/action_controller.rb +12 -12
  15. data/lib/brainzlab/instrumentation/action_dispatch.rb +1 -1
  16. data/lib/brainzlab/instrumentation/action_mailbox.rb +13 -7
  17. data/lib/brainzlab/instrumentation/action_view.rb +33 -29
  18. data/lib/brainzlab/instrumentation/active_job.rb +10 -6
  19. data/lib/brainzlab/instrumentation/active_record.rb +24 -21
  20. data/lib/brainzlab/instrumentation/active_storage.rb +4 -4
  21. data/lib/brainzlab/instrumentation/active_support_cache.rb +8 -6
  22. data/lib/brainzlab/instrumentation/grape.rb +1 -3
  23. data/lib/brainzlab/instrumentation/rails_deprecation.rb +1 -1
  24. data/lib/brainzlab/instrumentation/railties.rb +2 -2
  25. data/lib/brainzlab/nerve/client.rb +6 -4
  26. data/lib/brainzlab/pulse/client.rb +1 -1
  27. data/lib/brainzlab/pulse.rb +1 -5
  28. data/lib/brainzlab/rails/railtie.rb +3 -1
  29. data/lib/brainzlab/reflex/client.rb +1 -1
  30. data/lib/brainzlab/sentinel/client.rb +6 -4
  31. data/lib/brainzlab/synapse/client.rb +6 -4
  32. data/lib/brainzlab/testing/event_store.rb +3 -3
  33. data/lib/brainzlab/testing/matchers.rb +4 -4
  34. data/lib/brainzlab/testing.rb +3 -5
  35. data/lib/brainzlab/vault/client.rb +6 -4
  36. data/lib/brainzlab/version.rb +1 -1
  37. data/lib/brainzlab/vision/client.rb +3 -3
  38. data/lib/fluyenta-ruby.rb +1 -1
  39. metadata +1 -1
@@ -184,9 +184,9 @@ module BrainzLab
184
184
  BrainzLab.debug_log("[Cortex::Client] #{operation} failed: #{structured_error.message}")
185
185
 
186
186
  # Call on_error callback if configured
187
- return unless @config.on_error
188
-
189
- @config.on_error.call(structured_error, { service: 'Cortex', operation: operation })
187
+ if @config.on_error
188
+ @config.on_error.call(structured_error, { service: 'Cortex', operation: operation })
189
+ end
190
190
  end
191
191
 
192
192
  def handle_response_error(response, operation)
@@ -196,7 +196,9 @@ module BrainzLab
196
196
  BrainzLab.debug_log("[Cortex::Client] #{operation} failed: #{structured_error.message}")
197
197
 
198
198
  # Call on_error callback if configured
199
- @config.on_error&.call(structured_error, { service: 'Cortex', operation: operation })
199
+ if @config.on_error
200
+ @config.on_error.call(structured_error, { service: 'Cortex', operation: operation })
201
+ end
200
202
 
201
203
  structured_error
202
204
  end
@@ -172,7 +172,7 @@ module BrainzLab
172
172
 
173
173
  def format_message(message, level:, **data)
174
174
  timestamp = format_timestamp
175
- prefix = colorize('[BrainzLab]', :bold, :blue)
175
+ prefix = colorize("[BrainzLab]", :bold, :blue)
176
176
  level_badge = format_level(level)
177
177
  data_str = data.empty? ? '' : " #{format_data(data)}"
178
178
 
@@ -181,8 +181,8 @@ module BrainzLab
181
181
 
182
182
  def format_arrow_message(direction, service, message, level: :info)
183
183
  timestamp = format_timestamp
184
- prefix = colorize('[BrainzLab]', :bold, :blue)
185
- arrow = direction == :out ? colorize('->', :cyan) : colorize('<-', :green)
184
+ prefix = colorize("[BrainzLab]", :bold, :blue)
185
+ arrow = direction == :out ? colorize("->", :cyan) : colorize("<-", :green)
186
186
  service_name = colorize(service.to_s.capitalize, :magenta)
187
187
 
188
188
  "#{prefix} #{timestamp} #{arrow} #{service_name} #{message}"
@@ -242,7 +242,7 @@ module BrainzLab
242
242
  other_keys = data.keys.reject { |k| %i[message timestamp level].include?(k.to_sym) }
243
243
  if other_keys.any?
244
244
  key_summary = other_keys.take(3).map { |k| "#{k}: #{format_value(data[k])}" }.join(', ')
245
- key_summary += ', ...' if other_keys.length > 3
245
+ key_summary += ", ..." if other_keys.length > 3
246
246
  summary_parts << "(#{key_summary})"
247
247
  end
248
248
 
@@ -253,7 +253,7 @@ module BrainzLab
253
253
  return '' unless str
254
254
 
255
255
  str = str.to_s
256
- str.length > length ? "#{str[0..(length - 4)]}..." : str
256
+ str.length > length ? "#{str[0..length - 4]}..." : str
257
257
  end
258
258
 
259
259
  def status_message(status)
@@ -293,7 +293,7 @@ module BrainzLab
293
293
  else config.logger.info(strip_colors(output))
294
294
  end
295
295
  else
296
- warn output
296
+ $stderr.puts output
297
297
  end
298
298
  end
299
299
 
@@ -227,9 +227,9 @@ module BrainzLab
227
227
  BrainzLab.debug_log("[Dendrite::Client] #{operation} failed: #{structured_error.message}")
228
228
 
229
229
  # Call on_error callback if configured
230
- return unless @config.on_error
231
-
232
- @config.on_error.call(structured_error, { service: 'Dendrite', operation: operation })
230
+ if @config.on_error
231
+ @config.on_error.call(structured_error, { service: 'Dendrite', operation: operation })
232
+ end
233
233
  end
234
234
 
235
235
  def handle_response_error(response, operation)
@@ -239,7 +239,9 @@ module BrainzLab
239
239
  BrainzLab.debug_log("[Dendrite::Client] #{operation} failed: #{structured_error.message}")
240
240
 
241
241
  # Call on_error callback if configured
242
- @config.on_error&.call(structured_error, { service: 'Dendrite', operation: operation })
242
+ if @config.on_error
243
+ @config.on_error.call(structured_error, { service: 'Dendrite', operation: operation })
244
+ end
243
245
 
244
246
  structured_error
245
247
  end
@@ -82,8 +82,8 @@ module BrainzLab
82
82
  when 'log'
83
83
  level = payload[:level]&.to_sym
84
84
  level_color = COLORS[level] || COLORS[:info]
85
- "#{colorize("[#{level&.upcase}]", level_color)} #{payload[:message]}"
86
-
85
+ msg = "#{colorize("[#{level&.upcase}]", level_color)} #{payload[:message]}"
86
+ msg
87
87
  when 'error'
88
88
  "#{payload[:error_class]}: #{payload[:message]}"
89
89
  when 'trace'
@@ -89,8 +89,10 @@ module BrainzLab
89
89
  private
90
90
 
91
91
  def db
92
- @db ||= SQLite3::Database.new(@db_path).tap do |database|
93
- database.results_as_hash = false
92
+ @db ||= begin
93
+ SQLite3::Database.new(@db_path).tap do |database|
94
+ database.results_as_hash = false
95
+ end
94
96
  end
95
97
  end
96
98
 
@@ -93,7 +93,7 @@ module BrainzLab
93
93
  .gsub('&nbsp;', ' ')
94
94
  end
95
95
 
96
- def collect_debug_data_from_info(env, info, _status = 500)
96
+ def collect_debug_data_from_info(env, info, status = 500)
97
97
  context = defined?(BrainzLab::Context) ? BrainzLab::Context.current : nil
98
98
  collector_data = Data::Collector.get_request_data
99
99
 
@@ -53,6 +53,13 @@ module BrainzLab
53
53
  super(message)
54
54
  end
55
55
 
56
+ # Format the error as a detailed string with hints and documentation links.
57
+ #
58
+ # @return [String] Formatted error message
59
+ def to_s
60
+ super
61
+ end
62
+
56
63
  # Return a detailed formatted version of the error with hints and documentation links.
57
64
  # Use this method when you want the full structured output.
58
65
  #
@@ -63,12 +70,12 @@ module BrainzLab
63
70
 
64
71
  parts = ["#{self.class.name}: #{base_msg}"]
65
72
 
66
- parts << '' << "Hint: #{hint}" if hint
73
+ parts << "" << "Hint: #{hint}" if hint
67
74
  parts << "Docs: #{docs_url}" if docs_url
68
75
  parts << "Code: #{code}" if code
69
76
 
70
77
  if context && !context.empty?
71
- parts << '' << 'Context:'
78
+ parts << "" << "Context:"
72
79
  context.each do |key, value|
73
80
  parts << " #{key}: #{value}"
74
81
  end
@@ -117,7 +124,7 @@ module BrainzLab
117
124
  def initialize(message = nil, hint: nil, docs_url: nil, code: nil, context: nil)
118
125
  docs_url ||= "#{DOCS_BASE_URL}/sdk/ruby/configuration"
119
126
  code ||= 'configuration_error'
120
- super
127
+ super(message, hint: hint, docs_url: docs_url, code: code, context: context)
121
128
  end
122
129
  end
123
130
 
@@ -134,7 +141,7 @@ module BrainzLab
134
141
  def initialize(message = nil, hint: nil, docs_url: nil, code: nil, context: nil)
135
142
  docs_url ||= "#{DOCS_BASE_URL}/sdk/ruby/authentication"
136
143
  code ||= 'authentication_error'
137
- super
144
+ super(message, hint: hint, docs_url: docs_url, code: code, context: context)
138
145
  end
139
146
  end
140
147
 
@@ -151,7 +158,7 @@ module BrainzLab
151
158
  def initialize(message = nil, hint: nil, docs_url: nil, code: nil, context: nil)
152
159
  docs_url ||= "#{DOCS_BASE_URL}/sdk/ruby/troubleshooting#connection-issues"
153
160
  code ||= 'connection_error'
154
- super
161
+ super(message, hint: hint, docs_url: docs_url, code: code, context: context)
155
162
  end
156
163
  end
157
164
 
@@ -61,7 +61,7 @@ module BrainzLab
61
61
  end
62
62
 
63
63
  def api_key
64
- @config.flux_ingest_key || @config.flux_api_key
64
+ @config.flux_auth_key
65
65
  end
66
66
  end
67
67
  end
@@ -91,7 +91,7 @@ module BrainzLab
91
91
  duration = event.duration.round(2)
92
92
 
93
93
  channel_class = payload[:channel_class]
94
- payload[:data]
94
+ data = payload[:data]
95
95
  via = payload[:via]
96
96
 
97
97
  # Record breadcrumb
@@ -187,7 +187,7 @@ module BrainzLab
187
187
  # Log rejection to Recall
188
188
  if BrainzLab.configuration.recall_effectively_enabled?
189
189
  BrainzLab::Recall.warn(
190
- 'ActionCable subscription rejected',
190
+ "ActionCable subscription rejected",
191
191
  channel: channel_class
192
192
  )
193
193
  end
@@ -210,7 +210,7 @@ module BrainzLab
210
210
  duration = event.duration.round(2)
211
211
 
212
212
  broadcasting = payload[:broadcasting]
213
- payload[:message]
213
+ message = payload[:message]
214
214
  coder = payload[:coder]
215
215
 
216
216
  # Record breadcrumb
@@ -236,7 +236,7 @@ module BrainzLab
236
236
  # ============================================
237
237
  # Span Recording Helpers
238
238
  # ============================================
239
- def record_action_span(event, channel_class, action, duration, _data)
239
+ def record_action_span(event, channel_class, action, duration, data)
240
240
  return unless BrainzLab.configuration.pulse_effectively_enabled?
241
241
 
242
242
  tracer = BrainzLab::Pulse.tracer
@@ -58,7 +58,7 @@ module BrainzLab
58
58
  method = payload[:method]
59
59
  path = payload[:path]
60
60
  format = payload[:format]
61
- payload[:params]
61
+ params = payload[:params]
62
62
 
63
63
  # Skip health check endpoints
64
64
  return if excluded_path?(path)
@@ -99,12 +99,12 @@ module BrainzLab
99
99
  payload = event.payload
100
100
  duration = event.duration.round(2)
101
101
 
102
- payload[:controller]
103
- payload[:action]
102
+ controller = payload[:controller]
103
+ action = payload[:action]
104
104
  status = payload[:status]
105
- payload[:method]
105
+ method = payload[:method]
106
106
  path = payload[:path]
107
- payload[:format]
107
+ format = payload[:format]
108
108
 
109
109
  # Skip health check endpoints
110
110
  return if excluded_path?(path)
@@ -157,7 +157,7 @@ module BrainzLab
157
157
  )
158
158
  end
159
159
 
160
- def record_request_trace(event, payload, _duration)
160
+ def record_request_trace(event, payload, duration)
161
161
  # Only record if Pulse is enabled and no trace is already active
162
162
  # (middleware should handle this, but this is a fallback)
163
163
  return unless BrainzLab.configuration.pulse_effectively_enabled?
@@ -265,7 +265,7 @@ module BrainzLab
265
265
  # Also log to Recall - halted callbacks can indicate auth issues
266
266
  if BrainzLab.configuration.recall_effectively_enabled?
267
267
  BrainzLab::Recall.info(
268
- 'Request halted by before_action filter',
268
+ "Request halted by before_action filter",
269
269
  filter: filter.to_s
270
270
  )
271
271
  end
@@ -307,7 +307,7 @@ module BrainzLab
307
307
  # Log to Recall - this is a security-relevant event
308
308
  if BrainzLab.configuration.recall_effectively_enabled?
309
309
  BrainzLab::Recall.warn(
310
- 'Unpermitted parameters rejected',
310
+ "Unpermitted parameters rejected",
311
311
  unpermitted_keys: keys,
312
312
  controller: context[:controller],
313
313
  action: context[:action]
@@ -362,7 +362,7 @@ module BrainzLab
362
362
  filename = payload[:filename]
363
363
 
364
364
  BrainzLab::Reflex.add_breadcrumb(
365
- "Sending data#{": #{filename}" if filename}",
365
+ "Sending data#{filename ? ": #{filename}" : ''}",
366
366
  category: 'http.data',
367
367
  level: :info,
368
368
  data: {
@@ -391,7 +391,7 @@ module BrainzLab
391
391
  type = payload[:type]
392
392
 
393
393
  BrainzLab::Reflex.add_breadcrumb(
394
- "Streaming#{": #{filename}" if filename}",
394
+ "Streaming#{filename ? ": #{filename}" : ''}",
395
395
  category: 'http.stream',
396
396
  level: :info,
397
397
  data: {
@@ -597,7 +597,7 @@ module BrainzLab
597
597
  # Add breadcrumb
598
598
  if BrainzLab.configuration.reflex_effectively_enabled?
599
599
  BrainzLab::Reflex.add_breadcrumb(
600
- 'Rate limit triggered',
600
+ "Rate limit triggered",
601
601
  category: 'security.rate_limit',
602
602
  level: :warning,
603
603
  data: {
@@ -609,7 +609,7 @@ module BrainzLab
609
609
  # Log to Recall - rate limiting is security-relevant
610
610
  if BrainzLab.configuration.recall_effectively_enabled?
611
611
  BrainzLab::Recall.warn(
612
- 'Rate limit triggered',
612
+ "Rate limit triggered",
613
613
  path: payload[:request]&.path,
614
614
  ip: payload[:request]&.remote_ip
615
615
  )
@@ -100,7 +100,7 @@ module BrainzLab
100
100
 
101
101
  status = payload[:status]
102
102
  location = payload[:location]
103
- payload[:request]
103
+ request = payload[:request]
104
104
 
105
105
  # Record breadcrumb
106
106
  if BrainzLab.configuration.reflex_effectively_enabled?
@@ -4,8 +4,8 @@ module BrainzLab
4
4
  module Instrumentation
5
5
  class ActionMailbox
6
6
  # Thresholds for slow processing (in milliseconds)
7
- SLOW_PROCESSING_THRESHOLD = 1000 # 1 second
8
- VERY_SLOW_PROCESSING_THRESHOLD = 5000 # 5 seconds
7
+ SLOW_PROCESSING_THRESHOLD = 1000 # 1 second
8
+ VERY_SLOW_PROCESSING_THRESHOLD = 5000 # 5 seconds
9
9
 
10
10
  class << self
11
11
  def install!
@@ -102,7 +102,7 @@ module BrainzLab
102
102
  started_at: event.time,
103
103
  ended_at: event.end,
104
104
  duration_ms: duration,
105
- error: %w[bounced failed].include?(status),
105
+ error: status == 'bounced' || status == 'failed',
106
106
  data: {
107
107
  'mailbox.class' => mailbox_class,
108
108
  'mailbox.email_id' => email_id,
@@ -123,7 +123,7 @@ module BrainzLab
123
123
  return unless BrainzLab.configuration.recall_effectively_enabled?
124
124
 
125
125
  # Determine log level based on status and duration
126
- if %w[bounced failed].include?(status)
126
+ if status == 'bounced' || status == 'failed'
127
127
  BrainzLab::Recall.error(
128
128
  "Mailbox processing failed: #{mailbox_class}",
129
129
  mailbox: mailbox_class,
@@ -154,7 +154,9 @@ module BrainzLab
154
154
  def extract_from(inbound_email)
155
155
  return nil unless inbound_email
156
156
 
157
- Array(inbound_email.mail.from).first if inbound_email.respond_to?(:mail) && inbound_email.mail.respond_to?(:from)
157
+ if inbound_email.respond_to?(:mail) && inbound_email.mail.respond_to?(:from)
158
+ Array(inbound_email.mail.from).first
159
+ end
158
160
  rescue StandardError
159
161
  nil
160
162
  end
@@ -162,7 +164,9 @@ module BrainzLab
162
164
  def extract_to(inbound_email)
163
165
  return nil unless inbound_email
164
166
 
165
- Array(inbound_email.mail.to).first if inbound_email.respond_to?(:mail) && inbound_email.mail.respond_to?(:to)
167
+ if inbound_email.respond_to?(:mail) && inbound_email.mail.respond_to?(:to)
168
+ Array(inbound_email.mail.to).first
169
+ end
166
170
  rescue StandardError
167
171
  nil
168
172
  end
@@ -170,7 +174,9 @@ module BrainzLab
170
174
  def extract_subject(inbound_email)
171
175
  return nil unless inbound_email
172
176
 
173
- inbound_email.mail.subject if inbound_email.respond_to?(:mail) && inbound_email.mail.respond_to?(:subject)
177
+ if inbound_email.respond_to?(:mail) && inbound_email.mail.respond_to?(:subject)
178
+ inbound_email.mail.subject
179
+ end
174
180
  rescue StandardError
175
181
  nil
176
182
  end
@@ -115,13 +115,17 @@ module BrainzLab
115
115
  template_name = extract_template_name(identifier)
116
116
 
117
117
  # Add breadcrumb for significant collections
118
- record_collection_breadcrumb(template_name, duration, count, cache_hits) if count >= COLLECTION_TRACKING_THRESHOLD || duration >= BrainzLab.configuration.slow_render_threshold
118
+ if count >= COLLECTION_TRACKING_THRESHOLD || duration >= BrainzLab.configuration.slow_render_threshold
119
+ record_collection_breadcrumb(template_name, duration, count, cache_hits)
120
+ end
119
121
 
120
122
  # Add span to Pulse
121
123
  record_collection_span(event, template_name, duration, count, cache_hits)
122
124
 
123
125
  # Log slow collection renders to Recall
124
- log_slow_collection_render(template_name, duration, count, cache_hits) if duration >= BrainzLab.configuration.slow_render_threshold
126
+ if duration >= BrainzLab.configuration.slow_render_threshold
127
+ log_slow_collection_render(template_name, duration, count, cache_hits)
128
+ end
125
129
 
126
130
  # Track potential N+1 view pattern (many partials rendered)
127
131
  track_collection_performance(template_name, count, duration) if count >= 50
@@ -240,7 +244,7 @@ module BrainzLab
240
244
  else :error
241
245
  end
242
246
 
243
- cache_info = cache_hits.positive? ? " (#{cache_hits}/#{count} cached)" : ''
247
+ cache_info = cache_hits > 0 ? " (#{cache_hits}/#{count} cached)" : ""
244
248
 
245
249
  BrainzLab::Reflex.add_breadcrumb(
246
250
  "Render collection: #{template_name} x#{count}#{cache_info} (#{duration}ms)",
@@ -251,7 +255,7 @@ module BrainzLab
251
255
  count: count,
252
256
  cache_hits: cache_hits,
253
257
  duration_ms: duration,
254
- avg_per_item_ms: count.positive? ? (duration / count).round(2) : nil
258
+ avg_per_item_ms: count > 0 ? (duration / count).round(2) : nil
255
259
  }.compact
256
260
  )
257
261
  end
@@ -275,7 +279,7 @@ module BrainzLab
275
279
  'view.template' => template_name,
276
280
  'view.count' => count,
277
281
  'view.cache_hits' => cache_hits,
278
- 'view.avg_per_item_ms' => count.positive? ? (duration / count).round(2) : nil
282
+ 'view.avg_per_item_ms' => count > 0 ? (duration / count).round(2) : nil
279
283
  }.compact
280
284
  }
281
285
 
@@ -313,41 +317,41 @@ module BrainzLab
313
317
  count: count,
314
318
  cache_hits: cache_hits,
315
319
  duration_ms: duration,
316
- avg_per_item_ms: count.positive? ? (duration / count).round(2) : nil,
320
+ avg_per_item_ms: count > 0 ? (duration / count).round(2) : nil,
317
321
  threshold_exceeded: duration >= BrainzLab.configuration.very_slow_render_threshold ? 'critical' : 'warning'
318
322
  )
319
323
  end
320
324
 
321
325
  def track_collection_performance(template_name, count, duration)
322
- avg_per_item = count.positive? ? (duration / count).round(2) : 0
326
+ avg_per_item = count > 0 ? (duration / count).round(2) : 0
323
327
 
324
328
  # If average time per item is high, this might indicate N+1 in the partial
325
- return unless avg_per_item > 5 # More than 5ms per item is suspicious
326
-
327
- if BrainzLab.configuration.reflex_effectively_enabled?
328
- BrainzLab::Reflex.add_breadcrumb(
329
- "Slow collection items: #{template_name} (#{avg_per_item}ms/item)",
330
- category: 'view.performance',
331
- level: :warning,
332
- data: {
329
+ if avg_per_item > 5 # More than 5ms per item is suspicious
330
+ if BrainzLab.configuration.reflex_effectively_enabled?
331
+ BrainzLab::Reflex.add_breadcrumb(
332
+ "Slow collection items: #{template_name} (#{avg_per_item}ms/item)",
333
+ category: 'view.performance',
334
+ level: :warning,
335
+ data: {
336
+ template: template_name,
337
+ count: count,
338
+ duration_ms: duration,
339
+ avg_per_item_ms: avg_per_item,
340
+ suggestion: 'Consider caching, eager loading, or optimizing the partial'
341
+ }
342
+ )
343
+ end
344
+
345
+ if BrainzLab.configuration.recall_effectively_enabled?
346
+ BrainzLab::Recall.warn(
347
+ "Collection partial may have N+1 or performance issue",
333
348
  template: template_name,
334
349
  count: count,
335
350
  duration_ms: duration,
336
- avg_per_item_ms: avg_per_item,
337
- suggestion: 'Consider caching, eager loading, or optimizing the partial'
338
- }
339
- )
351
+ avg_per_item_ms: avg_per_item
352
+ )
353
+ end
340
354
  end
341
-
342
- return unless BrainzLab.configuration.recall_effectively_enabled?
343
-
344
- BrainzLab::Recall.warn(
345
- 'Collection partial may have N+1 or performance issue',
346
- template: template_name,
347
- count: count,
348
- duration_ms: duration,
349
- avg_per_item_ms: avg_per_item
350
- )
351
355
  end
352
356
 
353
357
  # ============================================
@@ -4,8 +4,8 @@ module BrainzLab
4
4
  module Instrumentation
5
5
  class ActiveJob
6
6
  # Thresholds for slow job detection (in milliseconds)
7
- SLOW_JOB_THRESHOLD = 5000 # 5 seconds
8
- VERY_SLOW_JOB_THRESHOLD = 30_000 # 30 seconds
7
+ SLOW_JOB_THRESHOLD = 5000 # 5 seconds
8
+ VERY_SLOW_JOB_THRESHOLD = 30_000 # 30 seconds
9
9
 
10
10
  class << self
11
11
  def install!
@@ -95,7 +95,7 @@ module BrainzLab
95
95
  scheduled_in = scheduled_at ? ((scheduled_at - Time.now) / 60).round(1) : nil
96
96
 
97
97
  BrainzLab::Reflex.add_breadcrumb(
98
- "Job scheduled: #{job_class}#{" (in #{scheduled_in}min)" if scheduled_in}",
98
+ "Job scheduled: #{job_class}#{scheduled_in ? " (in #{scheduled_in}min)" : ''}",
99
99
  category: 'job.schedule',
100
100
  level: :info,
101
101
  data: {
@@ -242,12 +242,14 @@ module BrainzLab
242
242
 
243
243
  # Calculate queue wait time if enqueued_at is available
244
244
  queue_wait_ms = nil
245
- queue_wait_ms = ((event.time - job.enqueued_at) * 1000).round(2) if job.enqueued_at
245
+ if job.enqueued_at
246
+ queue_wait_ms = ((event.time - job.enqueued_at) * 1000).round(2)
247
+ end
246
248
 
247
249
  # Record breadcrumb
248
250
  if BrainzLab.configuration.reflex_effectively_enabled?
249
251
  BrainzLab::Reflex.add_breadcrumb(
250
- "Job started: #{job_class}#{" (attempt #{executions})" if executions > 1}",
252
+ "Job started: #{job_class}#{executions > 1 ? " (attempt #{executions})" : ''}",
251
253
  category: 'job.start',
252
254
  level: :info,
253
255
  data: {
@@ -291,7 +293,9 @@ module BrainzLab
291
293
  job_starts = Thread.current[:brainzlab_job_starts] || {}
292
294
  start_info = job_starts.delete(job_id) || {}
293
295
  queue_wait_ms = nil
294
- queue_wait_ms = ((start_info[:started_at] - start_info[:enqueued_at]) * 1000).round(2) if start_info[:enqueued_at]
296
+ if start_info[:enqueued_at]
297
+ queue_wait_ms = ((start_info[:started_at] - start_info[:enqueued_at]) * 1000).round(2)
298
+ end
295
299
 
296
300
  # Determine level based on outcome and duration
297
301
  level = if exception
@@ -80,6 +80,7 @@ module BrainzLab
80
80
  end
81
81
 
82
82
  def handle_sql_event(event)
83
+ payload = event.payload
83
84
  duration = event.duration.round(2)
84
85
 
85
86
  # Record breadcrumb for Reflex (enhanced)
@@ -217,12 +218,14 @@ module BrainzLab
217
218
  tracker[:count] += 1
218
219
 
219
220
  # Store sample queries (limited)
220
- tracker[:queries] << truncate_sql(sql, 200) if tracker[:queries].size < 3
221
+ if tracker[:queries].size < 3
222
+ tracker[:queries] << truncate_sql(sql, 200)
223
+ end
221
224
 
222
225
  # Detect N+1 pattern
223
- return unless tracker[:count] == BrainzLab.configuration.n_plus_one_threshold
224
-
225
- report_n_plus_one(table, tracker)
226
+ if tracker[:count] == BrainzLab.configuration.n_plus_one_threshold
227
+ report_n_plus_one(table, tracker)
228
+ end
226
229
  end
227
230
 
228
231
  def report_n_plus_one(table, tracker)
@@ -237,14 +240,14 @@ module BrainzLab
237
240
  }
238
241
  )
239
242
 
240
- return unless BrainzLab.configuration.recall_effectively_enabled?
241
-
242
- BrainzLab::Recall.warn(
243
- 'Potential N+1 query detected',
244
- table: table,
245
- query_count: tracker[:count],
246
- sample_queries: tracker[:queries]
247
- )
243
+ if BrainzLab.configuration.recall_effectively_enabled?
244
+ BrainzLab::Recall.warn(
245
+ "Potential N+1 query detected",
246
+ table: table,
247
+ query_count: tracker[:count],
248
+ sample_queries: tracker[:queries]
249
+ )
250
+ end
248
251
  end
249
252
 
250
253
  def clear_n_plus_one_tracker!
@@ -329,8 +332,8 @@ module BrainzLab
329
332
  transaction = event.payload[:transaction]
330
333
  return unless transaction
331
334
 
332
- Thread.current[:brainzlab_transaction_starts] ||= {}.compare_by_identity
333
- Thread.current[:brainzlab_transaction_starts][transaction] = event.time
335
+ Thread.current[:brainzlab_transaction_starts] ||= {}
336
+ Thread.current[:brainzlab_transaction_starts][transaction.object_id] = event.time
334
337
  rescue StandardError => e
335
338
  BrainzLab.debug_log("ActiveRecord transaction start instrumentation failed: #{e.message}")
336
339
  end
@@ -341,8 +344,8 @@ module BrainzLab
341
344
  outcome = payload[:outcome] # :commit, :rollback, :restart, :incomplete
342
345
 
343
346
  # Calculate duration from stored start time
344
- starts = Thread.current[:brainzlab_transaction_starts] || {}.compare_by_identity
345
- start_time = starts.delete(transaction) || event.time
347
+ starts = Thread.current[:brainzlab_transaction_starts] || {}
348
+ start_time = starts.delete(transaction&.object_id) || event.time
346
349
  duration = ((event.end - start_time) * 1000).round(2)
347
350
 
348
351
  connection_name = extract_connection_name(payload[:connection])
@@ -437,7 +440,7 @@ module BrainzLab
437
440
  # Log to Recall
438
441
  if BrainzLab.configuration.recall_effectively_enabled?
439
442
  BrainzLab::Recall.warn(
440
- 'Strict loading violation detected',
443
+ "Strict loading violation detected",
441
444
  owner_class: owner_class,
442
445
  association: association_name.to_s,
443
446
  message: "Attempted to lazily load #{association_name} on #{owner_class} with strict_loading enabled"
@@ -482,7 +485,7 @@ module BrainzLab
482
485
  # Log to Recall
483
486
  if BrainzLab.configuration.recall_effectively_enabled?
484
487
  BrainzLab::Recall.warn(
485
- 'Deprecated association accessed',
488
+ "Deprecated association accessed",
486
489
  owner_class: owner_class,
487
490
  association: association_name.to_s,
488
491
  message: message
@@ -518,9 +521,9 @@ module BrainzLab
518
521
  # Handles: SELECT ... FROM table_name, SELECT ... FROM "table_name", etc.
519
522
  return nil unless sql =~ /\ASELECT/i
520
523
 
521
- return unless sql =~ /FROM\s+["'`]?(\w+)["'`]?/i
522
-
523
- ::Regexp.last_match(1)
524
+ if sql =~ /FROM\s+["'`]?(\w+)["'`]?/i
525
+ ::Regexp.last_match(1)
526
+ end
524
527
  end
525
528
 
526
529
  def skip_query?(payload)