brainzlab 0.1.2 → 0.1.3

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 (94) 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 +92 -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_mailer.rb +14 -13
  28. data/lib/brainzlab/instrumentation/active_record.rb +13 -15
  29. data/lib/brainzlab/instrumentation/aws.rb +43 -39
  30. data/lib/brainzlab/instrumentation/dalli.rb +20 -20
  31. data/lib/brainzlab/instrumentation/delayed_job.rb +27 -29
  32. data/lib/brainzlab/instrumentation/elasticsearch.rb +23 -24
  33. data/lib/brainzlab/instrumentation/excon.rb +27 -27
  34. data/lib/brainzlab/instrumentation/faraday.rb +3 -4
  35. data/lib/brainzlab/instrumentation/good_job.rb +28 -28
  36. data/lib/brainzlab/instrumentation/grape.rb +24 -24
  37. data/lib/brainzlab/instrumentation/graphql.rb +24 -23
  38. data/lib/brainzlab/instrumentation/httparty.rb +13 -14
  39. data/lib/brainzlab/instrumentation/mongodb.rb +7 -7
  40. data/lib/brainzlab/instrumentation/net_http.rb +6 -6
  41. data/lib/brainzlab/instrumentation/redis.rb +14 -21
  42. data/lib/brainzlab/instrumentation/resque.rb +23 -24
  43. data/lib/brainzlab/instrumentation/sidekiq.rb +29 -28
  44. data/lib/brainzlab/instrumentation/solid_queue.rb +37 -41
  45. data/lib/brainzlab/instrumentation/stripe.rb +36 -37
  46. data/lib/brainzlab/instrumentation/typhoeus.rb +19 -17
  47. data/lib/brainzlab/instrumentation.rb +20 -20
  48. data/lib/brainzlab/nerve/client.rb +38 -40
  49. data/lib/brainzlab/nerve/provisioner.rb +1 -1
  50. data/lib/brainzlab/nerve.rb +6 -6
  51. data/lib/brainzlab/pulse/client.rb +15 -11
  52. data/lib/brainzlab/pulse/instrumentation.rb +61 -57
  53. data/lib/brainzlab/pulse/propagation.rb +28 -28
  54. data/lib/brainzlab/pulse/provisioner.rb +12 -12
  55. data/lib/brainzlab/pulse/tracer.rb +3 -3
  56. data/lib/brainzlab/pulse.rb +13 -13
  57. data/lib/brainzlab/rails/log_formatter.rb +127 -121
  58. data/lib/brainzlab/rails/log_subscriber.rb +70 -76
  59. data/lib/brainzlab/rails/railtie.rb +66 -89
  60. data/lib/brainzlab/recall/buffer.rb +1 -1
  61. data/lib/brainzlab/recall/client.rb +14 -10
  62. data/lib/brainzlab/recall/logger.rb +16 -18
  63. data/lib/brainzlab/recall/provisioner.rb +16 -16
  64. data/lib/brainzlab/recall.rb +11 -13
  65. data/lib/brainzlab/reflex/breadcrumbs.rb +2 -2
  66. data/lib/brainzlab/reflex/client.rb +14 -10
  67. data/lib/brainzlab/reflex/provisioner.rb +12 -12
  68. data/lib/brainzlab/reflex.rb +29 -29
  69. data/lib/brainzlab/sentinel/client.rb +40 -42
  70. data/lib/brainzlab/sentinel/provisioner.rb +1 -1
  71. data/lib/brainzlab/sentinel.rb +5 -5
  72. data/lib/brainzlab/signal/client.rb +12 -14
  73. data/lib/brainzlab/signal/provisioner.rb +12 -12
  74. data/lib/brainzlab/signal.rb +7 -7
  75. data/lib/brainzlab/synapse/client.rb +42 -44
  76. data/lib/brainzlab/synapse/provisioner.rb +1 -1
  77. data/lib/brainzlab/synapse.rb +6 -6
  78. data/lib/brainzlab/utilities/circuit_breaker.rb +37 -41
  79. data/lib/brainzlab/utilities/health_check.rb +53 -55
  80. data/lib/brainzlab/utilities/log_formatter.rb +38 -40
  81. data/lib/brainzlab/utilities/rate_limiter.rb +5 -5
  82. data/lib/brainzlab/utilities.rb +4 -4
  83. data/lib/brainzlab/vault/cache.rb +1 -1
  84. data/lib/brainzlab/vault/client.rb +39 -41
  85. data/lib/brainzlab/vault/provisioner.rb +1 -1
  86. data/lib/brainzlab/vault.rb +19 -25
  87. data/lib/brainzlab/version.rb +1 -1
  88. data/lib/brainzlab/vision/client.rb +20 -20
  89. data/lib/brainzlab/vision/provisioner.rb +21 -21
  90. data/lib/brainzlab/vision.rb +17 -19
  91. data/lib/brainzlab-sdk.rb +1 -1
  92. data/lib/brainzlab.rb +22 -24
  93. data/lib/generators/brainzlab/install/install_generator.rb +29 -27
  94. metadata +1 -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,
