brainzlab 0.1.2 → 0.1.4

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +6 -21
  3. data/README.md +16 -2
  4. data/lib/brainzlab/beacon/client.rb +38 -40
  5. data/lib/brainzlab/beacon/provisioner.rb +1 -1
  6. data/lib/brainzlab/beacon.rb +15 -15
  7. data/lib/brainzlab/configuration.rb +112 -90
  8. data/lib/brainzlab/context.rb +2 -3
  9. data/lib/brainzlab/cortex/client.rb +29 -31
  10. data/lib/brainzlab/cortex/provisioner.rb +1 -1
  11. data/lib/brainzlab/cortex.rb +7 -11
  12. data/lib/brainzlab/dendrite/client.rb +42 -44
  13. data/lib/brainzlab/dendrite/provisioner.rb +1 -1
  14. data/lib/brainzlab/dendrite.rb +4 -4
  15. data/lib/brainzlab/devtools/data/collector.rb +22 -22
  16. data/lib/brainzlab/devtools/middleware/asset_server.rb +14 -14
  17. data/lib/brainzlab/devtools/middleware/database_handler.rb +52 -55
  18. data/lib/brainzlab/devtools/middleware/debug_panel.rb +19 -19
  19. data/lib/brainzlab/devtools/middleware/error_page.rb +45 -44
  20. data/lib/brainzlab/devtools/renderers/debug_panel_renderer.rb +39 -35
  21. data/lib/brainzlab/devtools/renderers/error_page_renderer.rb +13 -9
  22. data/lib/brainzlab/devtools.rb +11 -11
  23. data/lib/brainzlab/flux/buffer.rb +3 -3
  24. data/lib/brainzlab/flux/client.rb +14 -16
  25. data/lib/brainzlab/flux/provisioner.rb +13 -13
  26. data/lib/brainzlab/flux.rb +8 -8
  27. data/lib/brainzlab/instrumentation/action_cable.rb +351 -0
  28. data/lib/brainzlab/instrumentation/action_controller.rb +649 -0
  29. data/lib/brainzlab/instrumentation/action_dispatch.rb +259 -0
  30. data/lib/brainzlab/instrumentation/action_mailbox.rb +197 -0
  31. data/lib/brainzlab/instrumentation/action_mailer.rb +14 -13
  32. data/lib/brainzlab/instrumentation/action_view.rb +380 -0
  33. data/lib/brainzlab/instrumentation/active_job.rb +569 -0
  34. data/lib/brainzlab/instrumentation/active_record.rb +467 -36
  35. data/lib/brainzlab/instrumentation/active_storage.rb +541 -0
  36. data/lib/brainzlab/instrumentation/active_support_cache.rb +700 -0
  37. data/lib/brainzlab/instrumentation/aws.rb +43 -39
  38. data/lib/brainzlab/instrumentation/dalli.rb +20 -20
  39. data/lib/brainzlab/instrumentation/delayed_job.rb +27 -29
  40. data/lib/brainzlab/instrumentation/elasticsearch.rb +23 -24
  41. data/lib/brainzlab/instrumentation/excon.rb +27 -27
  42. data/lib/brainzlab/instrumentation/faraday.rb +3 -4
  43. data/lib/brainzlab/instrumentation/good_job.rb +28 -28
  44. data/lib/brainzlab/instrumentation/grape.rb +24 -24
  45. data/lib/brainzlab/instrumentation/graphql.rb +24 -23
  46. data/lib/brainzlab/instrumentation/httparty.rb +13 -14
  47. data/lib/brainzlab/instrumentation/mongodb.rb +7 -7
  48. data/lib/brainzlab/instrumentation/net_http.rb +6 -6
  49. data/lib/brainzlab/instrumentation/rails_deprecation.rb +139 -0
  50. data/lib/brainzlab/instrumentation/railties.rb +134 -0
  51. data/lib/brainzlab/instrumentation/redis.rb +14 -21
  52. data/lib/brainzlab/instrumentation/resque.rb +23 -24
  53. data/lib/brainzlab/instrumentation/sidekiq.rb +29 -28
  54. data/lib/brainzlab/instrumentation/solid_queue.rb +37 -41
  55. data/lib/brainzlab/instrumentation/stripe.rb +36 -37
  56. data/lib/brainzlab/instrumentation/typhoeus.rb +19 -17
  57. data/lib/brainzlab/instrumentation.rb +111 -21
  58. data/lib/brainzlab/nerve/client.rb +38 -40
  59. data/lib/brainzlab/nerve/provisioner.rb +1 -1
  60. data/lib/brainzlab/nerve.rb +6 -6
  61. data/lib/brainzlab/pulse/client.rb +15 -11
  62. data/lib/brainzlab/pulse/instrumentation.rb +61 -57
  63. data/lib/brainzlab/pulse/propagation.rb +28 -28
  64. data/lib/brainzlab/pulse/provisioner.rb +12 -12
  65. data/lib/brainzlab/pulse/tracer.rb +3 -3
  66. data/lib/brainzlab/pulse.rb +13 -13
  67. data/lib/brainzlab/rails/log_formatter.rb +127 -121
  68. data/lib/brainzlab/rails/log_subscriber.rb +70 -76
  69. data/lib/brainzlab/rails/railtie.rb +66 -89
  70. data/lib/brainzlab/recall/buffer.rb +1 -1
  71. data/lib/brainzlab/recall/client.rb +14 -10
  72. data/lib/brainzlab/recall/logger.rb +16 -18
  73. data/lib/brainzlab/recall/provisioner.rb +16 -16
  74. data/lib/brainzlab/recall.rb +11 -13
  75. data/lib/brainzlab/reflex/breadcrumbs.rb +2 -2
  76. data/lib/brainzlab/reflex/client.rb +14 -10
  77. data/lib/brainzlab/reflex/provisioner.rb +12 -12
  78. data/lib/brainzlab/reflex.rb +29 -29
  79. data/lib/brainzlab/sentinel/client.rb +40 -42
  80. data/lib/brainzlab/sentinel/provisioner.rb +1 -1
  81. data/lib/brainzlab/sentinel.rb +5 -5
  82. data/lib/brainzlab/signal/client.rb +12 -14
  83. data/lib/brainzlab/signal/provisioner.rb +12 -12
  84. data/lib/brainzlab/signal.rb +7 -7
  85. data/lib/brainzlab/synapse/client.rb +42 -44
  86. data/lib/brainzlab/synapse/provisioner.rb +1 -1
  87. data/lib/brainzlab/synapse.rb +6 -6
  88. data/lib/brainzlab/utilities/circuit_breaker.rb +37 -41
  89. data/lib/brainzlab/utilities/health_check.rb +53 -55
  90. data/lib/brainzlab/utilities/log_formatter.rb +38 -40
  91. data/lib/brainzlab/utilities/rate_limiter.rb +5 -5
  92. data/lib/brainzlab/utilities.rb +4 -4
  93. data/lib/brainzlab/vault/cache.rb +1 -1
  94. data/lib/brainzlab/vault/client.rb +39 -41
  95. data/lib/brainzlab/vault/provisioner.rb +1 -1
  96. data/lib/brainzlab/vault.rb +19 -25
  97. data/lib/brainzlab/version.rb +1 -1
  98. data/lib/brainzlab/vision/client.rb +20 -20
  99. data/lib/brainzlab/vision/provisioner.rb +21 -21
  100. data/lib/brainzlab/vision.rb +17 -19
  101. data/lib/brainzlab-sdk.rb +1 -1
  102. data/lib/brainzlab.rb +22 -24
  103. data/lib/generators/brainzlab/install/install_generator.rb +29 -27
  104. metadata +11 -1
