fluyenta-ruby 0.1.14

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 (121) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +68 -0
  3. data/LICENSE +11 -0
  4. data/README.md +571 -0
  5. data/lib/brainzlab/beacon/client.rb +227 -0
  6. data/lib/brainzlab/beacon/provisioner.rb +44 -0
  7. data/lib/brainzlab/beacon.rb +215 -0
  8. data/lib/brainzlab/configuration.rb +676 -0
  9. data/lib/brainzlab/context.rb +90 -0
  10. data/lib/brainzlab/cortex/cache.rb +59 -0
  11. data/lib/brainzlab/cortex/client.rb +159 -0
  12. data/lib/brainzlab/cortex/provisioner.rb +49 -0
  13. data/lib/brainzlab/cortex.rb +223 -0
  14. data/lib/brainzlab/debug.rb +305 -0
  15. data/lib/brainzlab/dendrite/client.rb +250 -0
  16. data/lib/brainzlab/dendrite/provisioner.rb +44 -0
  17. data/lib/brainzlab/dendrite.rb +195 -0
  18. data/lib/brainzlab/development/logger.rb +150 -0
  19. data/lib/brainzlab/development/store.rb +121 -0
  20. data/lib/brainzlab/development.rb +72 -0
  21. data/lib/brainzlab/devtools/assets/devtools.css +1329 -0
  22. data/lib/brainzlab/devtools/assets/devtools.js +396 -0
  23. data/lib/brainzlab/devtools/assets/logo.svg +6 -0
  24. data/lib/brainzlab/devtools/assets/templates/debug_panel.html.erb +511 -0
  25. data/lib/brainzlab/devtools/assets/templates/error_page.html.erb +1086 -0
  26. data/lib/brainzlab/devtools/data/collector.rb +248 -0
  27. data/lib/brainzlab/devtools/middleware/asset_server.rb +63 -0
  28. data/lib/brainzlab/devtools/middleware/database_handler.rb +177 -0
  29. data/lib/brainzlab/devtools/middleware/debug_panel.rb +126 -0
  30. data/lib/brainzlab/devtools/middleware/error_page.rb +377 -0
  31. data/lib/brainzlab/devtools/renderers/debug_panel_renderer.rb +159 -0
  32. data/lib/brainzlab/devtools/renderers/error_page_renderer.rb +98 -0
  33. data/lib/brainzlab/devtools.rb +75 -0
  34. data/lib/brainzlab/errors.rb +490 -0
  35. data/lib/brainzlab/flux/buffer.rb +96 -0
  36. data/lib/brainzlab/flux/client.rb +68 -0
  37. data/lib/brainzlab/flux/provisioner.rb +124 -0
  38. data/lib/brainzlab/flux.rb +184 -0
  39. data/lib/brainzlab/instrumentation/action_cable.rb +351 -0
  40. data/lib/brainzlab/instrumentation/action_controller.rb +649 -0
  41. data/lib/brainzlab/instrumentation/action_dispatch.rb +259 -0
  42. data/lib/brainzlab/instrumentation/action_mailbox.rb +197 -0
  43. data/lib/brainzlab/instrumentation/action_mailer.rb +182 -0
  44. data/lib/brainzlab/instrumentation/action_view.rb +380 -0
  45. data/lib/brainzlab/instrumentation/active_job.rb +569 -0
  46. data/lib/brainzlab/instrumentation/active_record.rb +559 -0
  47. data/lib/brainzlab/instrumentation/active_storage.rb +541 -0
  48. data/lib/brainzlab/instrumentation/active_support_cache.rb +730 -0
  49. data/lib/brainzlab/instrumentation/aws.rb +183 -0
  50. data/lib/brainzlab/instrumentation/dalli.rb +108 -0
  51. data/lib/brainzlab/instrumentation/delayed_job.rb +234 -0
  52. data/lib/brainzlab/instrumentation/elasticsearch.rb +209 -0
  53. data/lib/brainzlab/instrumentation/excon.rb +152 -0
  54. data/lib/brainzlab/instrumentation/faraday.rb +181 -0
  55. data/lib/brainzlab/instrumentation/good_job.rb +102 -0
  56. data/lib/brainzlab/instrumentation/grape.rb +293 -0
  57. data/lib/brainzlab/instrumentation/graphql.rb +252 -0
  58. data/lib/brainzlab/instrumentation/httparty.rb +193 -0
  59. data/lib/brainzlab/instrumentation/mongodb.rb +187 -0
  60. data/lib/brainzlab/instrumentation/net_http.rb +114 -0
  61. data/lib/brainzlab/instrumentation/rails_deprecation.rb +139 -0
  62. data/lib/brainzlab/instrumentation/railties.rb +134 -0
  63. data/lib/brainzlab/instrumentation/redis.rb +324 -0
  64. data/lib/brainzlab/instrumentation/resque.rb +114 -0
  65. data/lib/brainzlab/instrumentation/sidekiq.rb +265 -0
  66. data/lib/brainzlab/instrumentation/solid_queue.rb +194 -0
  67. data/lib/brainzlab/instrumentation/stripe.rb +163 -0
  68. data/lib/brainzlab/instrumentation/typhoeus.rb +106 -0
  69. data/lib/brainzlab/instrumentation.rb +360 -0
  70. data/lib/brainzlab/nerve/client.rb +235 -0
  71. data/lib/brainzlab/nerve/provisioner.rb +44 -0
  72. data/lib/brainzlab/nerve.rb +219 -0
  73. data/lib/brainzlab/pulse/client.rb +203 -0
  74. data/lib/brainzlab/pulse/instrumentation.rb +401 -0
  75. data/lib/brainzlab/pulse/propagation.rb +241 -0
  76. data/lib/brainzlab/pulse/provisioner.rb +114 -0
  77. data/lib/brainzlab/pulse/tracer.rb +111 -0
  78. data/lib/brainzlab/pulse.rb +294 -0
  79. data/lib/brainzlab/rails/log_formatter.rb +807 -0
  80. data/lib/brainzlab/rails/log_subscriber.rb +334 -0
  81. data/lib/brainzlab/rails/railtie.rb +606 -0
  82. data/lib/brainzlab/recall/buffer.rb +66 -0
  83. data/lib/brainzlab/recall/client.rb +158 -0
  84. data/lib/brainzlab/recall/logger.rb +116 -0
  85. data/lib/brainzlab/recall/provisioner.rb +130 -0
  86. data/lib/brainzlab/recall.rb +175 -0
  87. data/lib/brainzlab/reflex/breadcrumbs.rb +55 -0
  88. data/lib/brainzlab/reflex/client.rb +150 -0
  89. data/lib/brainzlab/reflex/provisioner.rb +116 -0
  90. data/lib/brainzlab/reflex.rb +421 -0
  91. data/lib/brainzlab/sentinel/client.rb +236 -0
  92. data/lib/brainzlab/sentinel/provisioner.rb +44 -0
  93. data/lib/brainzlab/sentinel.rb +165 -0
  94. data/lib/brainzlab/signal/client.rb +60 -0
  95. data/lib/brainzlab/signal/provisioner.rb +115 -0
  96. data/lib/brainzlab/signal.rb +136 -0
  97. data/lib/brainzlab/synapse/client.rb +308 -0
  98. data/lib/brainzlab/synapse/provisioner.rb +44 -0
  99. data/lib/brainzlab/synapse.rb +270 -0
  100. data/lib/brainzlab/testing/event_store.rb +377 -0
  101. data/lib/brainzlab/testing/helpers.rb +650 -0
  102. data/lib/brainzlab/testing/matchers.rb +391 -0
  103. data/lib/brainzlab/testing.rb +327 -0
  104. data/lib/brainzlab/utilities/circuit_breaker.rb +290 -0
  105. data/lib/brainzlab/utilities/health_check.rb +294 -0
  106. data/lib/brainzlab/utilities/log_formatter.rb +254 -0
  107. data/lib/brainzlab/utilities/rate_limiter.rb +230 -0
  108. data/lib/brainzlab/utilities.rb +17 -0
  109. data/lib/brainzlab/vault/cache.rb +80 -0
  110. data/lib/brainzlab/vault/client.rb +216 -0
  111. data/lib/brainzlab/vault/provisioner.rb +49 -0
  112. data/lib/brainzlab/vault.rb +262 -0
  113. data/lib/brainzlab/version.rb +5 -0
  114. data/lib/brainzlab/vision/client.rb +175 -0
  115. data/lib/brainzlab/vision/provisioner.rb +136 -0
  116. data/lib/brainzlab/vision.rb +155 -0
  117. data/lib/brainzlab-sdk.rb +3 -0
  118. data/lib/brainzlab.rb +306 -0
  119. data/lib/generators/brainzlab/install/install_generator.rb +63 -0
  120. data/lib/generators/brainzlab/install/templates/brainzlab.rb.tt +77 -0
  121. metadata +251 -0