@@ -140,61 +142,61 @@ module BrainzLab
140
142
 
141
143
  # Services that should not track themselves to avoid circular dependencies
142
144
  SELF_TRACKING_SERVICES = {
143
- "recall" => :recall_enabled,
144
- "reflex" => :reflex_enabled,
145
- "pulse" => :pulse_enabled,
146
- "flux" => :flux_enabled,
147
- "signal" => :signal_enabled
145
+ 'recall' => :recall_enabled,
146
+ 'reflex' => :reflex_enabled,
147
+ 'pulse' => :pulse_enabled,
148
+ 'flux' => :flux_enabled,
149
+ 'signal' => :signal_enabled
148
150
  }.freeze
149
151
 
150
152
  def initialize
151
153
  # Authentication
152
- @secret_key = ENV["BRAINZLAB_SECRET_KEY"]
154
+ @secret_key = ENV.fetch('BRAINZLAB_SECRET_KEY', nil)
153
155
 
154
156
  # Environment
155
- @environment = ENV["BRAINZLAB_ENVIRONMENT"] || detect_environment
156
- @service = ENV["BRAINZLAB_SERVICE"]
157
- @host = ENV["BRAINZLAB_HOST"] || detect_host
157
+ @environment = ENV['BRAINZLAB_ENVIRONMENT'] || detect_environment
158
+ @service = ENV.fetch('BRAINZLAB_SERVICE', nil)
159
+ @host = ENV['BRAINZLAB_HOST'] || detect_host
158
160
 
159
161
  # App name for auto-provisioning
160
- @app_name = ENV["BRAINZLAB_APP_NAME"]
162
+ @app_name = ENV.fetch('BRAINZLAB_APP_NAME', nil)
161
163
 
162
164
  # Git context
163
- @commit = ENV["GIT_COMMIT"] || ENV["COMMIT_SHA"] || detect_git_commit
164
- @branch = ENV["GIT_BRANCH"] || ENV["BRANCH_NAME"] || detect_git_branch
165
+ @commit = ENV['GIT_COMMIT'] || ENV['COMMIT_SHA'] || detect_git_commit
166
+ @branch = ENV['GIT_BRANCH'] || ENV['BRANCH_NAME'] || detect_git_branch
165
167
 
166
168
  # Debug mode - enables verbose logging
167
- @debug = ENV["BRAINZLAB_DEBUG"] == "true"
169
+ @debug = ENV['BRAINZLAB_DEBUG'] == 'true'
168
170
 
169
171
  # Disable self-tracking - prevents services from tracking to themselves
170
172
  # 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"
173
+ @disable_self_tracking = ENV.fetch('BRAINZLAB_DISABLE_SELF_TRACKING', 'true') == 'true'
172
174
 
173
175
  # Recall settings
174
176
  @recall_enabled = true
175
- @recall_url = ENV["RECALL_URL"] || "https://recall.brainzlab.ai"
177
+ @recall_url = ENV['RECALL_URL'] || 'https://recall.brainzlab.ai'
176
178
  @recall_min_level = :debug