@@ -4,6 +4,9 @@ module BrainzLab
4
4
  class Configuration
5
5
  LEVELS = %i[debug info warn error fatal].freeze
6
6
 
7
+ # recall_min_level has a custom setter with validation
8
+ attr_reader :recall_min_level
9
+
7
10
  attr_accessor :secret_key,
8
11
  :environment,
9
12
  :service,
@@ -14,7 +17,6 @@ module BrainzLab
14
17
  :debug,
15
18
  :recall_enabled,
16
19
  :recall_url,
17
- :recall_min_level,
18
20
  :recall_buffer_size,
19
21
  :recall_flush_interval,
20
22
  :recall_master_key,
@@ -110,7 +112,11 @@ module BrainzLab
110
112
  :instrument_graphql,
111
113
  :instrument_mongodb,
112
114
  :instrument_elasticsearch,
115
+ :instrument_action_controller,
116
+ :instrument_action_view,
113
117
  :instrument_action_mailer,
118
+ :instrument_active_job,
119
+ :instrument_active_support_cache,
114
120
  :instrument_delayed_job,
115
121
  :instrument_grape,
116
122
  :instrument_solid_queue,
@@ -121,6 +127,12 @@ module BrainzLab
121
127
  :instrument_dalli,
122
128
  :instrument_aws,
123
129
  :instrument_stripe,
130
+ :instrument_active_storage,
131
+ :instrument_action_cable,
132
+ :instrument_action_dispatch,
133
+ :instrument_rails_deprecation,
134
+ :instrument_action_mailbox,
135
+ :instrument_railties,
124
136
  :http_ignore_hosts,
125
137
  :redis_ignore_commands,
126
138
  :log_formatter_enabled,
@@ -140,61 +152,61 @@ module BrainzLab
140
152
 
141
153
  # Services that should not track themselves to avoid circular dependencies
142
154
  SELF_TRACKING_SERVICES = {
143
- "recall" => :recall_enabled,
144
- "reflex" => :reflex_enabled,
145
- "pulse" => :pulse_enabled,
146
- "flux" => :flux_enabled,
147
- "signal" => :signal_enabled
155
+ 'recall' => :recall_enabled,
156
+ 'reflex' => :reflex_enabled,
157
+ 'pulse' => :pulse_enabled,
158
+ 'flux' => :flux_enabled,
159
+ 'signal' => :signal_enabled
148
160
  }.freeze
