brainzlab 0.1.21 → 0.1.23
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/lib/brainzlab/configuration.rb +17 -1
- data/lib/brainzlab/instrumentation/active_record.rb +14 -10
- data/lib/brainzlab/rails/log_formatter.rb +16 -21
- data/lib/brainzlab/version.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: bba9f09002a8dcd486cb1b110567274f2d558c471eed12657996fbb0589cbba0
|
|
4
|
+
data.tar.gz: 60a5d0b80300d8ccf3aa6aa48bd615514fd222246be796f3ba7e2c9260578050
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2d4d0694747b4b08413636cb030465ad5babdd79388d8751f6fe6482229eea1dee0ca891711eb82a56641f745018b09c04cdfdcd87843ac1271c40f0b54bd2e8
|
|
7
|
+
data.tar.gz: cfd9ba154ac07f66eca51f22a4666a5c5a97db6c28265b725b7fcb1bbbd90a9064203957b0a26a39164201b963d55da8dbe7f23f45a9357cd89eccbe1cbce202
|
|
@@ -158,7 +158,13 @@ module BrainzLab
|
|
|
158
158
|
:devtools_expand_by_default,
|
|
159
159
|
:rails_instrumentation_handled_externally,
|
|
160
160
|
:development_db_path,
|
|
161
|
-
:development_log_output
|
|
161
|
+
:development_log_output,
|
|
162
|
+
:slow_query_threshold,
|
|
163
|
+
:very_slow_query_threshold,
|
|
164
|
+
:slow_query_log_level,
|
|
165
|
+
:very_slow_query_log_level,
|
|
166
|
+
:n_plus_one_threshold,
|
|
167
|
+
:n_plus_one_log_level
|
|
162
168
|
|
|
163
169
|
# Services that should not track themselves to avoid circular dependencies
|
|
164
170
|
SELF_TRACKING_SERVICES = {
|
|
@@ -362,6 +368,16 @@ module BrainzLab
|
|
|
362
368
|
@http_ignore_hosts = %w[localhost 127.0.0.1]
|
|
363
369
|
@redis_ignore_commands = %w[ping info] # Commands to skip tracking
|
|
364
370
|
|
|
371
|
+
# ActiveRecord slow-query / N+1 detection — all tunable so a single chatty
|
|
372
|
+
# default can't flood Recall. Slow-query duration is APM data (Pulse already
|
|
373
|
+
# records it), so it defaults to a quiet level (:debug) and a higher threshold.
|
|
374
|
+
@slow_query_threshold = (ENV['BRAINZLAB_SLOW_QUERY_THRESHOLD'] || 500).to_i # ms (was hardcoded 100)
|
|
375
|
+
@very_slow_query_threshold = (ENV['BRAINZLAB_VERY_SLOW_QUERY_THRESHOLD'] || 2000).to_i # ms (was hardcoded 1000)
|
|
376
|
+
@slow_query_log_level = (ENV['BRAINZLAB_SLOW_QUERY_LOG_LEVEL'] || 'debug').to_sym # was :warn → floods
|
|
377
|
+
@very_slow_query_log_level = (ENV['BRAINZLAB_VERY_SLOW_QUERY_LOG_LEVEL'] || 'warn').to_sym
|
|
378
|
+
@n_plus_one_threshold = (ENV['BRAINZLAB_N_PLUS_ONE_THRESHOLD'] || 10).to_i # was hardcoded 5
|
|
379
|
+
@n_plus_one_log_level = (ENV['BRAINZLAB_N_PLUS_ONE_LOG_LEVEL'] || 'debug').to_sym # was :warning
|
|
380
|
+
|
|
365
381
|
# Log formatter settings
|
|
366
382
|
@log_formatter_enabled = true
|
|
367
383
|
@log_formatter_colors = nil # auto-detect TTY
|
|
@@ -6,11 +6,13 @@ module BrainzLab
|
|
|
6
6
|
SCHEMA_QUERIES = %w[SCHEMA EXPLAIN].freeze
|
|
7
7
|
INTERNAL_TABLES = %w[pg_ information_schema sqlite_ mysql.].freeze
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
# Slow-query / N+1 thresholds + log levels are now configurable — see
|
|
10
|
+
# BrainzLab::Configuration (slow_query_threshold, very_slow_query_threshold,
|
|
11
|
+
# slow_query_log_level, very_slow_query_log_level, n_plus_one_threshold,
|
|
12
|
+
# n_plus_one_log_level) + their BRAINZLAB_* env vars. These constants are
|
|
13
|
+
# kept only as legacy fallbacks and are no longer read by the instrumentation.
|
|
10
14
|
SLOW_QUERY_THRESHOLD = 100
|
|
11
15
|
VERY_SLOW_QUERY_THRESHOLD = 1000
|
|
12
|
-
|
|
13
|
-
# N+1 detection settings
|
|
14
16
|
N_PLUS_ONE_THRESHOLD = 5 # queries to same table in single request
|
|
15
17
|
N_PLUS_ONE_WINDOW = 50 # max queries to track per request
|
|
16
18
|
|
|
@@ -58,7 +60,7 @@ module BrainzLab
|
|
|
58
60
|
record_sql_span(event, duration)
|
|
59
61
|
|
|
60
62
|
# Log slow queries to Recall
|
|
61
|
-
log_slow_query(event, duration) if duration >=
|
|
63
|
+
log_slow_query(event, duration) if duration >= BrainzLab.configuration.slow_query_threshold
|
|
62
64
|
|
|
63
65
|
# Track for N+1 detection
|
|
64
66
|
track_query_for_n_plus_one(event)
|
|
@@ -79,9 +81,10 @@ module BrainzLab
|
|
|
79
81
|
end
|
|
80
82
|
|
|
81
83
|
# Determine level based on duration
|
|
84
|
+
cfg = BrainzLab.configuration
|
|
82
85
|
level = case duration
|
|
83
|
-
when 0...
|
|
84
|
-
when
|
|
86
|
+
when 0...cfg.slow_query_threshold then :info
|
|
87
|
+
when cfg.slow_query_threshold...cfg.very_slow_query_threshold then :warning
|
|
85
88
|
else :error
|
|
86
89
|
end
|
|
87
90
|
|
|
@@ -146,7 +149,8 @@ module BrainzLab
|
|
|
146
149
|
operation = extract_operation(sql)
|
|
147
150
|
name = payload[:name] || 'SQL'
|
|
148
151
|
|
|
149
|
-
|
|
152
|
+
cfg = BrainzLab.configuration
|
|
153
|
+
level = duration >= cfg.very_slow_query_threshold ? cfg.very_slow_query_log_level : cfg.slow_query_log_level
|
|
150
154
|
|
|
151
155
|
BrainzLab::Recall.send(
|
|
152
156
|
level,
|
|
@@ -158,7 +162,7 @@ module BrainzLab
|
|
|
158
162
|
row_count: payload[:row_count],
|
|
159
163
|
affected_rows: payload[:affected_rows],
|
|
160
164
|
connection_name: extract_connection_name(payload[:connection]),
|
|
161
|
-
threshold_exceeded: duration >=
|
|
165
|
+
threshold_exceeded: duration >= cfg.very_slow_query_threshold ? 'critical' : 'warning'
|
|
162
166
|
)
|
|
163
167
|
end
|
|
164
168
|
|
|
@@ -188,7 +192,7 @@ module BrainzLab
|
|
|
188
192
|
end
|
|
189
193
|
|
|
190
194
|
# Detect N+1 pattern
|
|
191
|
-
if tracker[:count] ==
|
|
195
|
+
if tracker[:count] == BrainzLab.configuration.n_plus_one_threshold
|
|
192
196
|
report_n_plus_one(table, tracker)
|
|
193
197
|
end
|
|
194
198
|
end
|
|
@@ -197,7 +201,7 @@ module BrainzLab
|
|
|
197
201
|
BrainzLab::Reflex.add_breadcrumb(
|
|
198
202
|
"Potential N+1 detected: #{tracker[:count]}+ queries to '#{table}'",
|
|
199
203
|
category: 'db.n_plus_one',
|
|
200
|
-
level:
|
|
204
|
+
level: BrainzLab.configuration.n_plus_one_log_level,
|
|
201
205
|
data: {
|
|
202
206
|
table: table,
|
|
203
207
|
query_count: tracker[:count],
|
|
@@ -644,6 +644,17 @@ module BrainzLab
|
|
|
644
644
|
obj.is_a?(Hash) || (!obj.is_a?(Array) && obj.respond_to?(:to_h) && obj.respond_to?(:each))
|
|
645
645
|
end
|
|
646
646
|
|
|
647
|
+
# Convert hash-like values for display without raising. ActionController::Parameters
|
|
648
|
+
# raises UnfilteredParameters on #to_h when not permitted — use #to_unsafe_h (this
|
|
649
|
+
# is a log formatter, not a security boundary; param filtering happens elsewhere).
|
|
650
|
+
def safe_to_h(obj)
|
|
651
|
+
return obj.to_unsafe_h if obj.respond_to?(:to_unsafe_h)
|
|
652
|
+
|
|
653
|
+
obj.to_h
|
|
654
|
+
rescue StandardError
|
|
655
|
+
obj
|
|
656
|
+
end
|
|
657
|
+
|
|
647
658
|
def format_params_toml(params, prefix = '', depth = 0)
|
|
648
659
|
lines = []
|
|
649
660
|
line_prefix = colorize("#{BOX[:vertical]} ", :cyan)
|
|
@@ -654,11 +665,7 @@ module BrainzLab
|
|
|
654
665
|
|
|
655
666
|
case value
|
|
656
667
|
when Hash, ActionController::Parameters
|
|
657
|
-
value_hash =
|
|
658
|
-
value.to_h
|
|
659
|
-
rescue StandardError
|
|
660
|
-
value
|
|
661
|
-
end
|
|
668
|
+
value_hash = safe_to_h(value)
|
|
662
669
|
if value_hash.keys.length <= 3 && value_hash.values.all? { |v| !hash_like?(v) && !v.is_a?(Array) }
|
|
663
670
|
# Compact inline hash for simple cases
|
|
664
671
|
inline = value_hash.map { |k, v| "#{k} = #{format_value(v)}" }.join(', ')
|
|
@@ -669,16 +676,12 @@ module BrainzLab
|
|
|
669
676
|
value_hash.each do |k, v|
|
|
670
677
|
if hash_like?(v)
|
|
671
678
|
# Recursively format nested hashes
|
|
672
|
-
lines << format_hash_nested(v
|
|
679
|
+
lines << format_hash_nested(safe_to_h(v), "#{full_key}.#{k}", depth + 1)
|
|
673
680
|
elsif v.is_a?(Array) && hash_like?(v.first)
|
|
674
681
|
lines << "#{line_prefix}#{indent} #{colorize("[[#{full_key}.#{k}]]",
|
|
675
682
|
:gray)} #{colorize("# #{v.length} items", :gray)}"
|
|
676
683
|
if v.first
|
|
677
|
-
first_hash =
|
|
678
|
-
v.first.to_h
|
|
679
|
-
rescue StandardError
|
|
680
|
-
v.first
|
|
681
|
-
end
|
|
684
|
+
first_hash = safe_to_h(v.first)
|
|
682
685
|
first_hash.each do |nested_k, nested_v|
|
|
683
686
|
lines << "#{line_prefix}#{indent} #{colorize(nested_k.to_s, :white)} = #{format_value(nested_v)}"
|
|
684
687
|
end
|
|
@@ -699,19 +702,11 @@ module BrainzLab
|
|
|
699
702
|
:gray)} #{colorize("# #{value.length} items", :gray)}"
|
|
700
703
|
# Show first item fully expanded
|
|
701
704
|
if value.first
|
|
702
|
-
first_item =
|
|
703
|
-
value.first.to_h
|
|
704
|
-
rescue StandardError
|
|
705
|
-
value.first
|
|
706
|
-
end
|
|
705
|
+
first_item = safe_to_h(value.first)
|
|
707
706
|
first_item.each do |k, v|
|
|
708
707
|
if hash_like?(v)
|
|
709
708
|
# Expand nested hash fully
|
|
710
|
-
nested_hash =
|
|
711
|
-
v.to_h
|
|
712
|
-
rescue StandardError
|
|
713
|
-
v
|
|
714
|
-
end
|
|
709
|
+
nested_hash = safe_to_h(v)
|
|
715
710
|
lines << "#{line_prefix}#{indent} #{colorize("[#{k}]", :gray)}"
|
|
716
711
|
nested_hash.each do |nested_k, nested_v|
|
|
717
712
|
lines << "#{line_prefix}#{indent} #{colorize(nested_k.to_s,
|
data/lib/brainzlab/version.rb
CHANGED