177
179
  @recall_buffer_size = 50
178
180
  @recall_flush_interval = 5
179
- @recall_master_key = ENV["RECALL_MASTER_KEY"]
181
+ @recall_master_key = ENV.fetch('RECALL_MASTER_KEY', nil)
180
182
  @recall_auto_provision = true
181
183
 
182
184
  # Reflex settings
183
185
  @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"]
186
+ @reflex_url = ENV['REFLEX_URL'] || 'https://reflex.brainzlab.ai'
187
+ @reflex_api_key = ENV.fetch('REFLEX_API_KEY', nil)
188
+ @reflex_master_key = ENV.fetch('REFLEX_MASTER_KEY', nil)
187
189
  @reflex_auto_provision = true
188
190
  @reflex_excluded_exceptions = []
189
191
  @reflex_before_send = nil
190
192
  @reflex_sample_rate = nil
191
- @reflex_fingerprint = nil # Custom fingerprint callback
193
+ @reflex_fingerprint = nil # Custom fingerprint callback
192
194
 
193
195
  # Pulse settings
194
196
  @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"]
197
+ @pulse_url = ENV['PULSE_URL'] || 'https://pulse.brainzlab.ai'
198
+ @pulse_api_key = ENV.fetch('PULSE_API_KEY', nil)
199
+ @pulse_master_key = ENV.fetch('PULSE_MASTER_KEY', nil)
198
200
  @pulse_auto_provision = true
199
201
  @pulse_buffer_size = 50
200
202
  @pulse_flush_interval = 5
@@ -203,86 +205,86 @@ module BrainzLab
203
205
 
204
206
  # Flux settings
205
207
  @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"]
208
+ @flux_url = ENV['FLUX_URL'] || 'https://flux.brainzlab.ai'
209
+ @flux_api_key = ENV.fetch('FLUX_API_KEY', nil)
210
+ @flux_ingest_key = ENV.fetch('FLUX_INGEST_KEY', nil)
211
+ @flux_master_key = ENV.fetch('FLUX_MASTER_KEY', nil)
210
212
  @flux_auto_provision = true
211
213
  @flux_buffer_size = 100
212
214
  @flux_flush_interval = 5
213
215
 
214
216
  # Signal settings
215
217
  @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"]
218
+ @signal_url = ENV['SIGNAL_URL'] || 'https://signal.brainzlab.ai'
219
+ @signal_api_key = ENV.fetch('SIGNAL_API_KEY', nil)
220
+ @signal_master_key = ENV.fetch('SIGNAL_MASTER_KEY', nil)
219
221
  @signal_auto_provision = true
220
222
 
221
223
  # Vault settings
222
224
  @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"]
225
+ @vault_url = ENV['VAULT_URL'] || 'https://vault.brainzlab.ai'
226
+ @vault_api_key = ENV.fetch('VAULT_API_KEY', nil)
227
+ @vault_master_key = ENV.fetch('VAULT_MASTER_KEY', nil)
226
228
  @vault_auto_provision = true
227
229
  @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.)
230
+ @vault_cache_ttl = 300 # 5 minutes
231
+ @vault_auto_load = ENV.fetch('VAULT_AUTO_LOAD', 'false') == 'true' # Auto-load secrets into ENV
232
+ @vault_load_provider_keys = true # Also load provider keys (OpenAI, etc.)
231
233
 
232
234
  # Vision settings (AI browser automation)
233
235
  @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"]
236
+ @vision_url = ENV['VISION_URL'] || 'https://vision.brainzlab.ai'
237
+ @vision_api_key = ENV.fetch('VISION_API_KEY', nil)
238
+ @vision_ingest_key = ENV.fetch('VISION_INGEST_KEY', nil)
239
+ @vision_master_key = ENV.fetch('VISION_MASTER_KEY', nil)
238
240
  @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"
241
+ @vision_default_model = ENV['VISION_DEFAULT_MODEL'] || 'claude-sonnet-4'
242
+ @vision_default_browser_provider = ENV['VISION_DEFAULT_BROWSER_PROVIDER'] || 'local'
241
243
 