149
161
 
150
162
  def initialize
151
163
  # Authentication
152
- @secret_key = ENV["BRAINZLAB_SECRET_KEY"]
164
+ @secret_key = ENV.fetch('BRAINZLAB_SECRET_KEY', nil)
153
165
 
154
166
  # Environment
155
- @environment = ENV["BRAINZLAB_ENVIRONMENT"] || detect_environment
156
- @service = ENV["BRAINZLAB_SERVICE"]
157
- @host = ENV["BRAINZLAB_HOST"] || detect_host
167
+ @environment = ENV['BRAINZLAB_ENVIRONMENT'] || detect_environment
168
+ @service = ENV.fetch('BRAINZLAB_SERVICE', nil)
169
+ @host = ENV['BRAINZLAB_HOST'] || detect_host
158
170
 
159
171
  # App name for auto-provisioning
160
- @app_name = ENV["BRAINZLAB_APP_NAME"]
172
+ @app_name = ENV.fetch('BRAINZLAB_APP_NAME', nil)
161
173
 
162
174
  # Git context
163
- @commit = ENV["GIT_COMMIT"] || ENV["COMMIT_SHA"] || detect_git_commit
164
- @branch = ENV["GIT_BRANCH"] || ENV["BRANCH_NAME"] || detect_git_branch
175
+ @commit = ENV['GIT_COMMIT'] || ENV['COMMIT_SHA'] || detect_git_commit
176
+ @branch = ENV['GIT_BRANCH'] || ENV['BRANCH_NAME'] || detect_git_branch
165
177
 
166
178
  # Debug mode - enables verbose logging
167
- @debug = ENV["BRAINZLAB_DEBUG"] == "true"
179
+ @debug = ENV['BRAINZLAB_DEBUG'] == 'true'
168
180
 
169
181
  # Disable self-tracking - prevents services from tracking to themselves
170
182
  # e.g., Recall won't log to itself, Reflex won't track errors to itself
171
- @disable_self_tracking = ENV.fetch("BRAINZLAB_DISABLE_SELF_TRACKING", "true") == "true"
183
+ @disable_self_tracking = ENV.fetch('BRAINZLAB_DISABLE_SELF_TRACKING', 'true') == 'true'
172
184
 
173
185
  # Recall settings
174
186
  @recall_enabled = true
175
- @recall_url = ENV["RECALL_URL"] || "https://recall.brainzlab.ai"
187
+ @recall_url = ENV['RECALL_URL'] || 'https://recall.brainzlab.ai'
176
188
  @recall_min_level = :debug
177
189
  @recall_buffer_size = 50
178
190
  @recall_flush_interval = 5
179
- @recall_master_key = ENV["RECALL_MASTER_KEY"]
191
+ @recall_master_key = ENV.fetch('RECALL_MASTER_KEY', nil)
180
192
  @recall_auto_provision = true
181
193
 
182
194
  # Reflex settings
183
195
  @reflex_enabled = true
184
- @reflex_url = ENV["REFLEX_URL"] || "https://reflex.brainzlab.ai"
185
- @reflex_api_key = ENV["REFLEX_API_KEY"]
186
- @reflex_master_key = ENV["REFLEX_MASTER_KEY"]
196
+ @reflex_url = ENV['REFLEX_URL'] || 'https://reflex.brainzlab.ai'
197
+ @reflex_api_key = ENV.fetch('REFLEX_API_KEY', nil)
198
+ @reflex_master_key = ENV.fetch('REFLEX_MASTER_KEY', nil)
187
199
  @reflex_auto_provision = true
188
200
  @reflex_excluded_exceptions = []
189
201
  @reflex_before_send = nil
190
202
  @reflex_sample_rate = nil
191
- @reflex_fingerprint = nil # Custom fingerprint callback
203
+ @reflex_fingerprint = nil # Custom fingerprint callback
192
204
 
193
205
  # Pulse settings
194
206
  @pulse_enabled = true
195
- @pulse_url = ENV["PULSE_URL"] || "https://pulse.brainzlab.ai"
196
- @pulse_api_key = ENV["PULSE_API_KEY"]
197
- @pulse_master_key = ENV["PULSE_MASTER_KEY"]
207
+ @pulse_url = ENV['PULSE_URL'] || 'https://pulse.brainzlab.ai'
208
+ @pulse_api_key = ENV.fetch('PULSE_API_KEY', nil)
209
+ @pulse_master_key = ENV.fetch('PULSE_MASTER_KEY', nil)
198
210
  @pulse_auto_provision = true
199
211
  @pulse_buffer_size = 50
200
212
  @pulse_flush_interval = 5
@@ -203,86 +215,86 @@ module BrainzLab
203
215
 
204
216
  # Flux settings
205
217
  @flux_enabled = true