@@ -0,0 +1,676 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BrainzLab
4
+ class Configuration
5
+ LEVELS = %i[debug info warn error fatal].freeze
6
+
7
+ # recall_min_level has a custom setter with validation
8
+ attr_reader :recall_min_level
9
+
10
+ # mode has a custom setter with validation
11
+ attr_reader :mode
12
+
13
+ attr_accessor :enabled,
14
+ :secret_key,
15
+ :environment,
16
+ :service,
17
+ :host,
18
+ :commit,
19
+ :branch,
20
+ :app_name,
21
+ :debug,
22
+ :recall_enabled,
23
+ :recall_url,
24
+ :recall_buffer_size,
25
+ :recall_flush_interval,
26
+ :recall_master_key,
27
+ :recall_auto_provision,
28
+ :reflex_enabled,
29
+ :reflex_url,
30
+ :reflex_api_key,
31
+ :reflex_master_key,
32
+ :reflex_auto_provision,
33
+ :reflex_excluded_exceptions,
34
+ :reflex_before_send,
35
+ :reflex_sample_rate,
36
+ :reflex_fingerprint,
37
+ :pulse_enabled,
38
+ :pulse_url,
39
+ :pulse_api_key,
40
+ :pulse_master_key,
41
+ :pulse_auto_provision,
42
+ :pulse_buffer_size,
43
+ :pulse_flush_interval,
44
+ :pulse_sample_rate,
45
+ :pulse_excluded_paths,
46
+ :flux_enabled,
47
+ :flux_url,
48
+ :flux_api_key,
49
+ :flux_ingest_key,
50
+ :flux_master_key,
51
+ :flux_auto_provision,
52
+ :flux_buffer_size,
53
+ :flux_flush_interval,
54
+ :signal_enabled,
55
+ :signal_url,
56
+ :signal_api_key,
57
+ :signal_ingest_key,
58
+ :signal_master_key,
59
+ :signal_auto_provision,
60
+ :vault_enabled,
61
+ :vault_url,
62
+ :vault_api_key,
63
+ :vault_master_key,
64
+ :vault_auto_provision,
65
+ :vault_cache_enabled,
66
+ :vault_cache_ttl,
67
+ :vault_auto_load,
68
+ :vault_load_provider_keys,
69
+ :vision_enabled,
70
+ :vision_url,
71
+ :vision_api_key,
72
+ :vision_ingest_key,
73
+ :vision_master_key,
74
+ :vision_auto_provision,
75
+ :vision_default_model,
76
+ :vision_default_browser_provider,
77
+ :cortex_enabled,
78
+ :cortex_url,
79
+ :cortex_api_key,
80
+ :cortex_master_key,
81
+ :cortex_auto_provision,
82
+ :cortex_cache_enabled,
83
+ :cortex_cache_ttl,
84
+ :cortex_default_context,
85
+ :beacon_enabled,
86
+ :beacon_url,
87
+ :beacon_api_key,
88
+ :beacon_master_key,
89
+ :beacon_auto_provision,
90
+ :nerve_enabled,
91
+ :nerve_url,
92
+ :nerve_api_key,
93
+ :nerve_master_key,
94
+ :nerve_auto_provision,
95
+ :dendrite_enabled,
96
+ :dendrite_url,
97
+ :dendrite_api_key,
98
+ :dendrite_master_key,
99
+ :dendrite_auto_provision,
100
+ :sentinel_enabled,
101
+ :sentinel_url,
102
+ :sentinel_api_key,
103
+ :sentinel_agent_key,
104
+ :sentinel_master_key,
105
+ :sentinel_auto_provision,
106
+ :synapse_enabled,
107
+ :synapse_url,
108
+ :synapse_api_key,
109
+ :synapse_master_key,
110
+ :synapse_auto_provision,
111
+ :scrub_fields,
112
+ :logger,
113
+ :on_error,
114
+ :on_send,
115
+ :instrument_http,
116
+ :instrument_active_record,
117
+ :instrument_redis,
118
+ :instrument_sidekiq,
119
+ :instrument_graphql,
120
+ :instrument_mongodb,
121
+ :instrument_elasticsearch,
122
+ :instrument_action_controller,
123
+ :instrument_action_view,
124
+ :instrument_action_mailer,
125
+ :instrument_active_job,
126
+ :instrument_active_support_cache,
127
+ :instrument_delayed_job,
128
+ :instrument_grape,
129
+ :instrument_solid_queue,
130
+ :instrument_good_job,
131
+ :instrument_resque,
132
+ :instrument_excon,
133
+ :instrument_typhoeus,
134
+ :instrument_dalli,
135
+ :instrument_aws,
136
+ :instrument_stripe,
137
+ :instrument_active_storage,
138
+ :instrument_action_cable,
139
+ :instrument_action_dispatch,
140
+ :instrument_rails_deprecation,
141
+ :instrument_action_mailbox,
142
+ :instrument_railties,
143
+ :http_ignore_hosts,
144
+ :redis_ignore_commands,
145
+ :log_formatter_enabled,
146
+ :log_formatter_colors,
147
+ :log_formatter_hide_assets,
148
+ :log_formatter_compact_assets,
149
+ :log_formatter_show_params,
150
+ :disable_self_tracking,
151
+ :devtools_enabled,
152
+ :devtools_error_page_enabled,
153
+ :devtools_debug_panel_enabled,
154
+ :devtools_allowed_environments,
155
+ :devtools_allowed_ips,
156
+ :devtools_asset_path,
157
+ :devtools_panel_position,
158
+ :devtools_expand_by_default,
159
+ :rails_instrumentation_handled_externally,
160
+ :development_db_path,
161
+ :development_log_output
162
+
163
+ # Services that should not track themselves to avoid circular dependencies
164
+ SELF_TRACKING_SERVICES = {
165
+ 'recall' => :recall_enabled,
166
+ 'reflex' => :reflex_enabled,
167
+ 'pulse' => :pulse_enabled,
168
+ 'flux' => :flux_enabled,
169
+ 'signal' => :signal_enabled
170
+ }.freeze
171
+
172
+ def initialize
173
+ # SDK enabled flag — set BRAINZLAB_SDK_ENABLED=false to completely disable
174
+ @enabled = ENV.fetch('BRAINZLAB_SDK_ENABLED', 'true') != 'false'
175
+
176
+ # Authentication
177
+ @secret_key = ENV.fetch('BRAINZLAB_SECRET_KEY', nil)
178
+
179
+ # Environment
180
+ @environment = ENV['BRAINZLAB_ENVIRONMENT'] || detect_environment
181
+ @service = ENV.fetch('BRAINZLAB_SERVICE', nil)
182
+ @host = ENV['BRAINZLAB_HOST'] || detect_host
183
+
184
+ # App name for auto-provisioning
185
+ @app_name = ENV.fetch('BRAINZLAB_APP_NAME', nil)
186
+
187
+ # Git context
188
+ @commit = ENV['GIT_COMMIT'] || ENV['COMMIT_SHA'] || detect_git_commit
189
+ @branch = ENV['GIT_BRANCH'] || ENV['BRANCH_NAME'] || detect_git_branch
190
+
191
+ # Debug mode - enables verbose logging
192
+ @debug = ENV['BRAINZLAB_DEBUG'] == 'true'
193
+
194
+ # SDK mode - :production (default) or :development (offline, local storage)
195
+ @mode = ENV['BRAINZLAB_MODE']&.to_sym || :production
196
+
197
+ # Development mode settings
198
+ @development_db_path = ENV['BRAINZLAB_DEV_DB_PATH'] || 'tmp/brainzlab.sqlite3'
199
+ @development_log_output = $stdout
200
+
201
+ # Disable self-tracking - prevents services from tracking to themselves
202
+ # e.g., Recall won't log to itself, Reflex won't track errors to itself
203
+ @disable_self_tracking = ENV.fetch('BRAINZLAB_DISABLE_SELF_TRACKING', 'true') == 'true'
204
+
205
+ # Recall settings
206
+ @recall_enabled = true
207
+ @recall_url = ENV['RECALL_URL'] || detect_product_url('recall')
208
+ @recall_min_level = :debug
209
+ @recall_buffer_size = 50
210
+ @recall_flush_interval = 5
211
+ @recall_master_key = ENV.fetch('RECALL_MASTER_KEY', nil)
212
+ @recall_auto_provision = true
213
+
214
+ # Reflex settings
215
+ @reflex_enabled = true
216
+ @reflex_url = ENV['REFLEX_URL'] || detect_product_url('reflex')
217
+ @reflex_api_key = ENV.fetch('REFLEX_API_KEY', nil)
218
+ @reflex_master_key = ENV.fetch('REFLEX_MASTER_KEY', nil)
219
+ @reflex_auto_provision = true
220
+ @reflex_excluded_exceptions = []
221
+ @reflex_before_send = nil
222
+ @reflex_sample_rate = nil
223
+ @reflex_fingerprint = nil # Custom fingerprint callback
224
+
225
+ # Pulse settings
226
+ @pulse_enabled = true
227
+ @pulse_url = ENV['PULSE_URL'] || detect_product_url('pulse')
228
+ @pulse_api_key = ENV.fetch('PULSE_API_KEY', nil)
229
+ @pulse_master_key = ENV.fetch('PULSE_MASTER_KEY', nil)
230
+ @pulse_auto_provision = true
231
+ @pulse_buffer_size = 50
232
+ @pulse_flush_interval = 5
233
+ @pulse_sample_rate = nil
234
+ @pulse_excluded_paths = %w[/health /ping /up /assets]
235
+
236
+ # Flux settings
237
+ @flux_enabled = true
238
+ @flux_url = ENV['FLUX_URL'] || 'https://flux.brainzlab.ai'
239
+ @flux_api_key = ENV.fetch('FLUX_API_KEY', nil)
240
+ @flux_ingest_key = ENV.fetch('FLUX_INGEST_KEY', nil)
241
+ @flux_master_key = ENV.fetch('FLUX_MASTER_KEY', nil)
242
+ @flux_auto_provision = true
243
+ @flux_buffer_size = 100
244
+ @flux_flush_interval = 5
245
+
246
+ # Signal settings
247
+ @signal_enabled = true
248
+ @signal_url = ENV['SIGNAL_URL'] || detect_product_url('signal')
249
+ @signal_api_key = ENV.fetch('SIGNAL_API_KEY', nil)
250
+ @signal_ingest_key = ENV.fetch('SIGNAL_INGEST_KEY', nil)
251
+ @signal_master_key = ENV.fetch('SIGNAL_MASTER_KEY', nil)
252
+ @signal_auto_provision = true
253
+
254
+ # Vault settings
255
+ @vault_enabled = true
256
+ @vault_url = ENV['VAULT_URL'] || 'https://vault.brainzlab.ai'
257
+ @vault_api_key = ENV.fetch('VAULT_API_KEY', nil)
258
+ @vault_master_key = ENV.fetch('VAULT_MASTER_KEY', nil)
259
+ @vault_auto_provision = true
260
+ @vault_cache_enabled = true
261
+ @vault_cache_ttl = 300 # 5 minutes
262
+ @vault_auto_load = ENV.fetch('VAULT_AUTO_LOAD', 'false') == 'true' # Auto-load secrets into ENV
263
+ @vault_load_provider_keys = true # Also load provider keys (OpenAI, etc.)
264
+
265
+ # Vision settings (AI browser automation)
266
+ @vision_enabled = true
267
+ @vision_url = ENV['VISION_URL'] || 'https://vision.brainzlab.ai'
268
+ @vision_api_key = ENV.fetch('VISION_API_KEY', nil)
269
+ @vision_ingest_key = ENV.fetch('VISION_INGEST_KEY', nil)
270
+ @vision_master_key = ENV.fetch('VISION_MASTER_KEY', nil)
271
+ @vision_auto_provision = true
272
+ @vision_default_model = ENV['VISION_DEFAULT_MODEL'] || 'claude-sonnet-4'
273
+ @vision_default_browser_provider = ENV['VISION_DEFAULT_BROWSER_PROVIDER'] || 'local'
274
+
275
+ # Cortex settings (feature flags)
276
+ @cortex_enabled = true
277
+ @cortex_url = ENV['CORTEX_URL'] || 'https://cortex.brainzlab.ai'
278
+ @cortex_api_key = ENV.fetch('CORTEX_API_KEY', nil)
279
+ @cortex_master_key = ENV.fetch('CORTEX_MASTER_KEY', nil)
280
+ @cortex_auto_provision = true
281
+ @cortex_cache_enabled = true
282
+ @cortex_cache_ttl = 60 # 1 minute
283
+ @cortex_default_context = {}
284
+
285
+ # Beacon settings (uptime monitoring)
286
+ @beacon_enabled = true
287
+ @beacon_url = ENV['BEACON_URL'] || 'https://beacon.brainzlab.ai'
288
+ @beacon_api_key = ENV.fetch('BEACON_API_KEY', nil)
289
+ @beacon_master_key = ENV.fetch('BEACON_MASTER_KEY', nil)
290
+ @beacon_auto_provision = true
291
+
292
+ # Nerve settings (job monitoring)
293
+ @nerve_enabled = true
294
+ @nerve_url = ENV['NERVE_URL'] || 'https://nerve.brainzlab.ai'
295
+ @nerve_api_key = ENV.fetch('NERVE_API_KEY', nil)
296
+ @nerve_master_key = ENV.fetch('NERVE_MASTER_KEY', nil)
297
+ @nerve_auto_provision = true
298
+
299
+ # Dendrite settings (AI documentation)
300
+ @dendrite_enabled = true
301
+ @dendrite_url = ENV['DENDRITE_URL'] || 'https://dendrite.brainzlab.ai'
302
+ @dendrite_api_key = ENV.fetch('DENDRITE_API_KEY', nil)
303
+ @dendrite_master_key = ENV.fetch('DENDRITE_MASTER_KEY', nil)
304
+ @dendrite_auto_provision = true
305
+
306
+ # Sentinel settings (host monitoring)
307
+ @sentinel_enabled = true
308
+ @sentinel_url = ENV['SENTINEL_URL'] || 'https://sentinel.brainzlab.ai'
309
+ @sentinel_api_key = ENV.fetch('SENTINEL_API_KEY', nil)
310
+ @sentinel_agent_key = ENV.fetch('SENTINEL_AGENT_KEY', nil)
311
+ @sentinel_master_key = ENV.fetch('SENTINEL_MASTER_KEY', nil)
312
+ @sentinel_auto_provision = true
313
+
314
+ # Synapse settings (AI development orchestration)
315
+ @synapse_enabled = true
316
+ @synapse_url = ENV['SYNAPSE_URL'] || 'https://synapse.brainzlab.ai'
317
+ @synapse_api_key = ENV.fetch('SYNAPSE_API_KEY', nil)
318
+ @synapse_master_key = ENV.fetch('SYNAPSE_MASTER_KEY', nil)
319
+ @synapse_auto_provision = true
320
+
321
+ # Filtering
322
+ @scrub_fields = %i[password password_confirmation token api_key secret]
323
+
324
+ # Internal logger for debugging SDK issues
325
+ @logger = nil
326
+
327
+ # Debug callbacks
328
+ # Called when an SDK error occurs (lambda/proc receiving error object and context hash)
329
+ @on_error = nil
330
+ # Called before each API request (lambda/proc receiving service, method, path, and payload)
331
+ @on_send = nil
332
+
333
+ # Instrumentation
334
+ @instrument_http = true # Enable HTTP client instrumentation (Net::HTTP, Faraday, HTTParty)
335
+ @instrument_active_record = true # AR breadcrumbs for Reflex
336
+ @instrument_redis = true # Redis command instrumentation
337
+ @instrument_sidekiq = true # Sidekiq job instrumentation
338
+ @instrument_graphql = true # GraphQL query instrumentation
339
+ @instrument_mongodb = true # MongoDB/Mongoid instrumentation
340
+ @instrument_elasticsearch = true # Elasticsearch instrumentation
341
+ @instrument_action_controller = true # ActionController instrumentation (requests, redirects, filters)
342
+ @instrument_action_view = true # ActionView instrumentation (templates, partials, collections)
343
+ @instrument_action_mailer = true # ActionMailer instrumentation
344
+ @instrument_active_job = true # ActiveJob instrumentation (enqueue, perform, retry, discard)
345
+ @instrument_active_support_cache = true # ActiveSupport::Cache instrumentation (read, write, fetch)
346
+ @instrument_delayed_job = true # Delayed::Job instrumentation
347
+ @instrument_grape = true # Grape API instrumentation
348
+ @instrument_solid_queue = true # Solid Queue job instrumentation
349
+ @instrument_good_job = true # GoodJob instrumentation
350
+ @instrument_resque = true # Resque instrumentation
351
+ @instrument_excon = true # Excon HTTP client instrumentation
352
+ @instrument_typhoeus = true # Typhoeus HTTP client instrumentation
353
+ @instrument_dalli = true # Dalli/Memcached instrumentation
354
+ @instrument_aws = true # AWS SDK instrumentation
355
+ @instrument_stripe = true # Stripe API instrumentation
356
+ @instrument_active_storage = true # ActiveStorage instrumentation (uploads, downloads, transforms)
357
+ @instrument_action_cable = true # ActionCable WebSocket instrumentation
358
+ @instrument_action_dispatch = true # ActionDispatch instrumentation (middleware, redirects, requests)
359
+ @instrument_rails_deprecation = true # Rails deprecation warnings tracking
360
+ @instrument_action_mailbox = true # ActionMailbox inbound email processing instrumentation
361
+ @instrument_railties = true # Railties config initializer loading instrumentation
362
+ @http_ignore_hosts = %w[localhost 127.0.0.1]
363
+ @redis_ignore_commands = %w[ping info] # Commands to skip tracking
364
+
365
+ # Log formatter settings
366
+ @log_formatter_enabled = true
367
+ @log_formatter_colors = nil # auto-detect TTY
368
+ @log_formatter_hide_assets = false
369
+ @log_formatter_compact_assets = true
370
+ @log_formatter_show_params = true
371
+
372
+ # DevTools settings (development error page and debug panel)
373
+ @devtools_enabled = true
374
+ @devtools_error_page_enabled = true
375
+ @devtools_debug_panel_enabled = true
376
+ @devtools_allowed_environments = %w[development test]
377
+ @devtools_allowed_ips = ['127.0.0.1', '::1', '172.16.0.0/12', '192.168.0.0/16', '10.0.0.0/8']
378
+ @devtools_asset_path = '/__brainzlab__'
379
+ @devtools_panel_position = 'bottom-right'
380
+ @devtools_expand_by_default = false
381
+
382
+ # Rails instrumentation delegation
383
+ # When true, brainzlab-rails gem handles Rails-specific instrumentation
384
+ # SDK will only install non-Rails instrumentation (HTTP clients, Redis, etc.)
385
+ @rails_instrumentation_handled_externally = false
386
+ end
387
+
388
+ def recall_min_level=(level)
389
+ level = level.to_sym
390
+ unless LEVELS.include?(level)
391
+ raise ValidationError.new(
392
+ "Invalid log level: #{level}",
393
+ hint: "Valid log levels are: #{LEVELS.join(', ')}",
394
+ code: 'invalid_log_level',
395
+ field: 'recall_min_level',
396
+ context: { provided: level, valid_values: LEVELS }
397
+ )
398
+ end
399
+
400
+ @recall_min_level = level
401
+ end
402
+
403
+ MODES = %i[production development].freeze
404
+
405
+ def mode=(mode)
406
+ mode = mode.to_sym
407
+ unless MODES.include?(mode)
408
+ raise ValidationError.new(
409
+ "Invalid mode: #{mode}",
410
+ hint: "Valid modes are: #{MODES.join(', ')}. Use :development for offline mode with local storage.",
411
+ code: 'invalid_mode',
412
+ field: 'mode',
413
+ context: { provided: mode, valid_values: MODES }
414
+ )
415
+ end
416
+
417
+ @mode = mode
418
+ end
419
+
420
+ def development_mode?
421
+ @mode == :development
422
+ end
423
+
424
+ def level_enabled?(level)
425
+ LEVELS.index(level.to_sym) >= LEVELS.index(@recall_min_level)
426
+ end
427
+
428
+ def valid?
429
+ @enabled && !@secret_key.nil? && !@secret_key.empty?
430
+ end
431
+
432
+ def enabled?
433
+ @enabled == true
434
+ end
435
+
436
+ def reflex_valid?
437
+ key = reflex_api_key || secret_key
438
+ !key.nil? && !key.empty?
439
+ end
440
+
441
+ def reflex_auth_key
442
+ reflex_api_key || secret_key
443
+ end
444
+
445
+ def pulse_valid?
446
+ key = pulse_api_key || secret_key
447
+ !key.nil? && !key.empty?
448
+ end
449
+
450
+ def pulse_auth_key
451
+ pulse_api_key || secret_key
452
+ end
453
+
454
+ def flux_valid?
455
+ key = flux_ingest_key || flux_api_key || secret_key
456
+ !key.nil? && !key.empty?
457
+ end
458
+
459
+ def flux_auth_key
460
+ flux_ingest_key || flux_api_key || secret_key
461
+ end
462
+
463
+ def signal_valid?
464
+ key = signal_ingest_key || signal_api_key || secret_key
465
+ !key.nil? && !key.empty?
466
+ end
467
+
468
+ def signal_auth_key
469
+ signal_ingest_key || signal_api_key || secret_key
470
+ end
471
+
472
+ def vault_valid?
473
+ key = vault_api_key || secret_key
474
+ !key.nil? && !key.empty?
475
+ end
476
+
477
+ def vault_auth_key
478
+ vault_api_key || secret_key
479
+ end
480
+
481
+ def vision_valid?
482
+ key = vision_ingest_key || vision_api_key || secret_key
483
+ !key.nil? && !key.empty?
484
+ end
485
+
486
+ def vision_auth_key
487
+ vision_ingest_key || vision_api_key || secret_key
488
+ end
489
+
490
+ def beacon_valid?
491
+ key = beacon_api_key || secret_key
492
+ !key.nil? && !key.empty?
493
+ end
494
+
495
+ def beacon_auth_key
496
+ beacon_api_key || secret_key
497
+ end
498
+
499
+ def nerve_valid?
500
+ key = nerve_api_key || secret_key
501
+ !key.nil? && !key.empty?
502
+ end
503
+
504
+ def nerve_auth_key
505
+ nerve_api_key || secret_key
506
+ end
507
+
508
+ def cortex_valid?
509
+ key = cortex_api_key || secret_key
510
+ !key.nil? && !key.empty?
511
+ end
512
+
513
+ def cortex_auth_key
514
+ cortex_api_key || secret_key
515
+ end
516
+
517
+ def dendrite_valid?
518
+ key = dendrite_api_key || secret_key
519
+ !key.nil? && !key.empty?
520
+ end
521
+
522
+ def dendrite_auth_key
523
+ dendrite_api_key || secret_key
524
+ end
525
+
526
+ def sentinel_valid?
527
+ key = sentinel_api_key || secret_key
528
+ !key.nil? && !key.empty?
529
+ end
530
+
531
+ def sentinel_auth_key
532
+ sentinel_api_key || secret_key
533
+ end
534
+
535
+ def synapse_valid?
536
+ key = synapse_api_key || secret_key
537
+ !key.nil? && !key.empty?
538
+ end
539
+
540
+ def synapse_auth_key
541
+ synapse_api_key || secret_key
542
+ end
543
+
544
+ def debug?
545
+ @debug == true
546
+ end
547
+
548
+ # Returns hostnames of all configured SDK service URLs
549
+ # Used by Net::HTTP instrumentation to skip tracking SDK's own HTTP calls
550
+ def sdk_service_hosts
551
+ @sdk_service_hosts ||= begin
552
+ urls = [
553
+ @recall_url, @reflex_url, @pulse_url, @flux_url,
554
+ @signal_url, @vault_url, @vision_url, @cortex_url,
555
+ @beacon_url, @nerve_url, @dendrite_url, @sentinel_url,
556
+ @synapse_url
557
+ ].compact
558
+
559
+ urls.filter_map { |url| URI.parse(url).host rescue nil }.uniq
560
+ end
561
+ end
562
+
563
+ # Check if recall is effectively enabled (considering self-tracking)
564
+ def recall_effectively_enabled?
565
+ return false unless @enabled
566
+ return false unless @recall_enabled
567
+ return true unless @disable_self_tracking
568
+
569
+ # Disable if this is the Recall service itself
570
+ normalized_app_name = @app_name.to_s.downcase.strip
571
+ normalized_app_name != 'recall'
572
+ end
573
+
574
+ # Check if reflex is effectively enabled (considering self-tracking)
575
+ def reflex_effectively_enabled?
576
+ return false unless @enabled
577
+ return false unless @reflex_enabled
578
+ return true unless @disable_self_tracking
579
+
580
+ # Disable if this is the Reflex service itself
581
+ normalized_app_name = @app_name.to_s.downcase.strip
582
+ normalized_app_name != 'reflex'
583
+ end
584
+
585
+ # Check if pulse is effectively enabled (considering self-tracking)
586
+ def pulse_effectively_enabled?
587
+ return false unless @enabled
588
+ return false unless @pulse_enabled
589
+ return true unless @disable_self_tracking
590
+
591
+ # Disable if this is the Pulse service itself
592
+ normalized_app_name = @app_name.to_s.downcase.strip
593
+ normalized_app_name != 'pulse'
594
+ end
595
+
596
+ # Check if flux is effectively enabled (considering self-tracking)
597
+ def flux_effectively_enabled?
598
+ return false unless @enabled
599
+ return false unless @flux_enabled
600
+ return true unless @disable_self_tracking
601
+
602
+ # Disable if this is the Flux service itself
603
+ normalized_app_name = @app_name.to_s.downcase.strip
604
+ normalized_app_name != 'flux'
605
+ end
606
+
607
+ # Check if signal is effectively enabled (considering self-tracking)
608
+ def signal_effectively_enabled?
609
+ return false unless @enabled
610
+ return false unless @signal_enabled
611
+ return true unless @disable_self_tracking
612
+
613
+ # Disable if this is the Signal service itself
614
+ normalized_app_name = @app_name.to_s.downcase.strip
615
+ normalized_app_name != 'signal'
616
+ end
617
+
618
+ def debug_log(message)
619
+ return unless debug?
620
+
621
+ log_message = "[BrainzLab::Debug] #{message}"
622
+ if logger
623
+ logger.debug(log_message)
624
+ else
625
+ warn(log_message)
626
+ end
627
+ end
628
+
629
+ private
630
+
631
+ def detect_environment
632
+ return ::Rails.env.to_s if defined?(::Rails) && ::Rails.respond_to?(:env)
633
+ return ENV['RACK_ENV'] if ENV['RACK_ENV']
634
+ return ENV['RUBY_ENV'] if ENV['RUBY_ENV']
635
+
636
+ 'development'
637
+ end
638
+
639
+ def detect_host
640
+ require 'socket'
641
+ Socket.gethostname
642
+ rescue StandardError
643
+ nil
644
+ end
645
+
646
+ def detect_git_commit
647
+ result = `git rev-parse HEAD 2>/dev/null`.strip
648
+ result.empty? ? nil : result
649
+ rescue StandardError
650
+ nil
651
+ end
652
+
653
+ def detect_git_branch
654
+ result = `git rev-parse --abbrev-ref HEAD 2>/dev/null`.strip
655
+ result.empty? ? nil : result
656
+ rescue StandardError
657
+ nil
658
+ end
659
+
660
+ def detect_product_url(product)
661
+ # In development, use .localhost domains (works with Traefik)
662
+ # In production, use the real brainzlab.ai domains
663
+ if development?
664
+ "http://#{product}.localhost"
665
+ else
666
+ "https://#{product}.brainzlab.ai"
667
+ end
668
+ end
669
+
670
+ def development?
671
+ @environment == 'development' ||
672
+ ENV['RAILS_ENV'] == 'development' ||
673
+ ENV['RACK_ENV'] == 'development'
674
+ end
675
+ end
676
+ end