brainzlab 0.1.35 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/brainzlab/beacon/client.rb +6 -4
- data/lib/brainzlab/configuration.rb +272 -301
- data/lib/brainzlab/cortex/client.rb +6 -4
- data/lib/brainzlab/debug.rb +6 -6
- data/lib/brainzlab/dendrite/client.rb +6 -4
- data/lib/brainzlab/development/logger.rb +2 -2
- data/lib/brainzlab/development/store.rb +4 -2
- data/lib/brainzlab/devtools/middleware/error_page.rb +1 -1
- data/lib/brainzlab/errors.rb +12 -5
- data/lib/brainzlab/flux/client.rb +1 -1
- 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 +13 -7
- data/lib/brainzlab/instrumentation/action_view.rb +33 -29
- data/lib/brainzlab/instrumentation/active_job.rb +10 -6
- data/lib/brainzlab/instrumentation/active_record.rb +24 -21
- data/lib/brainzlab/instrumentation/active_storage.rb +4 -4
- data/lib/brainzlab/instrumentation/active_support_cache.rb +8 -6
- data/lib/brainzlab/instrumentation/grape.rb +1 -3
- data/lib/brainzlab/instrumentation/rails_deprecation.rb +1 -1
- data/lib/brainzlab/instrumentation/railties.rb +2 -2
- data/lib/brainzlab/nerve/client.rb +6 -4
- data/lib/brainzlab/pulse/client.rb +1 -1
- data/lib/brainzlab/pulse.rb +1 -5
- data/lib/brainzlab/rails/railtie.rb +3 -1
- data/lib/brainzlab/reflex/client.rb +1 -1
- data/lib/brainzlab/sentinel/client.rb +6 -4
- data/lib/brainzlab/synapse/client.rb +6 -4
- data/lib/brainzlab/testing/event_store.rb +3 -3
- data/lib/brainzlab/testing/matchers.rb +4 -4
- data/lib/brainzlab/testing.rb +3 -5
- data/lib/brainzlab/vault/client.rb +6 -4
- data/lib/brainzlab/version.rb +1 -1
- data/lib/brainzlab/vision/client.rb +3 -3
- data/lib/fluyenta-ruby.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4ff0306e7d8fe78a37efbc84090d9ffc65dbfa46f76f5ada564304368a5d218a
|
|
4
|
+
data.tar.gz: 79ab8e0b681d14468a6cd24577c3850bd0ce0800d547bc7bb5020ff69cb40054
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cdb11db4fd944c0978bedf6e619061269e21c334a036bfb3d5d4b7d3d9c9f50317e87434d8915e5adfefc8d6f2c37f9da3cf75dfefd7776eb1edc6f90ad0b818
|
|
7
|
+
data.tar.gz: eecd6d8197389329c70971e93fc9d2cbede53eea1866e181182a1c38f5d8f273585e44c071c440cb495f03e822928ed7dd8d6ffd527791022ba31b05760e8016
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.1.36] - 2026-10-29
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Flux client now falls back to `secret_key`.** `Flux::Client#api_key` only read `flux_ingest_key || flux_api_key`, while `Configuration#flux_valid?` also accepted `secret_key`. Apps configured with only `BRAINZLAB_SECRET_KEY` (no `FLUX_API_KEY` / `FLUX_INGEST_KEY`) therefore sent `Authorization: Bearer ` with an empty token, and Flux rejected every batch with 401. The client now uses `Configuration#flux_auth_key` (`flux_ingest_key || flux_api_key || secret_key`), matching how Pulse resolves its key. Measured in production on 2026-10-29: every `solid_queue.job.duration_ms` batch from services on 0.1.32/0.1.33 without a Flux-specific key was rejected.
|
|
10
|
+
|
|
5
11
|
## [0.1.31] - 2026-06-18
|
|
6
12
|
|
|
7
13
|
### Fixed
|
|
@@ -204,9 +204,9 @@ module BrainzLab
|
|
|
204
204
|
BrainzLab.debug_log("[Beacon::Client] #{operation} failed: #{structured_error.message}")
|
|
205
205
|
|
|
206
206
|
# Call on_error callback if configured
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
207
|
+
if @config.on_error
|
|
208
|
+
@config.on_error.call(structured_error, { service: 'Beacon', operation: operation })
|
|
209
|
+
end
|
|
210
210
|
end
|
|
211
211
|
|
|
212
212
|
def handle_response_error(response, operation)
|
|
@@ -216,7 +216,9 @@ module BrainzLab
|
|
|
216
216
|
BrainzLab.debug_log("[Beacon::Client] #{operation} failed: #{structured_error.message}")
|
|
217
217
|
|
|
218
218
|
# Call on_error callback if configured
|
|
219
|
-
@config.on_error
|
|
219
|
+
if @config.on_error
|
|
220
|
+
@config.on_error.call(structured_error, { service: 'Beacon', operation: operation })
|
|
221
|
+
end
|
|
220
222
|
|
|
221
223
|
structured_error
|
|
222
224
|
end
|
|
@@ -199,13 +199,270 @@ module BrainzLab
|
|
|
199
199
|
}.freeze
|
|
200
200
|
|
|
201
201
|
def initialize
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
202
|
+
# SDK enabled flag — set BRAINZLAB_SDK_ENABLED=false to completely disable
|
|
203
|
+
@enabled = ENV.fetch('BRAINZLAB_SDK_ENABLED', 'true') != 'false'
|
|
204
|
+
|
|
205
|
+
# Authentication
|
|
206
|
+
@secret_key = ENV.fetch('BRAINZLAB_SECRET_KEY', nil)
|
|
207
|
+
|
|
208
|
+
# Environment
|
|
209
|
+
@environment = ENV['BRAINZLAB_ENVIRONMENT'] || detect_environment
|
|
210
|
+
@service = ENV.fetch('BRAINZLAB_SERVICE', nil)
|
|
211
|
+
@host = ENV['BRAINZLAB_HOST'] || detect_host
|
|
212
|
+
|
|
213
|
+
# App name for auto-provisioning
|
|
214
|
+
@app_name = ENV.fetch('BRAINZLAB_APP_NAME', nil)
|
|
215
|
+
|
|
216
|
+
# Git context
|
|
217
|
+
@commit = ENV['GIT_COMMIT'] || ENV['COMMIT_SHA'] || detect_git_commit
|
|
218
|
+
@branch = ENV['GIT_BRANCH'] || ENV['BRANCH_NAME'] || detect_git_branch
|
|
219
|
+
|
|
220
|
+
# Debug mode - enables verbose logging
|
|
221
|
+
@debug = ENV['BRAINZLAB_DEBUG'] == 'true'
|
|
222
|
+
|
|
223
|
+
# SDK mode - :production (default) or :development (offline, local storage)
|
|
224
|
+
@mode = ENV['BRAINZLAB_MODE']&.to_sym || :production
|
|
225
|
+
|
|
226
|
+
# Development mode settings
|
|
227
|
+
@development_db_path = ENV['BRAINZLAB_DEV_DB_PATH'] || 'tmp/brainzlab.sqlite3'
|
|
228
|
+
@development_log_output = $stdout
|
|
229
|
+
|
|
230
|
+
# Disable self-tracking - prevents services from tracking to themselves
|
|
231
|
+
# e.g., Recall won't log to itself, Reflex won't track errors to itself
|
|
232
|
+
@disable_self_tracking = ENV.fetch('BRAINZLAB_DISABLE_SELF_TRACKING', 'true') == 'true'
|
|
233
|
+
|
|
234
|
+
# Recall settings
|
|
235
|
+
@recall_enabled = true
|
|
236
|
+
@recall_url = ENV['RECALL_URL'] || detect_product_url('recall')
|
|
237
|
+
@recall_min_level = :debug
|
|
238
|
+
@recall_buffer_size = 50
|
|
239
|
+
@recall_flush_interval = 5
|
|
240
|
+
@recall_master_key = ENV.fetch('RECALL_MASTER_KEY', nil)
|
|
241
|
+
@recall_auto_provision = true
|
|
242
|
+
|
|
243
|
+
# Reflex settings
|
|
244
|
+
@reflex_enabled = true
|
|
245
|
+
@reflex_url = ENV['REFLEX_URL'] || detect_product_url('reflex')
|
|
246
|
+
@reflex_api_key = ENV.fetch('REFLEX_API_KEY', nil)
|
|
247
|
+
@reflex_master_key = ENV.fetch('REFLEX_MASTER_KEY', nil)
|
|
248
|
+
@reflex_auto_provision = true
|
|
249
|
+
@reflex_excluded_exceptions = []
|
|
250
|
+
@reflex_before_send = nil
|
|
251
|
+
@reflex_sample_rate = nil
|
|
252
|
+
@reflex_fingerprint = nil # Custom fingerprint callback
|
|
253
|
+
|
|
254
|
+
# Pulse settings
|
|
255
|
+
@pulse_enabled = true
|
|
256
|
+
@pulse_url = ENV['PULSE_URL'] || detect_product_url('pulse')
|
|
257
|
+
@pulse_api_key = ENV.fetch('PULSE_API_KEY', nil)
|
|
258
|
+
@pulse_master_key = ENV.fetch('PULSE_MASTER_KEY', nil)
|
|
259
|
+
@pulse_auto_provision = true
|
|
260
|
+
@pulse_buffer_size = 50
|
|
261
|
+
@pulse_flush_interval = 5
|
|
262
|
+
# Trace sampling. Explicit rate (0.0–1.0) wins; otherwise derived from the
|
|
263
|
+
# tier. Defaults to the "internal" tier so the Brainz fleet samples ~10%
|
|
264
|
+
# (error traces are always kept). Client-facing apps set
|
|
265
|
+
# BRAINZLAB_PULSE_TIER=client (or PULSE_SAMPLE_RATE) to keep everything.
|
|
266
|
+
@pulse_sample_rate = (v = ENV['PULSE_SAMPLE_RATE'] || ENV['BRAINZLAB_PULSE_SAMPLE_RATE']).nil? || v.to_s.strip.empty? ? nil : v.to_f
|
|
267
|
+
@pulse_sample_tier = (ENV['BRAINZLAB_PULSE_TIER'] || 'internal').to_s.strip.downcase
|
|
268
|
+
# Traces at/above this duration (ms) bypass sampling and are ALWAYS kept,
|
|
269
|
+
# so slow requests / N+1s are never sampled away (APM's whole purpose).
|
|
270
|
+
# Set to 0 to disable. Default 1000ms.
|
|
271
|
+
@pulse_always_keep_slow_ms = (ENV['BRAINZLAB_PULSE_ALWAYS_KEEP_SLOW_MS'] || 1000).to_i
|
|
272
|
+
@pulse_excluded_paths = %w[/health /ping /up /assets]
|
|
273
|
+
|
|
274
|
+
# Flux settings
|
|
275
|
+
@flux_enabled = true
|
|
276
|
+
@flux_url = ENV['FLUX_URL'] || 'https://flux.brainzlab.ai'
|
|
277
|
+
@flux_api_key = ENV.fetch('FLUX_API_KEY', nil)
|
|
278
|
+
@flux_ingest_key = ENV.fetch('FLUX_INGEST_KEY', nil)
|
|
279
|
+
@flux_master_key = ENV.fetch('FLUX_MASTER_KEY', nil)
|
|
280
|
+
@flux_auto_provision = true
|
|
281
|
+
@flux_buffer_size = 100
|
|
282
|
+
@flux_flush_interval = 5
|
|
283
|
+
|
|
284
|
+
# Signal settings
|
|
285
|
+
@signal_enabled = true
|
|
286
|
+
@signal_url = ENV['SIGNAL_URL'] || detect_product_url('signal')
|
|
287
|
+
@signal_api_key = ENV.fetch('SIGNAL_API_KEY', nil)
|
|
288
|
+
@signal_ingest_key = ENV.fetch('SIGNAL_INGEST_KEY', nil)
|
|
289
|
+
@signal_master_key = ENV.fetch('SIGNAL_MASTER_KEY', nil)
|
|
290
|
+
@signal_auto_provision = true
|
|
291
|
+
|
|
292
|
+
# Vault settings
|
|
293
|
+
@vault_enabled = true
|
|
294
|
+
@vault_url = ENV['VAULT_URL'] || 'https://vault.brainzlab.ai'
|
|
295
|
+
@vault_api_key = ENV.fetch('VAULT_API_KEY', nil)
|
|
296
|
+
@vault_master_key = ENV.fetch('VAULT_MASTER_KEY', nil)
|
|
297
|
+
@vault_auto_provision = true
|
|
298
|
+
@vault_cache_enabled = true
|
|
299
|
+
@vault_cache_ttl = 300 # 5 minutes
|
|
300
|
+
@vault_auto_load = ENV.fetch('VAULT_AUTO_LOAD', 'false') == 'true' # Auto-load secrets into ENV
|
|
301
|
+
@vault_load_provider_keys = true # Also load provider keys (OpenAI, etc.)
|
|
302
|
+
|
|
303
|
+
# Vision settings (AI browser automation)
|
|
304
|
+
@vision_enabled = true
|
|
305
|
+
@vision_url = ENV['VISION_URL'] || 'https://vision.brainzlab.ai'
|
|
306
|
+
@vision_api_key = ENV.fetch('VISION_API_KEY', nil)
|
|
307
|
+
@vision_ingest_key = ENV.fetch('VISION_INGEST_KEY', nil)
|
|
308
|
+
@vision_master_key = ENV.fetch('VISION_MASTER_KEY', nil)
|
|
309
|
+
@vision_auto_provision = true
|
|
310
|
+
@vision_default_model = ENV['VISION_DEFAULT_MODEL'] || 'claude-sonnet-4'
|
|
311
|
+
@vision_default_browser_provider = ENV['VISION_DEFAULT_BROWSER_PROVIDER'] || 'local'
|
|
312
|
+
|
|
313
|
+
# Cortex settings (feature flags)
|
|
314
|
+
@cortex_enabled = true
|
|
315
|
+
@cortex_url = ENV['CORTEX_URL'] || 'https://cortex.brainzlab.ai'
|
|
316
|
+
@cortex_api_key = ENV.fetch('CORTEX_API_KEY', nil)
|
|
317
|
+
@cortex_master_key = ENV.fetch('CORTEX_MASTER_KEY', nil)
|
|
318
|
+
@cortex_auto_provision = true
|
|
319
|
+
@cortex_cache_enabled = true
|
|
320
|
+
@cortex_cache_ttl = 60 # 1 minute
|
|
321
|
+
@cortex_default_context = {}
|
|
322
|
+
|
|
323
|
+
# Beacon settings (uptime monitoring)
|
|
324
|
+
@beacon_enabled = true
|
|
325
|
+
@beacon_url = ENV['BEACON_URL'] || 'https://beacon.brainzlab.ai'
|
|
326
|
+
@beacon_api_key = ENV.fetch('BEACON_API_KEY', nil)
|
|
327
|
+
@beacon_master_key = ENV.fetch('BEACON_MASTER_KEY', nil)
|
|
328
|
+
@beacon_auto_provision = true
|
|
329
|
+
|
|
330
|
+
# Nerve settings (job monitoring)
|
|
331
|
+
@nerve_enabled = true
|
|
332
|
+
@nerve_url = ENV['NERVE_URL'] || 'https://nerve.brainzlab.ai'
|
|
333
|
+
@nerve_api_key = ENV.fetch('NERVE_API_KEY', nil)
|
|
334
|
+
@nerve_master_key = ENV.fetch('NERVE_MASTER_KEY', nil)
|
|
335
|
+
@nerve_auto_provision = true
|
|
336
|
+
|
|
337
|
+
# Dendrite settings (AI documentation)
|
|
338
|
+
@dendrite_enabled = true
|
|
339
|
+
@dendrite_url = ENV['DENDRITE_URL'] || 'https://dendrite.brainzlab.ai'
|
|
340
|
+
@dendrite_api_key = ENV.fetch('DENDRITE_API_KEY', nil)
|
|
341
|
+
@dendrite_master_key = ENV.fetch('DENDRITE_MASTER_KEY', nil)
|
|
342
|
+
@dendrite_auto_provision = true
|
|
343
|
+
|
|
344
|
+
# Sentinel settings (host monitoring)
|
|
345
|
+
@sentinel_enabled = true
|
|
346
|
+
@sentinel_url = ENV['SENTINEL_URL'] || 'https://sentinel.brainzlab.ai'
|
|
347
|
+
@sentinel_api_key = ENV.fetch('SENTINEL_API_KEY', nil)
|
|
348
|
+
@sentinel_agent_key = ENV.fetch('SENTINEL_AGENT_KEY', nil)
|
|
349
|
+
@sentinel_master_key = ENV.fetch('SENTINEL_MASTER_KEY', nil)
|
|
350
|
+
@sentinel_auto_provision = true
|
|
351
|
+
|
|
352
|
+
# Synapse settings (AI development orchestration)
|
|
353
|
+
@synapse_enabled = true
|
|
354
|
+
@synapse_url = ENV['SYNAPSE_URL'] || 'https://synapse.brainzlab.ai'
|
|
355
|
+
@synapse_api_key = ENV.fetch('SYNAPSE_API_KEY', nil)
|
|
356
|
+
@synapse_master_key = ENV.fetch('SYNAPSE_MASTER_KEY', nil)
|
|
357
|
+
@synapse_auto_provision = true
|
|
358
|
+
|
|
359
|
+
# Filtering
|
|
360
|
+
@scrub_fields = %i[password password_confirmation token api_key secret]
|
|
361
|
+
|
|
362
|
+
# Internal logger for debugging SDK issues
|
|
363
|
+
@logger = nil
|
|
364
|
+
|
|
365
|
+
# Debug callbacks
|
|
366
|
+
# Called when an SDK error occurs (lambda/proc receiving error object and context hash)
|
|
367
|
+
@on_error = nil
|
|
368
|
+
# Called before each API request (lambda/proc receiving service, method, path, and payload)
|
|
369
|
+
@on_send = nil
|
|
370
|
+
|
|
371
|
+
# Instrumentation
|
|
372
|
+
@instrument_http = true # Enable HTTP client instrumentation (Net::HTTP, Faraday, HTTParty)
|
|
373
|
+
@instrument_active_record = true # AR breadcrumbs for Reflex
|
|
374
|
+
@instrument_redis = true # Redis command instrumentation
|
|
375
|
+
@instrument_sidekiq = true # Sidekiq job instrumentation
|
|
376
|
+
@instrument_graphql = true # GraphQL query instrumentation
|
|
377
|
+
@instrument_mongodb = true # MongoDB/Mongoid instrumentation
|
|
378
|
+
@instrument_elasticsearch = true # Elasticsearch instrumentation
|
|
379
|
+
@instrument_action_controller = true # ActionController instrumentation (requests, redirects, filters)
|
|
380
|
+
@instrument_action_view = true # ActionView instrumentation (templates, partials, collections)
|
|
381
|
+
@instrument_action_mailer = true # ActionMailer instrumentation
|
|
382
|
+
@instrument_active_job = true # ActiveJob instrumentation (enqueue, perform, retry, discard)
|
|
383
|
+
@instrument_active_support_cache = true # ActiveSupport::Cache instrumentation (read, write, fetch)
|
|
384
|
+
@instrument_delayed_job = true # Delayed::Job instrumentation
|
|
385
|
+
@instrument_grape = true # Grape API instrumentation
|
|
386
|
+
@instrument_solid_queue = true # Solid Queue job instrumentation
|
|
387
|
+
@instrument_good_job = true # GoodJob instrumentation
|
|
388
|
+
@instrument_resque = true # Resque instrumentation
|
|
389
|
+
@instrument_excon = true # Excon HTTP client instrumentation
|
|
390
|
+
@instrument_typhoeus = true # Typhoeus HTTP client instrumentation
|
|
391
|
+
@instrument_dalli = true # Dalli/Memcached instrumentation
|
|
392
|
+
@instrument_aws = true # AWS SDK instrumentation
|
|
393
|
+
@instrument_stripe = true # Stripe API instrumentation
|
|
394
|
+
@instrument_active_storage = true # ActiveStorage instrumentation (uploads, downloads, transforms)
|
|
395
|
+
@instrument_action_cable = true # ActionCable WebSocket instrumentation
|
|
396
|
+
@instrument_action_dispatch = true # ActionDispatch instrumentation (middleware, redirects, requests)
|
|
397
|
+
@instrument_rails_deprecation = true # Rails deprecation warnings tracking
|
|
398
|
+
@instrument_action_mailbox = true # ActionMailbox inbound email processing instrumentation
|
|
399
|
+
@instrument_railties = true # Railties config initializer loading instrumentation
|
|
400
|
+
@http_ignore_hosts = %w[localhost 127.0.0.1]
|
|
401
|
+
@redis_ignore_commands = %w[ping info] # Commands to skip tracking
|
|
402
|
+
|
|
403
|
+
# ActiveRecord slow-query / N+1 detection — all tunable so a single chatty
|
|
404
|
+
# default can't flood Recall. Slow-query duration is APM data (Pulse already
|
|
405
|
+
# records it), so it defaults to a quiet level (:debug) and a higher threshold.
|
|
406
|
+
@slow_query_threshold = (ENV['BRAINZLAB_SLOW_QUERY_THRESHOLD'] || 500).to_i # ms (was hardcoded 100)
|
|
407
|
+
|
|
408
|
+
# Query plan capture. Off by default: it issues an extra (read-only)
|
|
409
|
+
# EXPLAIN against the app's own database, so an app opts in deliberately.
|
|
410
|
+
# Threshold defaults to the slow query threshold — a fast query has no
|
|
411
|
+
# plan worth looking at.
|
|
412
|
+
@pulse_explain_enabled = ENV['BRAINZLAB_PULSE_EXPLAIN_ENABLED'] == 'true'
|
|
413
|
+
@pulse_explain_threshold = (ENV['BRAINZLAB_PULSE_EXPLAIN_THRESHOLD'] || @slow_query_threshold).to_i
|
|
414
|
+
@pulse_explain_timeout = (ENV['BRAINZLAB_PULSE_EXPLAIN_TIMEOUT'] || 2).to_i
|
|
415
|
+
@very_slow_query_threshold = (ENV['BRAINZLAB_VERY_SLOW_QUERY_THRESHOLD'] || 2000).to_i # ms (was hardcoded 1000)
|
|
416
|
+
@slow_query_log_level = (ENV['BRAINZLAB_SLOW_QUERY_LOG_LEVEL'] || 'debug').to_sym # was :warn → floods
|
|
417
|
+
@very_slow_query_log_level = (ENV['BRAINZLAB_VERY_SLOW_QUERY_LOG_LEVEL'] || 'warn').to_sym
|
|
418
|
+
@n_plus_one_threshold = (ENV['BRAINZLAB_N_PLUS_ONE_THRESHOLD'] || 10).to_i # was hardcoded 5
|
|
419
|
+
@n_plus_one_log_level = (ENV['BRAINZLAB_N_PLUS_ONE_LOG_LEVEL'] || 'debug').to_sym # was :warning
|
|
420
|
+
|
|
421
|
+
# Per-instrumentation slow / very-slow thresholds (ms) — all env-tunable so a
|
|
422
|
+
# single low default can't flood Recall or wrongly escalate normal latency to
|
|
423
|
+
# :error. Defaults preserve prior behaviour EXCEPT cache, which is raised off
|
|
424
|
+
# DB-backed Solid Cache's normal write latency (~50ms paid a DB round-trip and
|
|
425
|
+
# tripped the old VERY_SLOW=50 → thousands of false :error logs/hour).
|
|
426
|
+
@slow_request_threshold = (ENV['BRAINZLAB_SLOW_REQUEST_THRESHOLD'] || 500).to_i
|
|
427
|
+
@very_slow_request_threshold = (ENV['BRAINZLAB_VERY_SLOW_REQUEST_THRESHOLD'] || 2000).to_i
|
|
428
|
+
@slow_cache_threshold = (ENV['BRAINZLAB_SLOW_CACHE_THRESHOLD'] || 100).to_i # was 10
|
|
429
|
+
@very_slow_cache_threshold = (ENV['BRAINZLAB_VERY_SLOW_CACHE_THRESHOLD'] || 500).to_i # was 50 → flooded :error
|
|
430
|
+
@slow_render_threshold = (ENV['BRAINZLAB_SLOW_RENDER_THRESHOLD'] || 50).to_i
|
|
431
|
+
@very_slow_render_threshold = (ENV['BRAINZLAB_VERY_SLOW_RENDER_THRESHOLD'] || 200).to_i
|
|
432
|
+
@slow_storage_threshold = (ENV['BRAINZLAB_SLOW_STORAGE_THRESHOLD'] || 500).to_i
|
|
433
|
+
@very_slow_storage_threshold = (ENV['BRAINZLAB_VERY_SLOW_STORAGE_THRESHOLD'] || 2000).to_i
|
|
434
|
+
@slow_cable_threshold = (ENV['BRAINZLAB_SLOW_CABLE_THRESHOLD'] || 100).to_i
|
|
435
|
+
@very_slow_cable_threshold = (ENV['BRAINZLAB_VERY_SLOW_CABLE_THRESHOLD'] || 500).to_i
|
|
436
|
+
@slow_initializer_threshold = (ENV['BRAINZLAB_SLOW_INITIALIZER_THRESHOLD'] || 100).to_i
|
|
437
|
+
@very_slow_initializer_threshold = (ENV['BRAINZLAB_VERY_SLOW_INITIALIZER_THRESHOLD'] || 500).to_i
|
|
438
|
+
@slow_middleware_threshold = (ENV['BRAINZLAB_SLOW_MIDDLEWARE_THRESHOLD'] || 50).to_i
|
|
439
|
+
@very_slow_middleware_threshold = (ENV['BRAINZLAB_VERY_SLOW_MIDDLEWARE_THRESHOLD'] || 200).to_i
|
|
440
|
+
@slow_mailbox_threshold = (ENV['BRAINZLAB_SLOW_MAILBOX_THRESHOLD'] || 1000).to_i
|
|
441
|
+
@very_slow_mailbox_threshold = (ENV['BRAINZLAB_VERY_SLOW_MAILBOX_THRESHOLD'] || 5000).to_i
|
|
442
|
+
@slow_job_threshold = (ENV['BRAINZLAB_SLOW_JOB_THRESHOLD'] || 5000).to_i
|
|
443
|
+
@very_slow_job_threshold = (ENV['BRAINZLAB_VERY_SLOW_JOB_THRESHOLD'] || 30_000).to_i
|
|
444
|
+
|
|
445
|
+
# Log formatter settings
|
|
446
|
+
@log_formatter_enabled = true
|
|
447
|
+
@log_formatter_colors = nil # auto-detect TTY
|
|
448
|
+
@log_formatter_hide_assets = false
|
|
449
|
+
@log_formatter_compact_assets = true
|
|
450
|
+
@log_formatter_show_params = true
|
|
451
|
+
|
|
452
|
+
# DevTools settings (development error page and debug panel)
|
|
453
|
+
@devtools_enabled = true
|
|
454
|
+
@devtools_error_page_enabled = true
|
|
455
|
+
@devtools_debug_panel_enabled = true
|
|
456
|
+
@devtools_allowed_environments = %w[development test]
|
|
457
|
+
@devtools_allowed_ips = ['127.0.0.1', '::1', '172.16.0.0/12', '192.168.0.0/16', '10.0.0.0/8']
|
|
458
|
+
@devtools_asset_path = '/__brainzlab__'
|
|
459
|
+
@devtools_panel_position = 'bottom-right'
|
|
460
|
+
@devtools_expand_by_default = false
|
|
461
|
+
|
|
462
|
+
# Rails instrumentation delegation
|
|
463
|
+
# When true, brainzlab-rails gem handles Rails-specific instrumentation
|
|
464
|
+
# SDK will only install non-Rails instrumentation (HTTP clients, Redis, etc.)
|
|
465
|
+
@rails_instrumentation_handled_externally = false
|
|
209
466
|
end
|
|
210
467
|
|
|
211
468
|
def recall_min_level=(level)
|
|
@@ -285,7 +542,9 @@ module BrainzLab
|
|
|
285
542
|
value = public_send(setting)
|
|
286
543
|
next if value.nil? # nil means "fall back to the tier default"
|
|
287
544
|
|
|
288
|
-
|
|
545
|
+
unless value.is_a?(Numeric) && value.between?(0, 1)
|
|
546
|
+
problems << "#{setting} must be a number between 0 and 1 (got #{value.inspect})"
|
|
547
|
+
end
|
|
289
548
|
end
|
|
290
549
|
|
|
291
550
|
POSITIVE_INTEGER_SETTINGS.each do |setting|
|
|
@@ -295,7 +554,9 @@ module BrainzLab
|
|
|
295
554
|
|
|
296
555
|
NON_NEGATIVE_NUMBER_SETTINGS.each do |setting|
|
|
297
556
|
value = public_send(setting)
|
|
298
|
-
|
|
557
|
+
unless value.is_a?(Numeric) && !value.negative?
|
|
558
|
+
problems << "#{setting} must be a non-negative number (got #{value.inspect})"
|
|
559
|
+
end
|
|
299
560
|
end
|
|
300
561
|
|
|
301
562
|
return self if problems.empty?
|
|
@@ -337,7 +598,7 @@ module BrainzLab
|
|
|
337
598
|
PULSE_TIER_SAMPLE_RATES = {
|
|
338
599
|
'internal' => 0.1,
|
|
339
600
|
'standard' => 0.5,
|
|
340
|
-
'client'
|
|
601
|
+
'client' => 1.0,
|
|
341
602
|
'critical' => 1.0
|
|
342
603
|
}.freeze
|
|
343
604
|
|
|
@@ -453,11 +714,7 @@ module BrainzLab
|
|
|
453
714
|
@synapse_url
|
|
454
715
|
].compact
|
|
455
716
|
|
|
456
|
-
urls.filter_map
|
|
457
|
-
URI.parse(url).host
|
|
458
|
-
rescue StandardError
|
|
459
|
-
nil
|
|
460
|
-
end.uniq
|
|
717
|
+
urls.filter_map { |url| URI.parse(url).host rescue nil }.uniq
|
|
461
718
|
end
|
|
462
719
|
end
|
|
463
720
|
|
|
@@ -529,292 +786,6 @@ module BrainzLab
|
|
|
529
786
|
|
|
530
787
|
private
|
|
531
788
|
|
|
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
789
|
def positive_number?(value)
|
|
819
790
|
value.is_a?(Numeric) && value.positive?
|
|
820
791
|
end
|