206
- @flux_url = ENV["FLUX_URL"] || "https://flux.brainzlab.ai"
207
- @flux_api_key = ENV["FLUX_API_KEY"]
208
- @flux_ingest_key = ENV["FLUX_INGEST_KEY"]
209
- @flux_master_key = ENV["FLUX_MASTER_KEY"]
218
+ @flux_url = ENV['FLUX_URL'] || 'https://flux.brainzlab.ai'
219
+ @flux_api_key = ENV.fetch('FLUX_API_KEY', nil)
220
+ @flux_ingest_key = ENV.fetch('FLUX_INGEST_KEY', nil)
221
+ @flux_master_key = ENV.fetch('FLUX_MASTER_KEY', nil)
210
222
  @flux_auto_provision = true
211
223
  @flux_buffer_size = 100
212
224
  @flux_flush_interval = 5
213
225
 
214
226
  # Signal settings
215
227
  @signal_enabled = true
216
- @signal_url = ENV["SIGNAL_URL"] || "https://signal.brainzlab.ai"
217
- @signal_api_key = ENV["SIGNAL_API_KEY"]
218
- @signal_master_key = ENV["SIGNAL_MASTER_KEY"]
228
+ @signal_url = ENV['SIGNAL_URL'] || 'https://signal.brainzlab.ai'
229
+ @signal_api_key = ENV.fetch('SIGNAL_API_KEY', nil)
230
+ @signal_master_key = ENV.fetch('SIGNAL_MASTER_KEY', nil)
219
231
  @signal_auto_provision = true
220
232
 
221
233
  # Vault settings
222
234
  @vault_enabled = true
223
- @vault_url = ENV["VAULT_URL"] || "https://vault.brainzlab.ai"
224
- @vault_api_key = ENV["VAULT_API_KEY"]
225
- @vault_master_key = ENV["VAULT_MASTER_KEY"]
235
+ @vault_url = ENV['VAULT_URL'] || 'https://vault.brainzlab.ai'
236
+ @vault_api_key = ENV.fetch('VAULT_API_KEY', nil)
237
+ @vault_master_key = ENV.fetch('VAULT_MASTER_KEY', nil)
226
238
  @vault_auto_provision = true
227
239
  @vault_cache_enabled = true
228
- @vault_cache_ttl = 300 # 5 minutes
229
- @vault_auto_load = ENV.fetch("VAULT_AUTO_LOAD", "false") == "true" # Auto-load secrets into ENV
230
- @vault_load_provider_keys = true # Also load provider keys (OpenAI, etc.)
240
+ @vault_cache_ttl = 300 # 5 minutes
241
+ @vault_auto_load = ENV.fetch('VAULT_AUTO_LOAD', 'false') == 'true' # Auto-load secrets into ENV
242
+ @vault_load_provider_keys = true # Also load provider keys (OpenAI, etc.)
231
243
 
232
244
  # Vision settings (AI browser automation)
233
245
  @vision_enabled = true
234
- @vision_url = ENV["VISION_URL"] || "https://vision.brainzlab.ai"
235
- @vision_api_key = ENV["VISION_API_KEY"]
236
- @vision_ingest_key = ENV["VISION_INGEST_KEY"]
237
- @vision_master_key = ENV["VISION_MASTER_KEY"]
246
+ @vision_url = ENV['VISION_URL'] || 'https://vision.brainzlab.ai'
247
+ @vision_api_key = ENV.fetch('VISION_API_KEY', nil)
248
+ @vision_ingest_key = ENV.fetch('VISION_INGEST_KEY', nil)
249
+ @vision_master_key = ENV.fetch('VISION_MASTER_KEY', nil)
238
250
  @vision_auto_provision = true
239
- @vision_default_model = ENV["VISION_DEFAULT_MODEL"] || "claude-sonnet-4"
240
- @vision_default_browser_provider = ENV["VISION_DEFAULT_BROWSER_PROVIDER"] || "local"
251
+ @vision_default_model = ENV['VISION_DEFAULT_MODEL'] || 'claude-sonnet-4'
252
+ @vision_default_browser_provider = ENV['VISION_DEFAULT_BROWSER_PROVIDER'] || 'local'
241
253
 
242
254
  # Cortex settings (feature flags)
243
255
  @cortex_enabled = true
244
- @cortex_url = ENV["CORTEX_URL"] || "https://cortex.brainzlab.ai"
245
- @cortex_api_key = ENV["CORTEX_API_KEY"]
246
- @cortex_master_key = ENV["CORTEX_MASTER_KEY"]
256
+ @cortex_url = ENV['CORTEX_URL'] || 'https://cortex.brainzlab.ai'
257
+ @cortex_api_key = ENV.fetch('CORTEX_API_KEY', nil)
258
+ @cortex_master_key = ENV.fetch('CORTEX_MASTER_KEY', nil)
247
259
  @cortex_auto_provision = true
248
260
  @cortex_cache_enabled = true
