brainzlab 0.1.33 → 0.1.35
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.
- checksums.yaml +4 -4
- data/README.md +38 -0
- data/lib/brainzlab/beacon/client.rb +4 -6
- data/lib/brainzlab/configuration.rb +363 -258
- data/lib/brainzlab/cortex/client.rb +4 -6
- data/lib/brainzlab/debug.rb +6 -6
- data/lib/brainzlab/dendrite/client.rb +4 -6
- data/lib/brainzlab/development/logger.rb +2 -2
- data/lib/brainzlab/development/store.rb +2 -4
- data/lib/brainzlab/devtools/middleware/error_page.rb +1 -1
- data/lib/brainzlab/errors.rb +5 -12
- data/lib/brainzlab/instrumentation/action_cable.rb +4 -4
- data/lib/brainzlab/instrumentation/action_controller.rb +12 -12
- data/lib/brainzlab/instrumentation/action_dispatch.rb +1 -1
- data/lib/brainzlab/instrumentation/action_mailbox.rb +7 -13
- data/lib/brainzlab/instrumentation/action_view.rb +29 -33
- data/lib/brainzlab/instrumentation/active_job.rb +6 -10
- data/lib/brainzlab/instrumentation/active_record.rb +53 -25
- data/lib/brainzlab/instrumentation/active_storage.rb +4 -4
- data/lib/brainzlab/instrumentation/active_support_cache.rb +6 -8
- data/lib/brainzlab/instrumentation/aws.rb +10 -7
- data/lib/brainzlab/instrumentation/grape.rb +37 -2
- data/lib/brainzlab/instrumentation/rails_deprecation.rb +1 -1
- data/lib/brainzlab/instrumentation/railties.rb +2 -2
- data/lib/brainzlab/nerve/client.rb +4 -6
- data/lib/brainzlab/pulse/client.rb +1 -1
- data/lib/brainzlab/pulse/explain_capture.rb +123 -0
- data/lib/brainzlab/pulse.rb +6 -1
- data/lib/brainzlab/rails/railtie.rb +1 -3
- data/lib/brainzlab/reflex/client.rb +1 -1
- data/lib/brainzlab/sentinel/client.rb +4 -6
- data/lib/brainzlab/signal/client.rb +16 -2
- data/lib/brainzlab/signal.rb +8 -0
- data/lib/brainzlab/synapse/client.rb +4 -6
- data/lib/brainzlab/testing/event_store.rb +3 -3
- data/lib/brainzlab/testing/matchers.rb +4 -4
- data/lib/brainzlab/testing.rb +5 -3
- data/lib/brainzlab/utilities/route_path_normalizer.rb +91 -0
- data/lib/brainzlab/utilities.rb +1 -0
- data/lib/brainzlab/vault/client.rb +4 -6
- data/lib/brainzlab/version.rb +1 -1
- data/lib/brainzlab/vision/client.rb +3 -3
- data/lib/brainzlab.rb +1 -0
- data/lib/fluyenta-ruby.rb +1 -1
- metadata +3 -1
|
@@ -45,6 +45,9 @@ module BrainzLab
|
|
|
45
45
|
:pulse_sample_tier,
|
|
46
46
|
:pulse_always_keep_slow_ms,
|
|
47
47
|
:pulse_excluded_paths,
|
|
48
|
+
:pulse_explain_enabled,
|
|
49
|
+
:pulse_explain_threshold,
|
|
50
|
+
:pulse_explain_timeout,
|
|
48
51
|
:flux_enabled,
|
|
49
52
|
:flux_url,
|
|
50
53
|
:flux_api_key,
|
|
@@ -196,262 +199,13 @@ module BrainzLab
|
|
|
196
199
|
}.freeze
|
|
197
200
|
|
|
198
201
|
def initialize
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
@environment = ENV['BRAINZLAB_ENVIRONMENT'] || detect_environment
|
|
207
|
-
@service = ENV.fetch('BRAINZLAB_SERVICE', nil)
|
|
208
|
-
@host = ENV['BRAINZLAB_HOST'] || detect_host
|
|
209
|
-
|
|
210
|
-
# App name for auto-provisioning
|
|
211
|
-
@app_name = ENV.fetch('BRAINZLAB_APP_NAME', nil)
|
|
212
|
-
|
|
213
|
-
# Git context
|
|
214
|
-
@commit = ENV['GIT_COMMIT'] || ENV['COMMIT_SHA'] || detect_git_commit
|
|
215
|
-
@branch = ENV['GIT_BRANCH'] || ENV['BRANCH_NAME'] || detect_git_branch
|
|
216
|
-
|
|
217
|
-
# Debug mode - enables verbose logging
|
|
218
|
-
@debug = ENV['BRAINZLAB_DEBUG'] == 'true'
|
|
219
|
-
|
|
220
|
-
# SDK mode - :production (default) or :development (offline, local storage)
|
|
221
|
-
@mode = ENV['BRAINZLAB_MODE']&.to_sym || :production
|
|
222
|
-
|
|
223
|
-
# Development mode settings
|
|
224
|
-
@development_db_path = ENV['BRAINZLAB_DEV_DB_PATH'] || 'tmp/brainzlab.sqlite3'
|
|
225
|
-
@development_log_output = $stdout
|
|
226
|
-
|
|
227
|
-
# Disable self-tracking - prevents services from tracking to themselves
|
|
228
|
-
# e.g., Recall won't log to itself, Reflex won't track errors to itself
|
|
229
|
-
@disable_self_tracking = ENV.fetch('BRAINZLAB_DISABLE_SELF_TRACKING', 'true') == 'true'
|
|
230
|
-
|
|
231
|
-
# Recall settings
|
|
232
|
-
@recall_enabled = true
|
|
233
|
-
@recall_url = ENV['RECALL_URL'] || detect_product_url('recall')
|
|
234
|
-
@recall_min_level = :debug
|
|
235
|
-
@recall_buffer_size = 50
|
|
236
|
-
@recall_flush_interval = 5
|
|
237
|
-
@recall_master_key = ENV.fetch('RECALL_MASTER_KEY', nil)
|
|
238
|
-
@recall_auto_provision = true
|
|
239
|
-
|
|
240
|
-
# Reflex settings
|
|
241
|
-
@reflex_enabled = true
|
|
242
|
-
@reflex_url = ENV['REFLEX_URL'] || detect_product_url('reflex')
|
|
243
|
-
@reflex_api_key = ENV.fetch('REFLEX_API_KEY', nil)
|
|
244
|
-
@reflex_master_key = ENV.fetch('REFLEX_MASTER_KEY', nil)
|
|
245
|
-
@reflex_auto_provision = true
|
|
246
|
-
@reflex_excluded_exceptions = []
|
|
247
|
-
@reflex_before_send = nil
|
|
248
|
-
@reflex_sample_rate = nil
|
|
249
|
-
@reflex_fingerprint = nil # Custom fingerprint callback
|
|
250
|
-
|
|
251
|
-
# Pulse settings
|
|
252
|
-
@pulse_enabled = true
|
|
253
|
-
@pulse_url = ENV['PULSE_URL'] || detect_product_url('pulse')
|
|
254
|
-
@pulse_api_key = ENV.fetch('PULSE_API_KEY', nil)
|
|
255
|
-
@pulse_master_key = ENV.fetch('PULSE_MASTER_KEY', nil)
|
|
256
|
-
@pulse_auto_provision = true
|
|
257
|
-
@pulse_buffer_size = 50
|
|
258
|
-
@pulse_flush_interval = 5
|
|
259
|
-
# Trace sampling. Explicit rate (0.0–1.0) wins; otherwise derived from the
|
|
260
|
-
# tier. Defaults to the "internal" tier so the Brainz fleet samples ~10%
|
|
261
|
-
# (error traces are always kept). Client-facing apps set
|
|
262
|
-
# BRAINZLAB_PULSE_TIER=client (or PULSE_SAMPLE_RATE) to keep everything.
|
|
263
|
-
@pulse_sample_rate = (v = ENV['PULSE_SAMPLE_RATE'] || ENV['BRAINZLAB_PULSE_SAMPLE_RATE']).nil? || v.to_s.strip.empty? ? nil : v.to_f
|
|
264
|
-
@pulse_sample_tier = (ENV['BRAINZLAB_PULSE_TIER'] || 'internal').to_s.strip.downcase
|
|
265
|
-
# Traces at/above this duration (ms) bypass sampling and are ALWAYS kept,
|
|
266
|
-
# so slow requests / N+1s are never sampled away (APM's whole purpose).
|
|
267
|
-
# Set to 0 to disable. Default 1000ms.
|
|
268
|
-
@pulse_always_keep_slow_ms = (ENV['BRAINZLAB_PULSE_ALWAYS_KEEP_SLOW_MS'] || 1000).to_i
|
|
269
|
-
@pulse_excluded_paths = %w[/health /ping /up /assets]
|
|
270
|
-
|
|
271
|
-
# Flux settings
|
|
272
|
-
@flux_enabled = true
|
|
273
|
-
@flux_url = ENV['FLUX_URL'] || 'https://flux.brainzlab.ai'
|
|
274
|
-
@flux_api_key = ENV.fetch('FLUX_API_KEY', nil)
|
|
275
|
-
@flux_ingest_key = ENV.fetch('FLUX_INGEST_KEY', nil)
|
|
276
|
-
@flux_master_key = ENV.fetch('FLUX_MASTER_KEY', nil)
|
|
277
|
-
@flux_auto_provision = true
|
|
278
|
-
@flux_buffer_size = 100
|
|
279
|
-
@flux_flush_interval = 5
|
|
280
|
-
|
|
281
|
-
# Signal settings
|
|
282
|
-
@signal_enabled = true
|
|
283
|
-
@signal_url = ENV['SIGNAL_URL'] || detect_product_url('signal')
|
|
284
|
-
@signal_api_key = ENV.fetch('SIGNAL_API_KEY', nil)
|
|
285
|
-
@signal_ingest_key = ENV.fetch('SIGNAL_INGEST_KEY', nil)
|
|
286
|
-
@signal_master_key = ENV.fetch('SIGNAL_MASTER_KEY', nil)
|
|
287
|
-
@signal_auto_provision = true
|
|
288
|
-
|
|
289
|
-
# Vault settings
|
|
290
|
-
@vault_enabled = true
|
|
291
|
-
@vault_url = ENV['VAULT_URL'] || 'https://vault.brainzlab.ai'
|
|
292
|
-
@vault_api_key = ENV.fetch('VAULT_API_KEY', nil)
|
|
293
|
-
@vault_master_key = ENV.fetch('VAULT_MASTER_KEY', nil)
|
|
294
|
-
@vault_auto_provision = true
|
|
295
|
-
@vault_cache_enabled = true
|
|
296
|
-
@vault_cache_ttl = 300 # 5 minutes
|
|
297
|
-
@vault_auto_load = ENV.fetch('VAULT_AUTO_LOAD', 'false') == 'true' # Auto-load secrets into ENV
|
|
298
|
-
@vault_load_provider_keys = true # Also load provider keys (OpenAI, etc.)
|
|
299
|
-
|
|
300
|
-
# Vision settings (AI browser automation)
|
|
301
|
-
@vision_enabled = true
|
|
302
|
-
@vision_url = ENV['VISION_URL'] || 'https://vision.brainzlab.ai'
|
|
303
|
-
@vision_api_key = ENV.fetch('VISION_API_KEY', nil)
|
|
304
|
-
@vision_ingest_key = ENV.fetch('VISION_INGEST_KEY', nil)
|
|
305
|
-
@vision_master_key = ENV.fetch('VISION_MASTER_KEY', nil)
|
|
306
|
-
@vision_auto_provision = true
|
|
307
|
-
@vision_default_model = ENV['VISION_DEFAULT_MODEL'] || 'claude-sonnet-4'
|
|
308
|
-
@vision_default_browser_provider = ENV['VISION_DEFAULT_BROWSER_PROVIDER'] || 'local'
|
|
309
|
-
|
|
310
|
-
# Cortex settings (feature flags)
|
|
311
|
-
@cortex_enabled = true
|
|
312
|
-
@cortex_url = ENV['CORTEX_URL'] || 'https://cortex.brainzlab.ai'
|
|
313
|
-
@cortex_api_key = ENV.fetch('CORTEX_API_KEY', nil)
|
|
314
|
-
@cortex_master_key = ENV.fetch('CORTEX_MASTER_KEY', nil)
|
|
315
|
-
@cortex_auto_provision = true
|
|
316
|
-
@cortex_cache_enabled = true
|
|
317
|
-
@cortex_cache_ttl = 60 # 1 minute
|
|
318
|
-
@cortex_default_context = {}
|
|
319
|
-
|
|
320
|
-
# Beacon settings (uptime monitoring)
|
|
321
|
-
@beacon_enabled = true
|
|
322
|
-
@beacon_url = ENV['BEACON_URL'] || 'https://beacon.brainzlab.ai'
|
|
323
|
-
@beacon_api_key = ENV.fetch('BEACON_API_KEY', nil)
|
|
324
|
-
@beacon_master_key = ENV.fetch('BEACON_MASTER_KEY', nil)
|
|
325
|
-
@beacon_auto_provision = true
|
|
326
|
-
|
|
327
|
-
# Nerve settings (job monitoring)
|
|
328
|
-
@nerve_enabled = true
|
|
329
|
-
@nerve_url = ENV['NERVE_URL'] || 'https://nerve.brainzlab.ai'
|
|
330
|
-
@nerve_api_key = ENV.fetch('NERVE_API_KEY', nil)
|
|
331
|
-
@nerve_master_key = ENV.fetch('NERVE_MASTER_KEY', nil)
|
|
332
|
-
@nerve_auto_provision = true
|
|
333
|
-
|
|
334
|
-
# Dendrite settings (AI documentation)
|
|
335
|
-
@dendrite_enabled = true
|
|
336
|
-
@dendrite_url = ENV['DENDRITE_URL'] || 'https://dendrite.brainzlab.ai'
|
|
337
|
-
@dendrite_api_key = ENV.fetch('DENDRITE_API_KEY', nil)
|
|
338
|
-
@dendrite_master_key = ENV.fetch('DENDRITE_MASTER_KEY', nil)
|
|
339
|
-
@dendrite_auto_provision = true
|
|
340
|
-
|
|
341
|
-
# Sentinel settings (host monitoring)
|
|
342
|
-
@sentinel_enabled = true
|
|
343
|
-
@sentinel_url = ENV['SENTINEL_URL'] || 'https://sentinel.brainzlab.ai'
|
|
344
|
-
@sentinel_api_key = ENV.fetch('SENTINEL_API_KEY', nil)
|
|
345
|
-
@sentinel_agent_key = ENV.fetch('SENTINEL_AGENT_KEY', nil)
|
|
346
|
-
@sentinel_master_key = ENV.fetch('SENTINEL_MASTER_KEY', nil)
|
|
347
|
-
@sentinel_auto_provision = true
|
|
348
|
-
|
|
349
|
-
# Synapse settings (AI development orchestration)
|
|
350
|
-
@synapse_enabled = true
|
|
351
|
-
@synapse_url = ENV['SYNAPSE_URL'] || 'https://synapse.brainzlab.ai'
|
|
352
|
-
@synapse_api_key = ENV.fetch('SYNAPSE_API_KEY', nil)
|
|
353
|
-
@synapse_master_key = ENV.fetch('SYNAPSE_MASTER_KEY', nil)
|
|
354
|
-
@synapse_auto_provision = true
|
|
355
|
-
|
|
356
|
-
# Filtering
|
|
357
|
-
@scrub_fields = %i[password password_confirmation token api_key secret]
|
|
358
|
-
|
|
359
|
-
# Internal logger for debugging SDK issues
|
|
360
|
-
@logger = nil
|
|
361
|
-
|
|
362
|
-
# Debug callbacks
|
|
363
|
-
# Called when an SDK error occurs (lambda/proc receiving error object and context hash)
|
|
364
|
-
@on_error = nil
|
|
365
|
-
# Called before each API request (lambda/proc receiving service, method, path, and payload)
|
|
366
|
-
@on_send = nil
|
|
367
|
-
|
|
368
|
-
# Instrumentation
|
|
369
|
-
@instrument_http = true # Enable HTTP client instrumentation (Net::HTTP, Faraday, HTTParty)
|
|
370
|
-
@instrument_active_record = true # AR breadcrumbs for Reflex
|
|
371
|
-
@instrument_redis = true # Redis command instrumentation
|
|
372
|
-
@instrument_sidekiq = true # Sidekiq job instrumentation
|
|
373
|
-
@instrument_graphql = true # GraphQL query instrumentation
|
|
374
|
-
@instrument_mongodb = true # MongoDB/Mongoid instrumentation
|
|
375
|
-
@instrument_elasticsearch = true # Elasticsearch instrumentation
|
|
376
|
-
@instrument_action_controller = true # ActionController instrumentation (requests, redirects, filters)
|
|
377
|
-
@instrument_action_view = true # ActionView instrumentation (templates, partials, collections)
|
|
378
|
-
@instrument_action_mailer = true # ActionMailer instrumentation
|
|
379
|
-
@instrument_active_job = true # ActiveJob instrumentation (enqueue, perform, retry, discard)
|
|
380
|
-
@instrument_active_support_cache = true # ActiveSupport::Cache instrumentation (read, write, fetch)
|
|
381
|
-
@instrument_delayed_job = true # Delayed::Job instrumentation
|
|
382
|
-
@instrument_grape = true # Grape API instrumentation
|
|
383
|
-
@instrument_solid_queue = true # Solid Queue job instrumentation
|
|
384
|
-
@instrument_good_job = true # GoodJob instrumentation
|
|
385
|
-
@instrument_resque = true # Resque instrumentation
|
|
386
|
-
@instrument_excon = true # Excon HTTP client instrumentation
|
|
387
|
-
@instrument_typhoeus = true # Typhoeus HTTP client instrumentation
|
|
388
|
-
@instrument_dalli = true # Dalli/Memcached instrumentation
|
|
389
|
-
@instrument_aws = true # AWS SDK instrumentation
|
|
390
|
-
@instrument_stripe = true # Stripe API instrumentation
|
|
391
|
-
@instrument_active_storage = true # ActiveStorage instrumentation (uploads, downloads, transforms)
|
|
392
|
-
@instrument_action_cable = true # ActionCable WebSocket instrumentation
|
|
393
|
-
@instrument_action_dispatch = true # ActionDispatch instrumentation (middleware, redirects, requests)
|
|
394
|
-
@instrument_rails_deprecation = true # Rails deprecation warnings tracking
|
|
395
|
-
@instrument_action_mailbox = true # ActionMailbox inbound email processing instrumentation
|
|
396
|
-
@instrument_railties = true # Railties config initializer loading instrumentation
|
|
397
|
-
@http_ignore_hosts = %w[localhost 127.0.0.1]
|
|
398
|
-
@redis_ignore_commands = %w[ping info] # Commands to skip tracking
|
|
399
|
-
|
|
400
|
-
# ActiveRecord slow-query / N+1 detection — all tunable so a single chatty
|
|
401
|
-
# default can't flood Recall. Slow-query duration is APM data (Pulse already
|
|
402
|
-
# records it), so it defaults to a quiet level (:debug) and a higher threshold.
|
|
403
|
-
@slow_query_threshold = (ENV['BRAINZLAB_SLOW_QUERY_THRESHOLD'] || 500).to_i # ms (was hardcoded 100)
|
|
404
|
-
@very_slow_query_threshold = (ENV['BRAINZLAB_VERY_SLOW_QUERY_THRESHOLD'] || 2000).to_i # ms (was hardcoded 1000)
|
|
405
|
-
@slow_query_log_level = (ENV['BRAINZLAB_SLOW_QUERY_LOG_LEVEL'] || 'debug').to_sym # was :warn → floods
|
|
406
|
-
@very_slow_query_log_level = (ENV['BRAINZLAB_VERY_SLOW_QUERY_LOG_LEVEL'] || 'warn').to_sym
|
|
407
|
-
@n_plus_one_threshold = (ENV['BRAINZLAB_N_PLUS_ONE_THRESHOLD'] || 10).to_i # was hardcoded 5
|
|
408
|
-
@n_plus_one_log_level = (ENV['BRAINZLAB_N_PLUS_ONE_LOG_LEVEL'] || 'debug').to_sym # was :warning
|
|
409
|
-
|
|
410
|
-
# Per-instrumentation slow / very-slow thresholds (ms) — all env-tunable so a
|
|
411
|
-
# single low default can't flood Recall or wrongly escalate normal latency to
|
|
412
|
-
# :error. Defaults preserve prior behaviour EXCEPT cache, which is raised off
|
|
413
|
-
# DB-backed Solid Cache's normal write latency (~50ms paid a DB round-trip and
|
|
414
|
-
# tripped the old VERY_SLOW=50 → thousands of false :error logs/hour).
|
|
415
|
-
@slow_request_threshold = (ENV['BRAINZLAB_SLOW_REQUEST_THRESHOLD'] || 500).to_i
|
|
416
|
-
@very_slow_request_threshold = (ENV['BRAINZLAB_VERY_SLOW_REQUEST_THRESHOLD'] || 2000).to_i
|
|
417
|
-
@slow_cache_threshold = (ENV['BRAINZLAB_SLOW_CACHE_THRESHOLD'] || 100).to_i # was 10
|
|
418
|
-
@very_slow_cache_threshold = (ENV['BRAINZLAB_VERY_SLOW_CACHE_THRESHOLD'] || 500).to_i # was 50 → flooded :error
|
|
419
|
-
@slow_render_threshold = (ENV['BRAINZLAB_SLOW_RENDER_THRESHOLD'] || 50).to_i
|
|
420
|
-
@very_slow_render_threshold = (ENV['BRAINZLAB_VERY_SLOW_RENDER_THRESHOLD'] || 200).to_i
|
|
421
|
-
@slow_storage_threshold = (ENV['BRAINZLAB_SLOW_STORAGE_THRESHOLD'] || 500).to_i
|
|
422
|
-
@very_slow_storage_threshold = (ENV['BRAINZLAB_VERY_SLOW_STORAGE_THRESHOLD'] || 2000).to_i
|
|
423
|
-
@slow_cable_threshold = (ENV['BRAINZLAB_SLOW_CABLE_THRESHOLD'] || 100).to_i
|
|
424
|
-
@very_slow_cable_threshold = (ENV['BRAINZLAB_VERY_SLOW_CABLE_THRESHOLD'] || 500).to_i
|
|
425
|
-
@slow_initializer_threshold = (ENV['BRAINZLAB_SLOW_INITIALIZER_THRESHOLD'] || 100).to_i
|
|
426
|
-
@very_slow_initializer_threshold = (ENV['BRAINZLAB_VERY_SLOW_INITIALIZER_THRESHOLD'] || 500).to_i
|
|
427
|
-
@slow_middleware_threshold = (ENV['BRAINZLAB_SLOW_MIDDLEWARE_THRESHOLD'] || 50).to_i
|
|
428
|
-
@very_slow_middleware_threshold = (ENV['BRAINZLAB_VERY_SLOW_MIDDLEWARE_THRESHOLD'] || 200).to_i
|
|
429
|
-
@slow_mailbox_threshold = (ENV['BRAINZLAB_SLOW_MAILBOX_THRESHOLD'] || 1000).to_i
|
|
430
|
-
@very_slow_mailbox_threshold = (ENV['BRAINZLAB_VERY_SLOW_MAILBOX_THRESHOLD'] || 5000).to_i
|
|
431
|
-
@slow_job_threshold = (ENV['BRAINZLAB_SLOW_JOB_THRESHOLD'] || 5000).to_i
|
|
432
|
-
@very_slow_job_threshold = (ENV['BRAINZLAB_VERY_SLOW_JOB_THRESHOLD'] || 30_000).to_i
|
|
433
|
-
|
|
434
|
-
# Log formatter settings
|
|
435
|
-
@log_formatter_enabled = true
|
|
436
|
-
@log_formatter_colors = nil # auto-detect TTY
|
|
437
|
-
@log_formatter_hide_assets = false
|
|
438
|
-
@log_formatter_compact_assets = true
|
|
439
|
-
@log_formatter_show_params = true
|
|
440
|
-
|
|
441
|
-
# DevTools settings (development error page and debug panel)
|
|
442
|
-
@devtools_enabled = true
|
|
443
|
-
@devtools_error_page_enabled = true
|
|
444
|
-
@devtools_debug_panel_enabled = true
|
|
445
|
-
@devtools_allowed_environments = %w[development test]
|
|
446
|
-
@devtools_allowed_ips = ['127.0.0.1', '::1', '172.16.0.0/12', '192.168.0.0/16', '10.0.0.0/8']
|
|
447
|
-
@devtools_asset_path = '/__brainzlab__'
|
|
448
|
-
@devtools_panel_position = 'bottom-right'
|
|
449
|
-
@devtools_expand_by_default = false
|
|
450
|
-
|
|
451
|
-
# Rails instrumentation delegation
|
|
452
|
-
# When true, brainzlab-rails gem handles Rails-specific instrumentation
|
|
453
|
-
# SDK will only install non-Rails instrumentation (HTTP clients, Redis, etc.)
|
|
454
|
-
@rails_instrumentation_handled_externally = false
|
|
202
|
+
init_core_defaults
|
|
203
|
+
init_observability_defaults
|
|
204
|
+
init_platform_defaults
|
|
205
|
+
init_runtime_defaults
|
|
206
|
+
init_instrumentation_defaults
|
|
207
|
+
init_threshold_defaults
|
|
208
|
+
init_presentation_defaults
|
|
455
209
|
end
|
|
456
210
|
|
|
457
211
|
def recall_min_level=(level)
|
|
@@ -498,6 +252,63 @@ module BrainzLab
|
|
|
498
252
|
@enabled && !@secret_key.nil? && !@secret_key.empty?
|
|
499
253
|
end
|
|
500
254
|
|
|
255
|
+
# Settings validated eagerly by #validate!, grouped by the shape they must
|
|
256
|
+
# have. Kept as data so adding a setting is a one-line change here rather
|
|
257
|
+
# than another branch in the validation logic.
|
|
258
|
+
SAMPLE_RATE_SETTINGS = %i[pulse_sample_rate reflex_sample_rate].freeze
|
|
259
|
+
|
|
260
|
+
POSITIVE_INTEGER_SETTINGS = %i[
|
|
261
|
+
recall_buffer_size recall_flush_interval
|
|
262
|
+
pulse_buffer_size pulse_flush_interval
|
|
263
|
+
flux_buffer_size flux_flush_interval
|
|
264
|
+
pulse_explain_timeout
|
|
265
|
+
].freeze
|
|
266
|
+
|
|
267
|
+
NON_NEGATIVE_NUMBER_SETTINGS = %i[
|
|
268
|
+
pulse_always_keep_slow_ms
|
|
269
|
+
slow_query_threshold very_slow_query_threshold
|
|
270
|
+
slow_request_threshold very_slow_request_threshold
|
|
271
|
+
n_plus_one_threshold pulse_explain_threshold
|
|
272
|
+
].freeze
|
|
273
|
+
|
|
274
|
+
# Validate the configuration and raise on anything that would misbehave
|
|
275
|
+
# silently at runtime. Called by BrainzLab.configure once the user's block
|
|
276
|
+
# has been applied, so a typo surfaces at boot rather than as missing
|
|
277
|
+
# telemetry days later.
|
|
278
|
+
#
|
|
279
|
+
# @return [Configuration] self, when every setting is valid
|
|
280
|
+
# @raise [ConfigurationError] listing every invalid setting at once
|
|
281
|
+
def validate!
|
|
282
|
+
problems = []
|
|
283
|
+
|
|
284
|
+
SAMPLE_RATE_SETTINGS.each do |setting|
|
|
285
|
+
value = public_send(setting)
|
|
286
|
+
next if value.nil? # nil means "fall back to the tier default"
|
|
287
|
+
|
|
288
|
+
problems << "#{setting} must be a number between 0 and 1 (got #{value.inspect})" unless value.is_a?(Numeric) && value.between?(0, 1)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
POSITIVE_INTEGER_SETTINGS.each do |setting|
|
|
292
|
+
value = public_send(setting)
|
|
293
|
+
problems << "#{setting} must be a positive number (got #{value.inspect})" unless positive_number?(value)
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
NON_NEGATIVE_NUMBER_SETTINGS.each do |setting|
|
|
297
|
+
value = public_send(setting)
|
|
298
|
+
problems << "#{setting} must be a non-negative number (got #{value.inspect})" unless value.is_a?(Numeric) && !value.negative?
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
return self if problems.empty?
|
|
302
|
+
|
|
303
|
+
raise ConfigurationError.new(
|
|
304
|
+
"Invalid BrainzLab configuration: #{problems.join('; ')}",
|
|
305
|
+
hint: 'Fix these values in your BrainzLab.configure block or the matching environment variables. ' \
|
|
306
|
+
'Sample rates are fractions (0.5 = 50%), not percentages.',
|
|
307
|
+
code: 'invalid_configuration',
|
|
308
|
+
context: { problems: problems }
|
|
309
|
+
)
|
|
310
|
+
end
|
|
311
|
+
|
|
501
312
|
def enabled?
|
|
502
313
|
@enabled == true
|
|
503
314
|
end
|
|
@@ -526,7 +337,7 @@ module BrainzLab
|
|
|
526
337
|
PULSE_TIER_SAMPLE_RATES = {
|
|
527
338
|
'internal' => 0.1,
|
|
528
339
|
'standard' => 0.5,
|
|
529
|
-
'client'
|
|
340
|
+
'client' => 1.0,
|
|
530
341
|
'critical' => 1.0
|
|
531
342
|
}.freeze
|
|
532
343
|
|
|
@@ -642,7 +453,11 @@ module BrainzLab
|
|
|
642
453
|
@synapse_url
|
|
643
454
|
].compact
|
|
644
455
|
|
|
645
|
-
urls.filter_map
|
|
456
|
+
urls.filter_map do |url|
|
|
457
|
+
URI.parse(url).host
|
|
458
|
+
rescue StandardError
|
|
459
|
+
nil
|
|
460
|
+
end.uniq
|
|
646
461
|
end
|
|
647
462
|
end
|
|
648
463
|
|
|
@@ -714,6 +529,296 @@ module BrainzLab
|
|
|
714
529
|
|
|
715
530
|
private
|
|
716
531
|
|
|
532
|
+
# Core identity: enablement, auth, environment, git context, SDK mode.
|
|
533
|
+
def init_core_defaults
|
|
534
|
+
# SDK enabled flag — set BRAINZLAB_SDK_ENABLED=false to completely disable
|
|
535
|
+
@enabled = ENV.fetch('BRAINZLAB_SDK_ENABLED', 'true') != 'false'
|
|
536
|
+
|
|
537
|
+
# Authentication
|
|
538
|
+
@secret_key = ENV.fetch('BRAINZLAB_SECRET_KEY', nil)
|
|
539
|
+
|
|
540
|
+
# Environment
|
|
541
|
+
@environment = ENV['BRAINZLAB_ENVIRONMENT'] || detect_environment
|
|
542
|
+
@service = ENV.fetch('BRAINZLAB_SERVICE', nil)
|
|
543
|
+
@host = ENV['BRAINZLAB_HOST'] || detect_host
|
|
544
|
+
|
|
545
|
+
# App name for auto-provisioning
|
|
546
|
+
@app_name = ENV.fetch('BRAINZLAB_APP_NAME', nil)
|
|
547
|
+
|
|
548
|
+
# Git context
|
|
549
|
+
@commit = ENV['GIT_COMMIT'] || ENV['COMMIT_SHA'] || detect_git_commit
|
|
550
|
+
@branch = ENV['GIT_BRANCH'] || ENV['BRANCH_NAME'] || detect_git_branch
|
|
551
|
+
|
|
552
|
+
# Debug mode - enables verbose logging
|
|
553
|
+
@debug = ENV['BRAINZLAB_DEBUG'] == 'true'
|
|
554
|
+
|
|
555
|
+
# SDK mode - :production (default) or :development (offline, local storage)
|
|
556
|
+
@mode = ENV['BRAINZLAB_MODE']&.to_sym || :production
|
|
557
|
+
|
|
558
|
+
# Development mode settings
|
|
559
|
+
@development_db_path = ENV['BRAINZLAB_DEV_DB_PATH'] || 'tmp/brainzlab.sqlite3'
|
|
560
|
+
@development_log_output = $stdout
|
|
561
|
+
|
|
562
|
+
# Disable self-tracking - prevents services from tracking to themselves
|
|
563
|
+
# e.g., Recall won't log to itself, Reflex won't track errors to itself
|
|
564
|
+
@disable_self_tracking = ENV.fetch('BRAINZLAB_DISABLE_SELF_TRACKING', 'true') == 'true'
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
# The five observability products: Recall, Reflex, Pulse, Flux, Signal.
|
|
568
|
+
def init_observability_defaults
|
|
569
|
+
# Recall settings
|
|
570
|
+
@recall_enabled = true
|
|
571
|
+
@recall_url = ENV['RECALL_URL'] || detect_product_url('recall')
|
|
572
|
+
@recall_min_level = :debug
|
|
573
|
+
@recall_buffer_size = 50
|
|
574
|
+
@recall_flush_interval = 5
|
|
575
|
+
@recall_master_key = ENV.fetch('RECALL_MASTER_KEY', nil)
|
|
576
|
+
@recall_auto_provision = true
|
|
577
|
+
|
|
578
|
+
# Reflex settings
|
|
579
|
+
@reflex_enabled = true
|
|
580
|
+
@reflex_url = ENV['REFLEX_URL'] || detect_product_url('reflex')
|
|
581
|
+
@reflex_api_key = ENV.fetch('REFLEX_API_KEY', nil)
|
|
582
|
+
@reflex_master_key = ENV.fetch('REFLEX_MASTER_KEY', nil)
|
|
583
|
+
@reflex_auto_provision = true
|
|
584
|
+
@reflex_excluded_exceptions = []
|
|
585
|
+
@reflex_before_send = nil
|
|
586
|
+
@reflex_sample_rate = nil
|
|
587
|
+
@reflex_fingerprint = nil # Custom fingerprint callback
|
|
588
|
+
|
|
589
|
+
# Pulse settings
|
|
590
|
+
@pulse_enabled = true
|
|
591
|
+
@pulse_url = ENV['PULSE_URL'] || detect_product_url('pulse')
|
|
592
|
+
@pulse_api_key = ENV.fetch('PULSE_API_KEY', nil)
|
|
593
|
+
@pulse_master_key = ENV.fetch('PULSE_MASTER_KEY', nil)
|
|
594
|
+
@pulse_auto_provision = true
|
|
595
|
+
@pulse_buffer_size = 50
|
|
596
|
+
@pulse_flush_interval = 5
|
|
597
|
+
# Trace sampling. Explicit rate (0.0–1.0) wins; otherwise derived from the
|
|
598
|
+
# tier. Defaults to the "internal" tier so the Brainz fleet samples ~10%
|
|
599
|
+
# (error traces are always kept). Client-facing apps set
|
|
600
|
+
# BRAINZLAB_PULSE_TIER=client (or PULSE_SAMPLE_RATE) to keep everything.
|
|
601
|
+
@pulse_sample_rate = (v = ENV['PULSE_SAMPLE_RATE'] || ENV.fetch('BRAINZLAB_PULSE_SAMPLE_RATE', nil)).nil? || v.to_s.strip.empty? ? nil : v.to_f
|
|
602
|
+
@pulse_sample_tier = (ENV['BRAINZLAB_PULSE_TIER'] || 'internal').to_s.strip.downcase
|
|
603
|
+
# Traces at/above this duration (ms) bypass sampling and are ALWAYS kept,
|
|
604
|
+
# so slow requests / N+1s are never sampled away (APM's whole purpose).
|
|
605
|
+
# Set to 0 to disable. Default 1000ms.
|
|
606
|
+
@pulse_always_keep_slow_ms = (ENV['BRAINZLAB_PULSE_ALWAYS_KEEP_SLOW_MS'] || 1000).to_i
|
|
607
|
+
@pulse_excluded_paths = %w[/health /ping /up /assets]
|
|
608
|
+
|
|
609
|
+
# Flux settings
|
|
610
|
+
@flux_enabled = true
|
|
611
|
+
@flux_url = ENV['FLUX_URL'] || 'https://flux.brainzlab.ai'
|
|
612
|
+
@flux_api_key = ENV.fetch('FLUX_API_KEY', nil)
|
|
613
|
+
@flux_ingest_key = ENV.fetch('FLUX_INGEST_KEY', nil)
|
|
614
|
+
@flux_master_key = ENV.fetch('FLUX_MASTER_KEY', nil)
|
|
615
|
+
@flux_auto_provision = true
|
|
616
|
+
@flux_buffer_size = 100
|
|
617
|
+
@flux_flush_interval = 5
|
|
618
|
+
|
|
619
|
+
# Signal settings
|
|
620
|
+
@signal_enabled = true
|
|
621
|
+
@signal_url = ENV['SIGNAL_URL'] || detect_product_url('signal')
|
|
622
|
+
@signal_api_key = ENV.fetch('SIGNAL_API_KEY', nil)
|
|
623
|
+
@signal_ingest_key = ENV.fetch('SIGNAL_INGEST_KEY', nil)
|
|
624
|
+
@signal_master_key = ENV.fetch('SIGNAL_MASTER_KEY', nil)
|
|
625
|
+
@signal_auto_provision = true
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
# The platform services: Vault, Vision, Cortex, Beacon, Nerve, Dendrite, Sentinel, Synapse.
|
|
629
|
+
def init_platform_defaults
|
|
630
|
+
# Vault settings
|
|
631
|
+
@vault_enabled = true
|
|
632
|
+
@vault_url = ENV['VAULT_URL'] || 'https://vault.brainzlab.ai'
|
|
633
|
+
@vault_api_key = ENV.fetch('VAULT_API_KEY', nil)
|
|
634
|
+
@vault_master_key = ENV.fetch('VAULT_MASTER_KEY', nil)
|
|
635
|
+
@vault_auto_provision = true
|
|
636
|
+
@vault_cache_enabled = true
|
|
637
|
+
@vault_cache_ttl = 300 # 5 minutes
|
|
638
|
+
@vault_auto_load = ENV.fetch('VAULT_AUTO_LOAD', 'false') == 'true' # Auto-load secrets into ENV
|
|
639
|
+
@vault_load_provider_keys = true # Also load provider keys (OpenAI, etc.)
|
|
640
|
+
|
|
641
|
+
# Vision settings (AI browser automation)
|
|
642
|
+
@vision_enabled = true
|
|
643
|
+
@vision_url = ENV['VISION_URL'] || 'https://vision.brainzlab.ai'
|
|
644
|
+
@vision_api_key = ENV.fetch('VISION_API_KEY', nil)
|
|
645
|
+
@vision_ingest_key = ENV.fetch('VISION_INGEST_KEY', nil)
|
|
646
|
+
@vision_master_key = ENV.fetch('VISION_MASTER_KEY', nil)
|
|
647
|
+
@vision_auto_provision = true
|
|
648
|
+
@vision_default_model = ENV['VISION_DEFAULT_MODEL'] || 'claude-sonnet-4'
|
|
649
|
+
@vision_default_browser_provider = ENV['VISION_DEFAULT_BROWSER_PROVIDER'] || 'local'
|
|
650
|
+
|
|
651
|
+
# Cortex settings (feature flags)
|
|
652
|
+
@cortex_enabled = true
|
|
653
|
+
@cortex_url = ENV['CORTEX_URL'] || 'https://cortex.brainzlab.ai'
|
|
654
|
+
@cortex_api_key = ENV.fetch('CORTEX_API_KEY', nil)
|
|
655
|
+
@cortex_master_key = ENV.fetch('CORTEX_MASTER_KEY', nil)
|
|
656
|
+
@cortex_auto_provision = true
|
|
657
|
+
@cortex_cache_enabled = true
|
|
658
|
+
@cortex_cache_ttl = 60 # 1 minute
|
|
659
|
+
@cortex_default_context = {}
|
|
660
|
+
|
|
661
|
+
# Beacon settings (uptime monitoring)
|
|
662
|
+
@beacon_enabled = true
|
|
663
|
+
@beacon_url = ENV['BEACON_URL'] || 'https://beacon.brainzlab.ai'
|
|
664
|
+
@beacon_api_key = ENV.fetch('BEACON_API_KEY', nil)
|
|
665
|
+
@beacon_master_key = ENV.fetch('BEACON_MASTER_KEY', nil)
|
|
666
|
+
@beacon_auto_provision = true
|
|
667
|
+
|
|
668
|
+
# Nerve settings (job monitoring)
|
|
669
|
+
@nerve_enabled = true
|
|
670
|
+
@nerve_url = ENV['NERVE_URL'] || 'https://nerve.brainzlab.ai'
|
|
671
|
+
@nerve_api_key = ENV.fetch('NERVE_API_KEY', nil)
|
|
672
|
+
@nerve_master_key = ENV.fetch('NERVE_MASTER_KEY', nil)
|
|
673
|
+
@nerve_auto_provision = true
|
|
674
|
+
|
|
675
|
+
# Dendrite settings (AI documentation)
|
|
676
|
+
@dendrite_enabled = true
|
|
677
|
+
@dendrite_url = ENV['DENDRITE_URL'] || 'https://dendrite.brainzlab.ai'
|
|
678
|
+
@dendrite_api_key = ENV.fetch('DENDRITE_API_KEY', nil)
|
|
679
|
+
@dendrite_master_key = ENV.fetch('DENDRITE_MASTER_KEY', nil)
|
|
680
|
+
@dendrite_auto_provision = true
|
|
681
|
+
|
|
682
|
+
# Sentinel settings (host monitoring)
|
|
683
|
+
@sentinel_enabled = true
|
|
684
|
+
@sentinel_url = ENV['SENTINEL_URL'] || 'https://sentinel.brainzlab.ai'
|
|
685
|
+
@sentinel_api_key = ENV.fetch('SENTINEL_API_KEY', nil)
|
|
686
|
+
@sentinel_agent_key = ENV.fetch('SENTINEL_AGENT_KEY', nil)
|
|
687
|
+
@sentinel_master_key = ENV.fetch('SENTINEL_MASTER_KEY', nil)
|
|
688
|
+
@sentinel_auto_provision = true
|
|
689
|
+
|
|
690
|
+
# Synapse settings (AI development orchestration)
|
|
691
|
+
@synapse_enabled = true
|
|
692
|
+
@synapse_url = ENV['SYNAPSE_URL'] || 'https://synapse.brainzlab.ai'
|
|
693
|
+
@synapse_api_key = ENV.fetch('SYNAPSE_API_KEY', nil)
|
|
694
|
+
@synapse_master_key = ENV.fetch('SYNAPSE_MASTER_KEY', nil)
|
|
695
|
+
@synapse_auto_provision = true
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
# Scrubbing, internal logger and debug callbacks.
|
|
699
|
+
def init_runtime_defaults
|
|
700
|
+
# Filtering
|
|
701
|
+
@scrub_fields = %i[password password_confirmation token api_key secret]
|
|
702
|
+
|
|
703
|
+
# Internal logger for debugging SDK issues
|
|
704
|
+
@logger = nil
|
|
705
|
+
|
|
706
|
+
# Debug callbacks
|
|
707
|
+
# Called when an SDK error occurs (lambda/proc receiving error object and context hash)
|
|
708
|
+
@on_error = nil
|
|
709
|
+
# Called before each API request (lambda/proc receiving service, method, path, and payload)
|
|
710
|
+
@on_send = nil
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
# Which integrations auto-instrument, and what they ignore.
|
|
714
|
+
def init_instrumentation_defaults
|
|
715
|
+
# Instrumentation
|
|
716
|
+
@instrument_http = true # Enable HTTP client instrumentation (Net::HTTP, Faraday, HTTParty)
|
|
717
|
+
@instrument_active_record = true # AR breadcrumbs for Reflex
|
|
718
|
+
@instrument_redis = true # Redis command instrumentation
|
|
719
|
+
@instrument_sidekiq = true # Sidekiq job instrumentation
|
|
720
|
+
@instrument_graphql = true # GraphQL query instrumentation
|
|
721
|
+
@instrument_mongodb = true # MongoDB/Mongoid instrumentation
|
|
722
|
+
@instrument_elasticsearch = true # Elasticsearch instrumentation
|
|
723
|
+
@instrument_action_controller = true # ActionController instrumentation (requests, redirects, filters)
|
|
724
|
+
@instrument_action_view = true # ActionView instrumentation (templates, partials, collections)
|
|
725
|
+
@instrument_action_mailer = true # ActionMailer instrumentation
|
|
726
|
+
@instrument_active_job = true # ActiveJob instrumentation (enqueue, perform, retry, discard)
|
|
727
|
+
@instrument_active_support_cache = true # ActiveSupport::Cache instrumentation (read, write, fetch)
|
|
728
|
+
@instrument_delayed_job = true # Delayed::Job instrumentation
|
|
729
|
+
@instrument_grape = true # Grape API instrumentation
|
|
730
|
+
@instrument_solid_queue = true # Solid Queue job instrumentation
|
|
731
|
+
@instrument_good_job = true # GoodJob instrumentation
|
|
732
|
+
@instrument_resque = true # Resque instrumentation
|
|
733
|
+
@instrument_excon = true # Excon HTTP client instrumentation
|
|
734
|
+
@instrument_typhoeus = true # Typhoeus HTTP client instrumentation
|
|
735
|
+
@instrument_dalli = true # Dalli/Memcached instrumentation
|
|
736
|
+
@instrument_aws = true # AWS SDK instrumentation
|
|
737
|
+
@instrument_stripe = true # Stripe API instrumentation
|
|
738
|
+
@instrument_active_storage = true # ActiveStorage instrumentation (uploads, downloads, transforms)
|
|
739
|
+
@instrument_action_cable = true # ActionCable WebSocket instrumentation
|
|
740
|
+
@instrument_action_dispatch = true # ActionDispatch instrumentation (middleware, redirects, requests)
|
|
741
|
+
@instrument_rails_deprecation = true # Rails deprecation warnings tracking
|
|
742
|
+
@instrument_action_mailbox = true # ActionMailbox inbound email processing instrumentation
|
|
743
|
+
@instrument_railties = true # Railties config initializer loading instrumentation
|
|
744
|
+
@http_ignore_hosts = %w[localhost 127.0.0.1]
|
|
745
|
+
@redis_ignore_commands = %w[ping info] # Commands to skip tracking
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
# Slow / very-slow thresholds and N+1 detection, all env-tunable.
|
|
749
|
+
def init_threshold_defaults
|
|
750
|
+
# ActiveRecord slow-query / N+1 detection — all tunable so a single chatty
|
|
751
|
+
# default can't flood Recall. Slow-query duration is APM data (Pulse already
|
|
752
|
+
# records it), so it defaults to a quiet level (:debug) and a higher threshold.
|
|
753
|
+
@slow_query_threshold = (ENV['BRAINZLAB_SLOW_QUERY_THRESHOLD'] || 500).to_i # ms (was hardcoded 100)
|
|
754
|
+
|
|
755
|
+
# Query plan capture. Off by default: it issues an extra (read-only)
|
|
756
|
+
# EXPLAIN against the app's own database, so an app opts in deliberately.
|
|
757
|
+
# Threshold defaults to the slow query threshold — a fast query has no
|
|
758
|
+
# plan worth looking at.
|
|
759
|
+
@pulse_explain_enabled = ENV['BRAINZLAB_PULSE_EXPLAIN_ENABLED'] == 'true'
|
|
760
|
+
@pulse_explain_threshold = (ENV['BRAINZLAB_PULSE_EXPLAIN_THRESHOLD'] || @slow_query_threshold).to_i
|
|
761
|
+
@pulse_explain_timeout = (ENV['BRAINZLAB_PULSE_EXPLAIN_TIMEOUT'] || 2).to_i
|
|
762
|
+
@very_slow_query_threshold = (ENV['BRAINZLAB_VERY_SLOW_QUERY_THRESHOLD'] || 2000).to_i # ms (was hardcoded 1000)
|
|
763
|
+
@slow_query_log_level = (ENV['BRAINZLAB_SLOW_QUERY_LOG_LEVEL'] || 'debug').to_sym # was :warn → floods
|
|
764
|
+
@very_slow_query_log_level = (ENV['BRAINZLAB_VERY_SLOW_QUERY_LOG_LEVEL'] || 'warn').to_sym
|
|
765
|
+
@n_plus_one_threshold = (ENV['BRAINZLAB_N_PLUS_ONE_THRESHOLD'] || 10).to_i # was hardcoded 5
|
|
766
|
+
@n_plus_one_log_level = (ENV['BRAINZLAB_N_PLUS_ONE_LOG_LEVEL'] || 'debug').to_sym # was :warning
|
|
767
|
+
|
|
768
|
+
# Per-instrumentation slow / very-slow thresholds (ms) — all env-tunable so a
|
|
769
|
+
# single low default can't flood Recall or wrongly escalate normal latency to
|
|
770
|
+
# :error. Defaults preserve prior behaviour EXCEPT cache, which is raised off
|
|
771
|
+
# DB-backed Solid Cache's normal write latency (~50ms paid a DB round-trip and
|
|
772
|
+
# tripped the old VERY_SLOW=50 → thousands of false :error logs/hour).
|
|
773
|
+
@slow_request_threshold = (ENV['BRAINZLAB_SLOW_REQUEST_THRESHOLD'] || 500).to_i
|
|
774
|
+
@very_slow_request_threshold = (ENV['BRAINZLAB_VERY_SLOW_REQUEST_THRESHOLD'] || 2000).to_i
|
|
775
|
+
@slow_cache_threshold = (ENV['BRAINZLAB_SLOW_CACHE_THRESHOLD'] || 100).to_i # was 10
|
|
776
|
+
@very_slow_cache_threshold = (ENV['BRAINZLAB_VERY_SLOW_CACHE_THRESHOLD'] || 500).to_i # was 50 → flooded :error
|
|
777
|
+
@slow_render_threshold = (ENV['BRAINZLAB_SLOW_RENDER_THRESHOLD'] || 50).to_i
|
|
778
|
+
@very_slow_render_threshold = (ENV['BRAINZLAB_VERY_SLOW_RENDER_THRESHOLD'] || 200).to_i
|
|
779
|
+
@slow_storage_threshold = (ENV['BRAINZLAB_SLOW_STORAGE_THRESHOLD'] || 500).to_i
|
|
780
|
+
@very_slow_storage_threshold = (ENV['BRAINZLAB_VERY_SLOW_STORAGE_THRESHOLD'] || 2000).to_i
|
|
781
|
+
@slow_cable_threshold = (ENV['BRAINZLAB_SLOW_CABLE_THRESHOLD'] || 100).to_i
|
|
782
|
+
@very_slow_cable_threshold = (ENV['BRAINZLAB_VERY_SLOW_CABLE_THRESHOLD'] || 500).to_i
|
|
783
|
+
@slow_initializer_threshold = (ENV['BRAINZLAB_SLOW_INITIALIZER_THRESHOLD'] || 100).to_i
|
|
784
|
+
@very_slow_initializer_threshold = (ENV['BRAINZLAB_VERY_SLOW_INITIALIZER_THRESHOLD'] || 500).to_i
|
|
785
|
+
@slow_middleware_threshold = (ENV['BRAINZLAB_SLOW_MIDDLEWARE_THRESHOLD'] || 50).to_i
|
|
786
|
+
@very_slow_middleware_threshold = (ENV['BRAINZLAB_VERY_SLOW_MIDDLEWARE_THRESHOLD'] || 200).to_i
|
|
787
|
+
@slow_mailbox_threshold = (ENV['BRAINZLAB_SLOW_MAILBOX_THRESHOLD'] || 1000).to_i
|
|
788
|
+
@very_slow_mailbox_threshold = (ENV['BRAINZLAB_VERY_SLOW_MAILBOX_THRESHOLD'] || 5000).to_i
|
|
789
|
+
@slow_job_threshold = (ENV['BRAINZLAB_SLOW_JOB_THRESHOLD'] || 5000).to_i
|
|
790
|
+
@very_slow_job_threshold = (ENV['BRAINZLAB_VERY_SLOW_JOB_THRESHOLD'] || 30_000).to_i
|
|
791
|
+
end
|
|
792
|
+
|
|
793
|
+
# Log formatter, DevTools and Rails delegation.
|
|
794
|
+
def init_presentation_defaults
|
|
795
|
+
# Log formatter settings
|
|
796
|
+
@log_formatter_enabled = true
|
|
797
|
+
@log_formatter_colors = nil # auto-detect TTY
|
|
798
|
+
@log_formatter_hide_assets = false
|
|
799
|
+
@log_formatter_compact_assets = true
|
|
800
|
+
@log_formatter_show_params = true
|
|
801
|
+
|
|
802
|
+
# DevTools settings (development error page and debug panel)
|
|
803
|
+
@devtools_enabled = true
|
|
804
|
+
@devtools_error_page_enabled = true
|
|
805
|
+
@devtools_debug_panel_enabled = true
|
|
806
|
+
@devtools_allowed_environments = %w[development test]
|
|
807
|
+
@devtools_allowed_ips = ['127.0.0.1', '::1', '172.16.0.0/12', '192.168.0.0/16', '10.0.0.0/8']
|
|
808
|
+
@devtools_asset_path = '/__brainzlab__'
|
|
809
|
+
@devtools_panel_position = 'bottom-right'
|
|
810
|
+
@devtools_expand_by_default = false
|
|
811
|
+
|
|
812
|
+
# Rails instrumentation delegation
|
|
813
|
+
# When true, brainzlab-rails gem handles Rails-specific instrumentation
|
|
814
|
+
# SDK will only install non-Rails instrumentation (HTTP clients, Redis, etc.)
|
|
815
|
+
@rails_instrumentation_handled_externally = false
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
def positive_number?(value)
|
|
819
|
+
value.is_a?(Numeric) && value.positive?
|
|
820
|
+
end
|
|
821
|
+
|
|
717
822
|
def detect_environment
|
|
718
823
|
return ::Rails.env.to_s if defined?(::Rails) && ::Rails.respond_to?(:env)
|
|
719
824
|
return ENV['RACK_ENV'] if ENV['RACK_ENV']
|