brainzlab 0.1.0 → 0.1.2
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 +9 -0
- data/README.md +30 -0
- data/lib/brainzlab/beacon/client.rb +209 -0
- data/lib/brainzlab/beacon/provisioner.rb +44 -0
- data/lib/brainzlab/beacon.rb +215 -0
- data/lib/brainzlab/configuration.rb +341 -3
- data/lib/brainzlab/cortex/cache.rb +59 -0
- data/lib/brainzlab/cortex/client.rb +141 -0
- data/lib/brainzlab/cortex/provisioner.rb +49 -0
- data/lib/brainzlab/cortex.rb +227 -0
- data/lib/brainzlab/dendrite/client.rb +232 -0
- data/lib/brainzlab/dendrite/provisioner.rb +44 -0
- data/lib/brainzlab/dendrite.rb +195 -0
- data/lib/brainzlab/devtools/assets/devtools.css +1106 -0
- data/lib/brainzlab/devtools/assets/devtools.js +322 -0
- data/lib/brainzlab/devtools/assets/logo.svg +6 -0
- data/lib/brainzlab/devtools/assets/templates/debug_panel.html.erb +500 -0
- data/lib/brainzlab/devtools/assets/templates/error_page.html.erb +1086 -0
- data/lib/brainzlab/devtools/data/collector.rb +248 -0
- data/lib/brainzlab/devtools/middleware/asset_server.rb +63 -0
- data/lib/brainzlab/devtools/middleware/database_handler.rb +180 -0
- data/lib/brainzlab/devtools/middleware/debug_panel.rb +126 -0
- data/lib/brainzlab/devtools/middleware/error_page.rb +376 -0
- data/lib/brainzlab/devtools/renderers/debug_panel_renderer.rb +155 -0
- data/lib/brainzlab/devtools/renderers/error_page_renderer.rb +94 -0
- data/lib/brainzlab/devtools.rb +75 -0
- data/lib/brainzlab/flux/buffer.rb +96 -0
- data/lib/brainzlab/flux/client.rb +70 -0
- data/lib/brainzlab/flux/provisioner.rb +57 -0
- data/lib/brainzlab/flux.rb +174 -0
- data/lib/brainzlab/instrumentation/active_record.rb +18 -1
- data/lib/brainzlab/instrumentation/aws.rb +179 -0
- data/lib/brainzlab/instrumentation/dalli.rb +108 -0
- data/lib/brainzlab/instrumentation/excon.rb +152 -0
- data/lib/brainzlab/instrumentation/good_job.rb +102 -0
- data/lib/brainzlab/instrumentation/resque.rb +115 -0
- data/lib/brainzlab/instrumentation/solid_queue.rb +198 -0
- data/lib/brainzlab/instrumentation/stripe.rb +164 -0
- data/lib/brainzlab/instrumentation/typhoeus.rb +104 -0
- data/lib/brainzlab/instrumentation.rb +72 -0
- data/lib/brainzlab/nerve/client.rb +217 -0
- data/lib/brainzlab/nerve/provisioner.rb +44 -0
- data/lib/brainzlab/nerve.rb +219 -0
- data/lib/brainzlab/pulse/instrumentation.rb +35 -2
- data/lib/brainzlab/pulse/propagation.rb +1 -1
- data/lib/brainzlab/pulse/tracer.rb +1 -1
- data/lib/brainzlab/pulse.rb +1 -1
- data/lib/brainzlab/rails/log_subscriber.rb +1 -2
- data/lib/brainzlab/rails/railtie.rb +36 -3
- data/lib/brainzlab/recall/provisioner.rb +17 -0
- data/lib/brainzlab/recall.rb +6 -1
- data/lib/brainzlab/reflex.rb +20 -5
- data/lib/brainzlab/sentinel/client.rb +218 -0
- data/lib/brainzlab/sentinel/provisioner.rb +44 -0
- data/lib/brainzlab/sentinel.rb +165 -0
- data/lib/brainzlab/signal/client.rb +62 -0
- data/lib/brainzlab/signal/provisioner.rb +55 -0
- data/lib/brainzlab/signal.rb +136 -0
- data/lib/brainzlab/synapse/client.rb +290 -0
- data/lib/brainzlab/synapse/provisioner.rb +44 -0
- data/lib/brainzlab/synapse.rb +270 -0
- data/lib/brainzlab/utilities/circuit_breaker.rb +265 -0
- data/lib/brainzlab/utilities/health_check.rb +296 -0
- data/lib/brainzlab/utilities/log_formatter.rb +256 -0
- data/lib/brainzlab/utilities/rate_limiter.rb +230 -0
- data/lib/brainzlab/utilities.rb +17 -0
- data/lib/brainzlab/vault/cache.rb +80 -0
- data/lib/brainzlab/vault/client.rb +198 -0
- data/lib/brainzlab/vault/provisioner.rb +49 -0
- data/lib/brainzlab/vault.rb +268 -0
- data/lib/brainzlab/version.rb +1 -1
- data/lib/brainzlab/vision/client.rb +128 -0
- data/lib/brainzlab/vision/provisioner.rb +136 -0
- data/lib/brainzlab/vision.rb +157 -0
- data/lib/brainzlab.rb +101 -0
- metadata +62 -2
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "nerve/client"
|
|
4
|
+
require_relative "nerve/provisioner"
|
|
5
|
+
|
|
6
|
+
module BrainzLab
|
|
7
|
+
module Nerve
|
|
8
|
+
class << self
|
|
9
|
+
# Report a completed job
|
|
10
|
+
# @param job_class [String] Job class name
|
|
11
|
+
# @param job_id [String] Job ID
|
|
12
|
+
# @param queue [String] Queue name
|
|
13
|
+
# @param started_at [Time] When job started
|
|
14
|
+
# @param ended_at [Time] When job ended (defaults to now)
|
|
15
|
+
# @param attributes [Hash] Additional attributes
|
|
16
|
+
#
|
|
17
|
+
# @example
|
|
18
|
+
# BrainzLab::Nerve.report_success(
|
|
19
|
+
# job_class: "ProcessOrderJob",
|
|
20
|
+
# job_id: "abc-123",
|
|
21
|
+
# queue: "default",
|
|
22
|
+
# started_at: 1.minute.ago
|
|
23
|
+
# )
|
|
24
|
+
#
|
|
25
|
+
def report_success(job_class:, job_id:, queue:, started_at:, ended_at: Time.now, **attributes)
|
|
26
|
+
return false unless enabled?
|
|
27
|
+
|
|
28
|
+
ensure_provisioned!
|
|
29
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
30
|
+
|
|
31
|
+
client.report_job(
|
|
32
|
+
job_class: job_class,
|
|
33
|
+
job_id: job_id,
|
|
34
|
+
queue: queue,
|
|
35
|
+
status: "completed",
|
|
36
|
+
started_at: started_at,
|
|
37
|
+
ended_at: ended_at,
|
|
38
|
+
**attributes
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Report a failed job
|
|
43
|
+
def report_failure(job_class:, job_id:, queue:, error:, started_at: nil, **attributes)
|
|
44
|
+
return false unless enabled?
|
|
45
|
+
|
|
46
|
+
ensure_provisioned!
|
|
47
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
48
|
+
|
|
49
|
+
client.report_failure(
|
|
50
|
+
job_class: job_class,
|
|
51
|
+
job_id: job_id,
|
|
52
|
+
queue: queue,
|
|
53
|
+
error_class: error.class.name,
|
|
54
|
+
error_message: error.message,
|
|
55
|
+
backtrace: error.backtrace,
|
|
56
|
+
started_at: started_at,
|
|
57
|
+
**attributes
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Report a job that's currently running
|
|
62
|
+
def report_started(job_class:, job_id:, queue:, **attributes)
|
|
63
|
+
return false unless enabled?
|
|
64
|
+
|
|
65
|
+
ensure_provisioned!
|
|
66
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
67
|
+
|
|
68
|
+
client.report_job(
|
|
69
|
+
job_class: job_class,
|
|
70
|
+
job_id: job_id,
|
|
71
|
+
queue: queue,
|
|
72
|
+
status: "running",
|
|
73
|
+
started_at: Time.now,
|
|
74
|
+
ended_at: Time.now,
|
|
75
|
+
**attributes
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Get job statistics
|
|
80
|
+
# @param queue [String] Filter by queue (optional)
|
|
81
|
+
# @param job_class [String] Filter by job class (optional)
|
|
82
|
+
# @param period [String] Time period: "1h", "24h", "7d", "30d"
|
|
83
|
+
def stats(queue: nil, job_class: nil, period: "1h")
|
|
84
|
+
return nil unless enabled?
|
|
85
|
+
|
|
86
|
+
ensure_provisioned!
|
|
87
|
+
return nil unless BrainzLab.configuration.nerve_valid?
|
|
88
|
+
|
|
89
|
+
client.stats(queue: queue, job_class: job_class, period: period)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# List recent jobs
|
|
93
|
+
def jobs(queue: nil, status: nil, limit: 100)
|
|
94
|
+
return [] unless enabled?
|
|
95
|
+
|
|
96
|
+
ensure_provisioned!
|
|
97
|
+
return [] unless BrainzLab.configuration.nerve_valid?
|
|
98
|
+
|
|
99
|
+
client.list_jobs(queue: queue, status: status, limit: limit)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# List all queues
|
|
103
|
+
def queues
|
|
104
|
+
return [] unless enabled?
|
|
105
|
+
|
|
106
|
+
ensure_provisioned!
|
|
107
|
+
return [] unless BrainzLab.configuration.nerve_valid?
|
|
108
|
+
|
|
109
|
+
client.list_queues
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Get queue details
|
|
113
|
+
def queue(name)
|
|
114
|
+
return nil unless enabled?
|
|
115
|
+
|
|
116
|
+
ensure_provisioned!
|
|
117
|
+
return nil unless BrainzLab.configuration.nerve_valid?
|
|
118
|
+
|
|
119
|
+
client.get_queue(name)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Retry a failed job
|
|
123
|
+
def retry(job_id)
|
|
124
|
+
return false unless enabled?
|
|
125
|
+
|
|
126
|
+
ensure_provisioned!
|
|
127
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
128
|
+
|
|
129
|
+
client.retry_job(job_id)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Delete a job
|
|
133
|
+
def delete(job_id)
|
|
134
|
+
return false unless enabled?
|
|
135
|
+
|
|
136
|
+
ensure_provisioned!
|
|
137
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
138
|
+
|
|
139
|
+
client.delete_job(job_id)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Report queue metrics (for custom job backends)
|
|
143
|
+
def report_metrics(queue:, size:, latency_ms: nil, workers: nil)
|
|
144
|
+
return false unless enabled?
|
|
145
|
+
|
|
146
|
+
ensure_provisioned!
|
|
147
|
+
return false unless BrainzLab.configuration.nerve_valid?
|
|
148
|
+
|
|
149
|
+
client.report_metrics(
|
|
150
|
+
queue: queue,
|
|
151
|
+
size: size,
|
|
152
|
+
latency_ms: latency_ms,
|
|
153
|
+
workers: workers
|
|
154
|
+
)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Track a job execution (block helper)
|
|
158
|
+
# @example
|
|
159
|
+
# BrainzLab::Nerve.track(job_class: "MyJob", job_id: "123", queue: "default") do
|
|
160
|
+
# # job work
|
|
161
|
+
# end
|
|
162
|
+
#
|
|
163
|
+
def track(job_class:, job_id:, queue: "default", **attributes)
|
|
164
|
+
started_at = Time.now
|
|
165
|
+
|
|
166
|
+
begin
|
|
167
|
+
result = yield
|
|
168
|
+
report_success(
|
|
169
|
+
job_class: job_class,
|
|
170
|
+
job_id: job_id,
|
|
171
|
+
queue: queue,
|
|
172
|
+
started_at: started_at,
|
|
173
|
+
**attributes
|
|
174
|
+
)
|
|
175
|
+
result
|
|
176
|
+
rescue StandardError => e
|
|
177
|
+
report_failure(
|
|
178
|
+
job_class: job_class,
|
|
179
|
+
job_id: job_id,
|
|
180
|
+
queue: queue,
|
|
181
|
+
error: e,
|
|
182
|
+
started_at: started_at,
|
|
183
|
+
**attributes
|
|
184
|
+
)
|
|
185
|
+
raise
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# === INTERNAL ===
|
|
190
|
+
|
|
191
|
+
def ensure_provisioned!
|
|
192
|
+
return if @provisioned
|
|
193
|
+
|
|
194
|
+
@provisioned = true
|
|
195
|
+
provisioner.ensure_project!
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def provisioner
|
|
199
|
+
@provisioner ||= Provisioner.new(BrainzLab.configuration)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def client
|
|
203
|
+
@client ||= Client.new(BrainzLab.configuration)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def reset!
|
|
207
|
+
@client = nil
|
|
208
|
+
@provisioner = nil
|
|
209
|
+
@provisioned = false
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
private
|
|
213
|
+
|
|
214
|
+
def enabled?
|
|
215
|
+
BrainzLab.configuration.nerve_enabled
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
@@ -26,6 +26,7 @@ module BrainzLab
|
|
|
26
26
|
event = ActiveSupport::Notifications::Event.new(*args)
|
|
27
27
|
next if skip_query?(event.payload)
|
|
28
28
|
|
|
29
|
+
sql = event.payload[:sql]
|
|
29
30
|
record_span(
|
|
30
31
|
name: event.payload[:name] || "SQL",
|
|
31
32
|
kind: "db",
|
|
@@ -33,9 +34,11 @@ module BrainzLab
|
|
|
33
34
|
ended_at: event.end,
|
|
34
35
|
duration_ms: event.duration,
|
|
35
36
|
data: {
|
|
36
|
-
sql: truncate_sql(
|
|
37
|
+
sql: truncate_sql(sql),
|
|
37
38
|
name: event.payload[:name],
|
|
38
|
-
cached: event.payload[:cached] || false
|
|
39
|
+
cached: event.payload[:cached] || false,
|
|
40
|
+
table: extract_table(sql),
|
|
41
|
+
operation: extract_operation(sql)
|
|
39
42
|
}
|
|
40
43
|
)
|
|
41
44
|
end
|
|
@@ -358,6 +361,36 @@ module BrainzLab
|
|
|
358
361
|
return nil unless path
|
|
359
362
|
path.to_s.split("/").last(2).join("/")
|
|
360
363
|
end
|
|
364
|
+
|
|
365
|
+
def extract_table(sql)
|
|
366
|
+
return nil unless sql
|
|
367
|
+
|
|
368
|
+
# Match FROM "table" or FROM table patterns
|
|
369
|
+
# Also handles INSERT INTO, UPDATE, DELETE FROM
|
|
370
|
+
case sql.to_s
|
|
371
|
+
when /\bFROM\s+["'`]?(\w+)["'`]?/i
|
|
372
|
+
Regexp.last_match(1)
|
|
373
|
+
when /\bINTO\s+["'`]?(\w+)["'`]?/i
|
|
374
|
+
Regexp.last_match(1)
|
|
375
|
+
when /\bUPDATE\s+["'`]?(\w+)["'`]?/i
|
|
376
|
+
Regexp.last_match(1)
|
|
377
|
+
when /\bJOIN\s+["'`]?(\w+)["'`]?/i
|
|
378
|
+
Regexp.last_match(1)
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def extract_operation(sql)
|
|
383
|
+
return nil unless sql
|
|
384
|
+
|
|
385
|
+
case sql.to_s.strip.upcase
|
|
386
|
+
when /\ASELECT/i then "SELECT"
|
|
387
|
+
when /\AINSERT/i then "INSERT"
|
|
388
|
+
when /\AUPDATE/i then "UPDATE"
|
|
389
|
+
when /\ADELETE/i then "DELETE"
|
|
390
|
+
when /\ABEGIN/i, /\ACOMMIT/i, /\AROLLBACK/i then "TRANSACTION"
|
|
391
|
+
else "QUERY"
|
|
392
|
+
end
|
|
393
|
+
end
|
|
361
394
|
end
|
|
362
395
|
end
|
|
363
396
|
end
|
data/lib/brainzlab/pulse.rb
CHANGED
|
@@ -149,8 +149,7 @@ module BrainzLab
|
|
|
149
149
|
|
|
150
150
|
sql
|
|
151
151
|
.gsub(/\b\d+\b/, "?") # Replace numbers
|
|
152
|
-
.gsub(/'[^']*'/, "?") # Replace strings
|
|
153
|
-
.gsub(/"[^"]*"/, "?") # Replace double-quoted strings
|
|
152
|
+
.gsub(/'[^']*'/, "?") # Replace single-quoted strings
|
|
154
153
|
.gsub(/\$\d+/, "?") # Replace positional params
|
|
155
154
|
.gsub(/\/\*.*?\*\//, "") # Remove comments
|
|
156
155
|
.gsub(/\s+/, " ") # Normalize whitespace
|
|
@@ -7,6 +7,17 @@ module BrainzLab
|
|
|
7
7
|
require "generators/brainzlab/install/install_generator"
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
# Load Vault secrets early, before configuration
|
|
11
|
+
# This allows secrets to be used in config files
|
|
12
|
+
initializer "brainzlab.load_vault_secrets", before: :load_environment_config do
|
|
13
|
+
if BrainzLab.configuration.vault_enabled && BrainzLab.configuration.vault_auto_load
|
|
14
|
+
BrainzLab.debug_log("[Vault] Auto-loading secrets into ENV...")
|
|
15
|
+
BrainzLab::Vault.load!(
|
|
16
|
+
provider_keys: BrainzLab.configuration.vault_load_provider_keys
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
10
21
|
initializer "brainzlab.configure_rails_initialization" do |app|
|
|
11
22
|
# Set defaults from Rails
|
|
12
23
|
BrainzLab.configure do |config|
|
|
@@ -20,11 +31,33 @@ module BrainzLab
|
|
|
20
31
|
|
|
21
32
|
# Add request context middleware (runs early)
|
|
22
33
|
app.middleware.insert_after ActionDispatch::RequestId, BrainzLab::Rails::Middleware
|
|
34
|
+
|
|
35
|
+
# Add DevTools middlewares if enabled
|
|
36
|
+
if BrainzLab.configuration.devtools_enabled
|
|
37
|
+
require_relative "../devtools"
|
|
38
|
+
|
|
39
|
+
# Asset server (handles /__brainzlab__/* requests)
|
|
40
|
+
app.middleware.insert_before ActionDispatch::Static, BrainzLab::DevTools::Middleware::AssetServer
|
|
41
|
+
|
|
42
|
+
# Database handler (handles /_brainzlab/devtools/database POST requests)
|
|
43
|
+
# Allows running migrations from the error page
|
|
44
|
+
app.middleware.insert_before ActionDispatch::Static, BrainzLab::DevTools::Middleware::DatabaseHandler
|
|
45
|
+
|
|
46
|
+
# Error page (catches exceptions and renders branded error page)
|
|
47
|
+
# Insert BEFORE DebugExceptions so we can intercept the HTML error page
|
|
48
|
+
# that DebugExceptions renders and replace it with our own
|
|
49
|
+
if defined?(ActionDispatch::DebugExceptions)
|
|
50
|
+
app.middleware.insert_before ActionDispatch::DebugExceptions, BrainzLab::DevTools::Middleware::ErrorPage
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Debug panel (injects panel into HTML responses)
|
|
54
|
+
app.middleware.use BrainzLab::DevTools::Middleware::DebugPanel
|
|
55
|
+
end
|
|
23
56
|
end
|
|
24
57
|
|
|
25
58
|
config.after_initialize do
|
|
26
59
|
# Set up custom log formatter
|
|
27
|
-
setup_log_formatter if BrainzLab.configuration.log_formatter_enabled
|
|
60
|
+
BrainzLab::Rails::Railtie.setup_log_formatter if BrainzLab.configuration.log_formatter_enabled
|
|
28
61
|
|
|
29
62
|
# Install instrumentation (HTTP tracking, etc.)
|
|
30
63
|
BrainzLab::Instrumentation.install!
|
|
@@ -569,9 +602,9 @@ module BrainzLab
|
|
|
569
602
|
end
|
|
570
603
|
end
|
|
571
604
|
|
|
572
|
-
# Sidekiq error handler
|
|
605
|
+
# Sidekiq error handler - Sidekiq 7.x+ requires 3 arguments
|
|
573
606
|
class SidekiqErrorHandler
|
|
574
|
-
def call(exception, context)
|
|
607
|
+
def call(exception, context, _config = nil)
|
|
575
608
|
BrainzLab::Reflex.capture(exception,
|
|
576
609
|
tags: { type: "sidekiq" },
|
|
577
610
|
extra: {
|
|
@@ -37,14 +37,31 @@ module BrainzLab
|
|
|
37
37
|
private
|
|
38
38
|
|
|
39
39
|
def should_provision?
|
|
40
|
+
if @config.debug
|
|
41
|
+
log_debug("Checking provision conditions:")
|
|
42
|
+
log_debug(" recall_auto_provision: #{@config.recall_auto_provision}")
|
|
43
|
+
log_debug(" app_name: '#{@config.app_name}'")
|
|
44
|
+
log_debug(" secret_key set: #{@config.secret_key.to_s.strip.length > 0}")
|
|
45
|
+
log_debug(" recall_master_key set: #{@config.recall_master_key.to_s.strip.length > 0}")
|
|
46
|
+
end
|
|
47
|
+
|
|
40
48
|
return false unless @config.recall_auto_provision
|
|
41
49
|
return false unless @config.app_name.to_s.strip.length > 0
|
|
42
50
|
return false if @config.secret_key.to_s.strip.length > 0
|
|
43
51
|
return false unless @config.recall_master_key.to_s.strip.length > 0
|
|
44
52
|
|
|
53
|
+
log_debug("Will provision Recall project") if @config.debug
|
|
45
54
|
true
|
|
46
55
|
end
|
|
47
56
|
|
|
57
|
+
def log_debug(message)
|
|
58
|
+
if @config.logger
|
|
59
|
+
@config.logger.info("[BrainzLab::Debug] #{message}")
|
|
60
|
+
else
|
|
61
|
+
puts "[BrainzLab::Debug] #{message}"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
48
65
|
def provision_project
|
|
49
66
|
uri = URI.parse("#{@config.recall_url}/api/v1/projects/provision")
|
|
50
67
|
request = Net::HTTP::Post.new(uri)
|
data/lib/brainzlab/recall.rb
CHANGED
|
@@ -30,7 +30,7 @@ module BrainzLab
|
|
|
30
30
|
|
|
31
31
|
def log(level, message, **data)
|
|
32
32
|
config = BrainzLab.configuration
|
|
33
|
-
return unless config.
|
|
33
|
+
return unless config.recall_effectively_enabled?
|
|
34
34
|
|
|
35
35
|
# Auto-provision project on first log if app_name is configured
|
|
36
36
|
ensure_provisioned!
|
|
@@ -43,6 +43,11 @@ module BrainzLab
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def ensure_provisioned!
|
|
46
|
+
config = BrainzLab.configuration
|
|
47
|
+
if config.debug
|
|
48
|
+
puts "[BrainzLab::Debug] Recall.ensure_provisioned! called, @provisioned=#{@provisioned}"
|
|
49
|
+
end
|
|
50
|
+
|
|
46
51
|
return if @provisioned
|
|
47
52
|
|
|
48
53
|
@provisioned = true
|
data/lib/brainzlab/reflex.rb
CHANGED
|
@@ -77,7 +77,7 @@ module BrainzLab
|
|
|
77
77
|
private
|
|
78
78
|
|
|
79
79
|
def enabled?
|
|
80
|
-
BrainzLab.configuration.
|
|
80
|
+
BrainzLab.configuration.reflex_effectively_enabled?
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
def capture_disabled?
|
|
@@ -241,16 +241,27 @@ module BrainzLab
|
|
|
241
241
|
end
|
|
242
242
|
|
|
243
243
|
def parse_backtrace_line(line)
|
|
244
|
-
# Parse
|
|
245
|
-
|
|
244
|
+
# Parse various Ruby backtrace formats:
|
|
245
|
+
# - "path/to/file.rb:42:in `method_name'" (backtick + single quote)
|
|
246
|
+
# - "path/to/file.rb:42:in 'method_name'" (single quotes)
|
|
247
|
+
# - "path/to/file.rb:42" (no method)
|
|
248
|
+
if line =~ /\A(.+):(\d+):in [`']([^']+)'?\z/
|
|
246
249
|
{
|
|
247
250
|
file: $1,
|
|
248
251
|
line: $2.to_i,
|
|
249
252
|
function: $3,
|
|
250
253
|
in_app: in_app_frame?($1)
|
|
251
254
|
}
|
|
255
|
+
elsif line =~ /\A(.+):(\d+)\z/
|
|
256
|
+
{
|
|
257
|
+
file: $1,
|
|
258
|
+
line: $2.to_i,
|
|
259
|
+
function: nil,
|
|
260
|
+
in_app: in_app_frame?($1)
|
|
261
|
+
}
|
|
252
262
|
else
|
|
253
|
-
|
|
263
|
+
# Still store file for display even if format is unexpected
|
|
264
|
+
{ file: line, line: nil, function: nil, in_app: false }
|
|
254
265
|
end
|
|
255
266
|
end
|
|
256
267
|
|
|
@@ -258,8 +269,12 @@ module BrainzLab
|
|
|
258
269
|
return false if path.nil?
|
|
259
270
|
return false if path.include?("vendor/")
|
|
260
271
|
return false if path.include?("/gems/")
|
|
272
|
+
return false if path.include?("/ruby/")
|
|
261
273
|
|
|
262
|
-
|
|
274
|
+
# Match both relative and absolute paths containing app/ or lib/
|
|
275
|
+
path.start_with?("app/", "lib/", "./app/", "./lib/") ||
|
|
276
|
+
path.include?("/app/") ||
|
|
277
|
+
path.include?("/lib/")
|
|
263
278
|
end
|
|
264
279
|
|
|
265
280
|
def filter_params(params)
|