249
- @cortex_cache_ttl = 60 # 1 minute
261
+ @cortex_cache_ttl = 60 # 1 minute
250
262
  @cortex_default_context = {}
251
263
 
252
264
  # Beacon settings (uptime monitoring)
253
265
  @beacon_enabled = true
254
- @beacon_url = ENV["BEACON_URL"] || "https://beacon.brainzlab.ai"
255
- @beacon_api_key = ENV["BEACON_API_KEY"]
256
- @beacon_master_key = ENV["BEACON_MASTER_KEY"]
266
+ @beacon_url = ENV['BEACON_URL'] || 'https://beacon.brainzlab.ai'
267
+ @beacon_api_key = ENV.fetch('BEACON_API_KEY', nil)
268
+ @beacon_master_key = ENV.fetch('BEACON_MASTER_KEY', nil)
257
269
  @beacon_auto_provision = true
258
270
 
259
271
  # Nerve settings (job monitoring)
260
272
  @nerve_enabled = true
261
- @nerve_url = ENV["NERVE_URL"] || "https://nerve.brainzlab.ai"
262
- @nerve_api_key = ENV["NERVE_API_KEY"]
263
- @nerve_master_key = ENV["NERVE_MASTER_KEY"]
273
+ @nerve_url = ENV['NERVE_URL'] || 'https://nerve.brainzlab.ai'
274
+ @nerve_api_key = ENV.fetch('NERVE_API_KEY', nil)
275
+ @nerve_master_key = ENV.fetch('NERVE_MASTER_KEY', nil)
264
276
  @nerve_auto_provision = true
265
277
 
266
278
  # Dendrite settings (AI documentation)
267
279
  @dendrite_enabled = true
268
- @dendrite_url = ENV["DENDRITE_URL"] || "https://dendrite.brainzlab.ai"
269
- @dendrite_api_key = ENV["DENDRITE_API_KEY"]
270
- @dendrite_master_key = ENV["DENDRITE_MASTER_KEY"]
280
+ @dendrite_url = ENV['DENDRITE_URL'] || 'https://dendrite.brainzlab.ai'
281
+ @dendrite_api_key = ENV.fetch('DENDRITE_API_KEY', nil)
282
+ @dendrite_master_key = ENV.fetch('DENDRITE_MASTER_KEY', nil)
271
283
  @dendrite_auto_provision = true
272
284
 
273
285
  # Sentinel settings (host monitoring)
274
286
  @sentinel_enabled = true
275
- @sentinel_url = ENV["SENTINEL_URL"] || "https://sentinel.brainzlab.ai"
276
- @sentinel_api_key = ENV["SENTINEL_API_KEY"]
277
- @sentinel_agent_key = ENV["SENTINEL_AGENT_KEY"]
278
- @sentinel_master_key = ENV["SENTINEL_MASTER_KEY"]
287
+ @sentinel_url = ENV['SENTINEL_URL'] || 'https://sentinel.brainzlab.ai'
288
+ @sentinel_api_key = ENV.fetch('SENTINEL_API_KEY', nil)
289
+ @sentinel_agent_key = ENV.fetch('SENTINEL_AGENT_KEY', nil)
290
+ @sentinel_master_key = ENV.fetch('SENTINEL_MASTER_KEY', nil)
279
291
  @sentinel_auto_provision = true
280
292
 
281
293
  # Synapse settings (AI development orchestration)
282
294
  @synapse_enabled = true
283
- @synapse_url = ENV["SYNAPSE_URL"] || "https://synapse.brainzlab.ai"
284
- @synapse_api_key = ENV["SYNAPSE_API_KEY"]
285
- @synapse_master_key = ENV["SYNAPSE_MASTER_KEY"]
295
+ @synapse_url = ENV['SYNAPSE_URL'] || 'https://synapse.brainzlab.ai'
296
+ @synapse_api_key = ENV.fetch('SYNAPSE_API_KEY', nil)
297
+ @synapse_master_key = ENV.fetch('SYNAPSE_MASTER_KEY', nil)
286
298
  @synapse_auto_provision = true
287
299
 
288
300
  # Filtering
@@ -292,26 +304,36 @@ module BrainzLab
292
304
  @logger = nil
293
305
 
294
306
  # Instrumentation
295
- @instrument_http = true # Enable HTTP client instrumentation (Net::HTTP, Faraday, HTTParty)
296
- @instrument_active_record = true # AR breadcrumbs for Reflex
297
- @instrument_redis = true # Redis command instrumentation
307
+ @instrument_http = true # Enable HTTP client instrumentation (Net::HTTP, Faraday, HTTParty)
308
+ @instrument_active_record = true # AR breadcrumbs for Reflex
309
+ @instrument_redis = true # Redis command instrumentation
298
310
  @instrument_sidekiq = true # Sidekiq job instrumentation
299
311
  @instrument_graphql = true # GraphQL query instrumentation
300
312
  @instrument_mongodb = true # MongoDB/Mongoid instrumentation
301
313
  @instrument_elasticsearch = true # Elasticsearch instrumentation