242
244
  # Cortex settings (feature flags)
243
245
  @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"]
246
+ @cortex_url = ENV['CORTEX_URL'] || 'https://cortex.brainzlab.ai'
247
+ @cortex_api_key = ENV.fetch('CORTEX_API_KEY', nil)
248
+ @cortex_master_key = ENV.fetch('CORTEX_MASTER_KEY', nil)
247
249
  @cortex_auto_provision = true
248
250
  @cortex_cache_enabled = true
249
- @cortex_cache_ttl = 60 # 1 minute
251
+ @cortex_cache_ttl = 60 # 1 minute
250
252
  @cortex_default_context = {}
251
253
 
252
254
  # Beacon settings (uptime monitoring)
253
255
  @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"]
256
+ @beacon_url = ENV['BEACON_URL'] || 'https://beacon.brainzlab.ai'
257
+ @beacon_api_key = ENV.fetch('BEACON_API_KEY', nil)
258
+ @beacon_master_key = ENV.fetch('BEACON_MASTER_KEY', nil)
257
259
  @beacon_auto_provision = true
258
260
 
259
261
  # Nerve settings (job monitoring)
260
262
  @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"]
263
+ @nerve_url = ENV['NERVE_URL'] || 'https://nerve.brainzlab.ai'
264
+ @nerve_api_key = ENV.fetch('NERVE_API_KEY', nil)
265
+ @nerve_master_key = ENV.fetch('NERVE_MASTER_KEY', nil)
264
266
  @nerve_auto_provision = true
265
267
 
266
268
  # Dendrite settings (AI documentation)
267
269
  @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"]
270
+ @dendrite_url = ENV['DENDRITE_URL'] || 'https://dendrite.brainzlab.ai'
271
+ @dendrite_api_key = ENV.fetch('DENDRITE_API_KEY', nil)
272
+ @dendrite_master_key = ENV.fetch('DENDRITE_MASTER_KEY', nil)
271
273
  @dendrite_auto_provision = true
272
274
 
273
275
  # Sentinel settings (host monitoring)
274
276
  @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"]
277
+ @sentinel_url = ENV['SENTINEL_URL'] || 'https://sentinel.brainzlab.ai'
278
+ @sentinel_api_key = ENV.fetch('SENTINEL_API_KEY', nil)
279
+ @sentinel_agent_key = ENV.fetch('SENTINEL_AGENT_KEY', nil)
280
+ @sentinel_master_key = ENV.fetch('SENTINEL_MASTER_KEY', nil)
279
281
  @sentinel_auto_provision = true
280
282
 
281
283
  # Synapse settings (AI development orchestration)
282
284
  @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"]
285
+ @synapse_url = ENV['SYNAPSE_URL'] || 'https://synapse.brainzlab.ai'
286
+ @synapse_api_key = ENV.fetch('SYNAPSE_API_KEY', nil)
287
+ @synapse_master_key = ENV.fetch('SYNAPSE_MASTER_KEY', nil)
286
288
  @synapse_auto_provision = true
287
289
 
288
290
  # Filtering
@@ -292,26 +294,26 @@ module BrainzLab
292
294
  @logger = nil
293
295
 
294
296
  # 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
297
+ @instrument_http = true # Enable HTTP client instrumentation (Net::HTTP, Faraday, HTTParty)
298
+ @instrument_active_record = true # AR breadcrumbs for Reflex
299
+ @instrument_redis = true # Redis command instrumentation
298
300
  @instrument_sidekiq = true # Sidekiq job instrumentation
299
301
  @instrument_graphql = true # GraphQL query instrumentation
300
302
  @instrument_mongodb = true # MongoDB/Mongoid instrumentation
301
303
  @instrument_elasticsearch = true # Elasticsearch instrumentation
302
304
  @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