314
+ @instrument_action_controller = true # ActionController instrumentation (requests, redirects, filters)
315
+ @instrument_action_view = true # ActionView instrumentation (templates, partials, collections)
302
316
  @instrument_action_mailer = true # ActionMailer instrumentation
303
- @instrument_delayed_job = true # Delayed::Job instrumentation
304
- @instrument_grape = true # Grape API instrumentation
305
- @instrument_solid_queue = true # Solid Queue job instrumentation
306
- @instrument_good_job = true # GoodJob instrumentation
307
- @instrument_resque = true # Resque instrumentation
308
- @instrument_excon = true # Excon HTTP client instrumentation
309
- @instrument_typhoeus = true # Typhoeus HTTP client instrumentation
310
- @instrument_dalli = true # Dalli/Memcached instrumentation
311
- @instrument_aws = true # AWS SDK instrumentation
312
- @instrument_stripe = true # Stripe API instrumentation
317
+ @instrument_active_job = true # ActiveJob instrumentation (enqueue, perform, retry, discard)
318
+ @instrument_active_support_cache = true # ActiveSupport::Cache instrumentation (read, write, fetch)
319
+ @instrument_delayed_job = true # Delayed::Job instrumentation
320
+ @instrument_grape = true # Grape API instrumentation
321
+ @instrument_solid_queue = true # Solid Queue job instrumentation
322
+ @instrument_good_job = true # GoodJob instrumentation
323
+ @instrument_resque = true # Resque instrumentation
324
+ @instrument_excon = true # Excon HTTP client instrumentation
325
+ @instrument_typhoeus = true # Typhoeus HTTP client instrumentation
326
+ @instrument_dalli = true # Dalli/Memcached instrumentation
327
+ @instrument_aws = true # AWS SDK instrumentation
328
+ @instrument_stripe = true # Stripe API instrumentation
329
+ @instrument_active_storage = true # ActiveStorage instrumentation (uploads, downloads, transforms)
330
+ @instrument_action_cable = true # ActionCable WebSocket instrumentation
331
+ @instrument_action_dispatch = true # ActionDispatch instrumentation (middleware, redirects, requests)
332
+ @instrument_rails_deprecation = true # Rails deprecation warnings tracking
333
+ @instrument_action_mailbox = true # ActionMailbox inbound email processing instrumentation
334
+ @instrument_railties = true # Railties config initializer loading instrumentation
313
335
  @http_ignore_hosts = %w[localhost 127.0.0.1]
314
- @redis_ignore_commands = %w[ping info] # Commands to skip tracking
336
+ @redis_ignore_commands = %w[ping info] # Commands to skip tracking
315
337
 
316
338
  # Log formatter settings
317
339
  @log_formatter_enabled = true
@@ -325,9 +347,9 @@ module BrainzLab
325
347
  @devtools_error_page_enabled = true
326
348
  @devtools_debug_panel_enabled = true
327
349
  @devtools_allowed_environments = %w[development test]
328
- @devtools_allowed_ips = ["127.0.0.1", "::1", "172.16.0.0/12", "192.168.0.0/16", "10.0.0.0/8"]
329
- @devtools_asset_path = "/__brainzlab__"
330
- @devtools_panel_position = "bottom-right"
350
+ @devtools_allowed_ips = ['127.0.0.1', '::1', '172.16.0.0/12', '192.168.0.0/16', '10.0.0.0/8']
351
+ @devtools_asset_path = '/__brainzlab__'
352
+ @devtools_panel_position = 'bottom-right'
331
353
  @devtools_expand_by_default = false
332
354
  end
333
355
 
@@ -465,7 +487,7 @@ module BrainzLab
465
487
 
466
488
  # Disable if this is the Recall service itself
467
489
  normalized_app_name = @app_name.to_s.downcase.strip
468
- normalized_app_name != "recall"
490
+ normalized_app_name != 'recall'
469
491
  end
470
492
 
471
493
  # Check if reflex is effectively enabled (considering self-tracking)
@@ -475,7 +497,7 @@ module BrainzLab
475
497
 
476
498
  # Disable if this is the Reflex service itself
477
499
  normalized_app_name = @app_name.to_s.downcase.strip
478
- normalized_app_name != "reflex"
500
+ normalized_app_name != 'reflex'
479
501
  end
480
502
 
481
503
  # Check if pulse is effectively enabled (considering self-tracking)
@@ -485,7 +507,7 @@ module BrainzLab
485
507
 
486
508
  # Disable if this is the Pulse service itself
487
509
  normalized_app_name = @app_name.to_s.downcase.strip
488
- normalized_app_name != "pulse"
510
+ normalized_app_name != 'pulse'
489
511
  end
490
512
 
491
513
  # Check if flux is effectively enabled (considering self-tracking)
@@ -495,7 +517,7 @@ module BrainzLab
495
517
 
496
518
  # Disable if this is the Flux service itself
497
519
  normalized_app_name = @app_name.to_s.downcase.strip