305
+ @instrument_delayed_job = true # Delayed::Job instrumentation
306
+ @instrument_grape = true # Grape API instrumentation
307
+ @instrument_solid_queue = true # Solid Queue job instrumentation
308
+ @instrument_good_job = true # GoodJob instrumentation
309
+ @instrument_resque = true # Resque instrumentation
310
+ @instrument_excon = true # Excon HTTP client instrumentation
311
+ @instrument_typhoeus = true # Typhoeus HTTP client instrumentation
312
+ @instrument_dalli = true # Dalli/Memcached instrumentation
313
+ @instrument_aws = true # AWS SDK instrumentation
314
+ @instrument_stripe = true # Stripe API instrumentation
313
315
  @http_ignore_hosts = %w[localhost 127.0.0.1]
314
- @redis_ignore_commands = %w[ping info] # Commands to skip tracking
316
+ @redis_ignore_commands = %w[ping info] # Commands to skip tracking
315
317
 
316
318
  # Log formatter settings
317
319
  @log_formatter_enabled = true
@@ -325,9 +327,9 @@ module BrainzLab
325
327
  @devtools_error_page_enabled = true
326
328
  @devtools_debug_panel_enabled = true
327
329
  @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"
330
+ @devtools_allowed_ips = ['127.0.0.1', '::1', '172.16.0.0/12', '192.168.0.0/16', '10.0.0.0/8']
331
+ @devtools_asset_path = '/__brainzlab__'
332
+ @devtools_panel_position = 'bottom-right'
331
333
  @devtools_expand_by_default = false
332
334
  end
333
335
 
@@ -465,7 +467,7 @@ module BrainzLab
465
467
 
466
468
  # Disable if this is the Recall service itself
467
469
  normalized_app_name = @app_name.to_s.downcase.strip
468
- normalized_app_name != "recall"
470
+ normalized_app_name != 'recall'
469
471
  end
470
472
 
471
473
  # Check if reflex is effectively enabled (considering self-tracking)
@@ -475,7 +477,7 @@ module BrainzLab
475
477
 
476
478
  # Disable if this is the Reflex service itself
477
479
  normalized_app_name = @app_name.to_s.downcase.strip
478
- normalized_app_name != "reflex"
480
+ normalized_app_name != 'reflex'
479
481
  end
480
482
 
481
483
  # Check if pulse is effectively enabled (considering self-tracking)
@@ -485,7 +487,7 @@ module BrainzLab
485
487
 
486
488
  # Disable if this is the Pulse service itself
487
489
  normalized_app_name = @app_name.to_s.downcase.strip
488
- normalized_app_name != "pulse"
490
+ normalized_app_name != 'pulse'
489
491
  end
490
492
 
491
493
  # Check if flux is effectively enabled (considering self-tracking)
@@ -495,7 +497,7 @@ module BrainzLab
495
497
 
496
498
  # Disable if this is the Flux service itself
497
499
  normalized_app_name = @app_name.to_s.downcase.strip
498
- normalized_app_name != "flux"
500
+ normalized_app_name != 'flux'
499
501
  end
500
502
 
501
503
  # Check if signal is effectively enabled (considering self-tracking)
@@ -505,7 +507,7 @@ module BrainzLab
505
507
 
506
508
  # Disable if this is the Signal service itself
507
509
  normalized_app_name = @app_name.to_s.downcase.strip
508
- normalized_app_name != "signal"
510
+ normalized_app_name != 'signal'
509
511
  end
510
512
 
511
513
  def debug_log(message)
@@ -515,7 +517,7 @@ module BrainzLab
515
517
  if logger
516
518
  logger.debug(log_message)
517
519
  else
518
- $stderr.puts(log_message)
520
+ warn(log_message)
519
521
  end
520
522
  end
521
523
 
@@ -523,14 +525,14 @@ module BrainzLab
523
525
 
524
526
  def detect_environment
525
527
  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"]
528
+ return ENV['RACK_ENV'] if ENV['RACK_ENV']
529
+ return ENV['RUBY_ENV'] if ENV['RUBY_ENV']
528
530
 
529
- "development"
531
+ 'development'
530
532
  end
531
533
 
532
534
  def detect_host
533
- require "socket"
535
+ require 'socket'
534
536
  Socket.gethostname
535
537
  rescue StandardError
536
538
  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