498
- normalized_app_name != "flux"
520
+ normalized_app_name != 'flux'
499
521
  end
500
522
 
501
523
  # Check if signal is effectively enabled (considering self-tracking)
@@ -505,7 +527,7 @@ module BrainzLab
505
527
 
506
528
  # Disable if this is the Signal service itself
507
529
  normalized_app_name = @app_name.to_s.downcase.strip
508
- normalized_app_name != "signal"
530
+ normalized_app_name != 'signal'
509
531
  end
510
532
 
511
533
  def debug_log(message)
@@ -515,7 +537,7 @@ module BrainzLab
515
537
  if logger
516
538
  logger.debug(log_message)
517
539
  else
518
- $stderr.puts(log_message)
540
+ warn(log_message)
519
541
  end
520
542
  end
521
543
 
@@ -523,14 +545,14 @@ module BrainzLab
523
545
 
524
546
  def detect_environment
525
547
  return ::Rails.env.to_s if defined?(::Rails) && ::Rails.respond_to?(:env)
526
- return ENV["RACK_ENV"] if ENV["RACK_ENV"]
527
- return ENV["RUBY_ENV"] if ENV["RUBY_ENV"]
548
+ return ENV['RACK_ENV'] if ENV['RACK_ENV']
549
+ return ENV['RUBY_ENV'] if ENV['RUBY_ENV']
528
550
 
529
- "development"
551
+ 'development'
530
552
  end
531
553
 
532
554
  def detect_host
533
- require "socket"
555
+ require 'socket'
534
556
  Socket.gethostname
535
557
  rescue StandardError
536
558
  nil
@@ -14,9 +14,8 @@ module BrainzLab
14
14
  end
15
15
  end
16
16
 
17
- attr_accessor :user, :request_id, :session_id
18
- attr_accessor :request_method, :request_path, :request_url, :request_params, :request_headers
19
- attr_accessor :controller, :action
17
+ attr_accessor :user, :request_id, :session_id, :request_method, :request_path, :request_url, :request_params,
18
+ :request_headers, :controller, :action
20
19
  attr_reader :extra, :tags, :breadcrumbs
21
20
 
22
21
  def initialize
@@ -1,23 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "net/http"
4
- require "json"
5
- require "uri"
6
- require "cgi"
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'uri'
6
+ require 'cgi'
7
7
 
8
8
  module BrainzLab
9
9
  module Cortex
10
10
  class Client
11
11
  def initialize(config)
12
12
  @config = config
13
- @base_url = config.cortex_url || "https://cortex.brainzlab.ai"
13
+ @base_url = config.cortex_url || 'https://cortex.brainzlab.ai'
14
14
  end
15
15
 
16
16
  # Evaluate a single flag
17
17
  def evaluate(flag_name, context: {})
18
18
  response = request(
19
19
  :post,
20
- "/api/v1/evaluate",
20
+ '/api/v1/evaluate',
21
21
  body: {
22
22
  flag: flag_name,
23
23
  context: context
@@ -29,7 +29,7 @@ module BrainzLab
29
29
  data = JSON.parse(response.body, symbolize_names: true)
30
30
  data[:result]
31
31
  rescue StandardError => e
32
- log_error("evaluate", e)
32
+ log_error('evaluate', e)
33
33
  nil
34
34
  end
35
35
 
@@ -37,7 +37,7 @@ module BrainzLab
37
37
  def evaluate_all(context: {})
38
38
  response = request(
39
39
  :post,
40
- "/api/v1/evaluate/batch",
40
+ '/api/v1/evaluate/batch',
41
41
  body: { context: context }
42
42
  )
43
43
 
@@ -46,20 +46,20 @@ module BrainzLab
46
46
  data = JSON.parse(response.body, symbolize_names: true)
47
47
  data[:flags] || {}
48
48
  rescue StandardError => e
49
- log_error("evaluate_all", e)
49
+ log_error('evaluate_all', e)
50
50
  {}
51
51
  end
52
52
 
53
53
  # List all flags
54
54
  def list
55
- response = request(:get, "/api/v1/flags")
55
+ response = request(:get, '/api/v1/flags')
56
56
 
57
57
  return [] unless response.is_a?(Net::HTTPSuccess)
58
58
 
59
59
  data = JSON.parse(response.body, symbolize_names: true)
60
60
  data[:flags] || []
61
61
  rescue StandardError => e
62
- log_error("list", e)
62
+ log_error('list', e)
63
63
  []
64
64
  end
65
65
 
@@ -71,21 +71,21 @@ module BrainzLab
71
71
 
72
72
  JSON.parse(response.body, symbolize_names: true)
73
73
  rescue StandardError => e
74
- log_error("get_flag", e)
74
+ log_error('get_flag', e)
75
75
  nil
76
76
  end
77
77
 
78
78
  def provision(project_id:, app_name:)
79
79
  response = request(
80
80
  :post,
81
- "/api/v1/projects/provision",
81
+ '/api/v1/projects/provision',
82
82
  body: { project_id: project_id, app_name: app_name },
83
83
  use_service_key: true
84
84
  )
85
85
 
86
86
  response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPCreated)
87
87
  rescue StandardError => e
88
- log_error("provision", e)
88
+ log_error('provision', e)
89
89
  false
90
90
  end
91
91
 
@@ -94,35 +94,33 @@ module BrainzLab
94
94
  def request(method, path, headers: {}, body: nil, params: nil, use_service_key: false)
95
95
  uri = URI.parse("#{@base_url}#{path}")
96
96
 
97
- if params
98
- uri.query = URI.encode_www_form(params)
99
- end
97
+ uri.query = URI.encode_www_form(params) if params
100
98
 
101
99
  http = Net::HTTP.new(uri.host, uri.port)
102
- http.use_ssl = uri.scheme == "https"
100
+ http.use_ssl = uri.scheme == 'https'
103
101
  http.open_timeout = 5
104
102
  http.read_timeout = 10
105
103
 
106
104
  request = case method
107
- when :get
108
- Net::HTTP::Get.new(uri)
109
- when :post
110
- Net::HTTP::Post.new(uri)
111
- when :put
112
- Net::HTTP::Put.new(uri)
113
- when :delete
114
- Net::HTTP::Delete.new(uri)
115
- end
105
+ when :get
106
+ Net::HTTP::Get.new(uri)
107
+ when :post
108
+ Net::HTTP::Post.new(uri)
109
+ when :put
110
+ Net::HTTP::Put.new(uri)
111
+ when :delete
112
+ Net::HTTP::Delete.new(uri)
113
+ end
116
114
 
117
115
  # Set headers
118
- request["Content-Type"] = "application/json"
119
- request["Accept"] = "application/json"
116
+ request['Content-Type'] = 'application/json'
117
+ request['Accept'] = 'application/json'
120
118
 
121
119
  if use_service_key
122
- request["X-Service-Key"] = @config.cortex_master_key || @config.secret_key
120
+ request['X-Service-Key'] = @config.cortex_master_key || @config.secret_key
123
121
  else
124
122
  auth_key = @config.cortex_api_key || @config.secret_key
125
- request["Authorization"] = "Bearer #{auth_key}" if auth_key
123
+ request['Authorization'] = "Bearer #{auth_key}" if auth_key
126
124
  end
127
125
 
128
126
  headers.each { |k, v| request[k] = v }
@@ -39,7 +39,7 @@ module BrainzLab
39
39
 
40
40
  def detect_project_id
41
41
  # Try environment variable first
42
- return ENV["BRAINZLAB_PROJECT_ID"] if ENV["BRAINZLAB_PROJECT_ID"]
42
+ return ENV['BRAINZLAB_PROJECT_ID'] if ENV['BRAINZLAB_PROJECT_ID']
43
43
 
44
44
  # Could also detect from Platform API if we have a secret key
45
45
  nil
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "cortex/client"
4
- require_relative "cortex/cache"
5
- require_relative "cortex/provisioner"
3
+ require_relative 'cortex/client'
4
+ require_relative 'cortex/cache'
5
+ require_relative 'cortex/provisioner'
6
6
 
7
7
  module BrainzLab
8
8
  module Cortex
@@ -19,7 +19,7 @@ module BrainzLab
19
19
  #
20
20
  def enabled?(flag_name, **context)
21
21
  result = get(flag_name, **context)
22
- result == true || result == "true"
22
+ [true, 'true'].include?(result)
23
23
  end
24
24
 
25
25
  # Check if a feature flag is disabled
@@ -50,9 +50,7 @@ module BrainzLab
50
50
  cache_key = build_cache_key(flag_key, merged_context)
51
51
 
52
52
  # Check cache first
53
- if BrainzLab.configuration.cortex_cache_enabled && cache.has?(cache_key)
54
- return cache.get(cache_key)
55
- end
53
+ return cache.get(cache_key) if BrainzLab.configuration.cortex_cache_enabled && cache.has?(cache_key)
56
54
 
57
55
  result = client.evaluate(flag_key, context: merged_context)
58
56
 
@@ -194,9 +192,7 @@ module BrainzLab
194
192
 
195
193
  # Also include user from BrainzLab context if available
196
194
  brainzlab_context = {}
197
- if BrainzLab::Context.current.user
198
- brainzlab_context[:user] = BrainzLab::Context.current.user
199
- end
195
+ brainzlab_context[:user] = BrainzLab::Context.current.user if BrainzLab::Context.current.user
200
196
 
201
197
  # Normalize user context
202
198
  merged = default_context.merge(brainzlab_context).merge(thread_context).merge(context)
@@ -220,7 +216,7 @@ module BrainzLab
220
216
 
221
217
  parts = [env, flag_name]
222
218
  parts << "u:#{user_id}" if user_id
223
- parts.join(":")
219
+ parts.join(':')
224
220
  end
225
221
  end
226
222
  end