opentrace 0.13.2 → 0.14.0
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/opentrace/client.rb +28 -16
- data/lib/opentrace/config.rb +20 -5
- data/lib/opentrace/rails.rb +13 -4
- data/lib/opentrace/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: d768edfb2fd22f19187ff5e8f51abde81345f7a04cde6cc3a367ba4a1bc74faf
|
|
4
|
+
data.tar.gz: 0fe2d4458c4f1cbb4599ec27420a42b3e20e1c548129c19ef0181f34ea2dd81b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5eaa0f312e0a689744d42d9e06ce63a211024d377f0a2e7e68cb2879510636866957ed5dcedbfda5ede82d8dd223dc1e47197ef951ab4aeeb5c738c2501f4b87
|
|
7
|
+
data.tar.gz: c4b49a941eb4eec04db0d5d2ebf5973c45bd43ceda14c2043c44ff82554c78cffdb48a493b2e69c3eb1b40566977b3eae465d463f85729bad5f3fa85742032a4
|
data/lib/opentrace/client.rb
CHANGED
|
@@ -175,38 +175,50 @@ module OpenTrace
|
|
|
175
175
|
deadline = Time.now + @config.flush_interval
|
|
176
176
|
|
|
177
177
|
loop do
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
while batch.size < @config.batch_size
|
|
186
|
-
begin
|
|
187
|
-
item = @queue.pop(true) # non_block = true
|
|
188
|
-
batch << item
|
|
189
|
-
rescue ThreadError
|
|
190
|
-
break # queue empty
|
|
191
|
-
end
|
|
178
|
+
# Non-blocking drain: grab everything currently in the queue
|
|
179
|
+
while batch.size < @config.batch_size
|
|
180
|
+
begin
|
|
181
|
+
item = @queue.pop(true) # non_block = true
|
|
182
|
+
batch << item
|
|
183
|
+
rescue ThreadError, ClosedQueueError
|
|
184
|
+
break # queue empty or closed
|
|
192
185
|
end
|
|
193
186
|
end
|
|
194
187
|
|
|
195
188
|
break if batch.size >= @config.batch_size
|
|
196
189
|
break if Time.now >= deadline
|
|
197
|
-
|
|
190
|
+
|
|
191
|
+
# Queue closed — return remaining items or nil to signal shutdown
|
|
192
|
+
if @queue.closed?
|
|
193
|
+
return batch.empty? ? nil : batch
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Queue is empty but we haven't hit batch_size or deadline.
|
|
197
|
+
# Block (up to MAX_POP_WAIT) instead of busy-spinning so we
|
|
198
|
+
# release the GIL and let request-serving fibers run.
|
|
199
|
+
item = pop_with_timeout(deadline - Time.now)
|
|
200
|
+
return nil if item.nil? && @queue.closed?
|
|
201
|
+
batch << item if item
|
|
198
202
|
end
|
|
199
203
|
|
|
200
204
|
batch
|
|
201
205
|
end
|
|
202
206
|
|
|
207
|
+
# Maximum time to block in a single Queue#pop call.
|
|
208
|
+
# Falcon (and other fiber-based servers) rely on the GIL being released
|
|
209
|
+
# periodically so their health-check fibers can run. A long blocking
|
|
210
|
+
# pop (e.g. 5 seconds) starves those fibers and causes Falcon to
|
|
211
|
+
# SIGKILL the worker. By capping at 0.5s we yield the GIL frequently
|
|
212
|
+
# enough to keep the health-check happy (30s default timeout).
|
|
213
|
+
MAX_POP_WAIT = 0.5
|
|
214
|
+
|
|
203
215
|
def pop_with_timeout(timeout)
|
|
204
216
|
if timeout <= 0
|
|
205
217
|
# Deadline already passed — still try a non-blocking pop in case
|
|
206
218
|
# items arrived while we were busy (e.g. during version check).
|
|
207
219
|
@queue.pop(true)
|
|
208
220
|
else
|
|
209
|
-
@queue.pop(timeout: timeout)
|
|
221
|
+
@queue.pop(timeout: [timeout, MAX_POP_WAIT].min)
|
|
210
222
|
end
|
|
211
223
|
rescue ThreadError, ClosedQueueError
|
|
212
224
|
nil
|
data/lib/opentrace/config.rb
CHANGED
|
@@ -6,7 +6,7 @@ module OpenTrace
|
|
|
6
6
|
LEVELS = { debug: 0, info: 1, warn: 2, error: 3, fatal: 4 }.freeze
|
|
7
7
|
LEVEL_INTS = { "DEBUG" => 0, "INFO" => 1, "WARN" => 2, "ERROR" => 3, "FATAL" => 4 }.freeze
|
|
8
8
|
|
|
9
|
-
attr_accessor :endpoint, :api_key, :service, :environment, :timeout,
|
|
9
|
+
attr_accessor :endpoint, :api_key, :service, :environment, :timeout,
|
|
10
10
|
:context, :hostname, :pid, :git_sha,
|
|
11
11
|
:batch_size, :flush_interval,
|
|
12
12
|
:max_retries, :retry_base_delay, :retry_max_delay,
|
|
@@ -34,8 +34,13 @@ module OpenTrace
|
|
|
34
34
|
:explain_slow_queries, :explain_threshold_ms,
|
|
35
35
|
:runtime_metrics, :runtime_metrics_interval
|
|
36
36
|
|
|
37
|
-
# Custom writers that invalidate
|
|
38
|
-
attr_reader :min_level, :allowed_levels, :ignore_paths
|
|
37
|
+
# Custom writers that invalidate caches
|
|
38
|
+
attr_reader :enabled, :min_level, :allowed_levels, :ignore_paths
|
|
39
|
+
|
|
40
|
+
def enabled=(val)
|
|
41
|
+
@enabled = val
|
|
42
|
+
@enabled_cache = nil
|
|
43
|
+
end
|
|
39
44
|
|
|
40
45
|
def min_level=(val)
|
|
41
46
|
@min_level = val
|
|
@@ -115,6 +120,7 @@ module OpenTrace
|
|
|
115
120
|
@runtime_metrics = false # Collect GC/runtime metrics
|
|
116
121
|
@runtime_metrics_interval = 30 # Interval in seconds
|
|
117
122
|
@level_cache = nil
|
|
123
|
+
@enabled_cache = nil
|
|
118
124
|
end
|
|
119
125
|
|
|
120
126
|
def valid?
|
|
@@ -122,7 +128,12 @@ module OpenTrace
|
|
|
122
128
|
end
|
|
123
129
|
|
|
124
130
|
def enabled?
|
|
125
|
-
|
|
131
|
+
# Cache the enabled+valid result to avoid recomputing valid? on every call.
|
|
132
|
+
# Invalidated by finalize! (called at end of configure block) and enabled= setter.
|
|
133
|
+
if @enabled_cache.nil?
|
|
134
|
+
@enabled_cache = @enabled && valid?
|
|
135
|
+
end
|
|
136
|
+
@enabled_cache
|
|
126
137
|
end
|
|
127
138
|
|
|
128
139
|
def min_level_value
|
|
@@ -138,7 +149,10 @@ module OpenTrace
|
|
|
138
149
|
build_level_cache!
|
|
139
150
|
cache = @level_cache
|
|
140
151
|
end
|
|
141
|
-
|
|
152
|
+
# Avoid allocating a new String when the level is already uppercase.
|
|
153
|
+
# On the hot path (called per SQL query, per log line), this saves
|
|
154
|
+
# one String allocation per call.
|
|
155
|
+
key = level.is_a?(String) && level == level.upcase ? level : level.to_s.upcase
|
|
142
156
|
result = cache[key]
|
|
143
157
|
return result unless result.nil?
|
|
144
158
|
# Unknown level (e.g. "UNKNOWN"): treat as severity 0
|
|
@@ -149,6 +163,7 @@ module OpenTrace
|
|
|
149
163
|
# Pre-compute the level cache. Called at end of configure block
|
|
150
164
|
# and lazily when settings change afterward.
|
|
151
165
|
def finalize!
|
|
166
|
+
@enabled_cache = nil
|
|
152
167
|
build_level_cache!
|
|
153
168
|
end
|
|
154
169
|
|
data/lib/opentrace/rails.rb
CHANGED
|
@@ -43,8 +43,12 @@ if defined?(::Rails::Railtie)
|
|
|
43
43
|
# Swallow - never affect the host app
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
# SQL subscriber — lightweight counter + optional forwarding with filtering
|
|
46
|
+
# SQL subscriber — lightweight counter + optional forwarding with filtering.
|
|
47
|
+
# Cache config values at subscribe time to avoid repeated config lookups
|
|
48
|
+
# on every single SQL query (can be 50-200+ per request).
|
|
47
49
|
sql_logging = OpenTrace.config.sql_logging
|
|
50
|
+
explain_enabled = OpenTrace.config.explain_slow_queries
|
|
51
|
+
explain_threshold = OpenTrace.config.explain_threshold_ms
|
|
48
52
|
ActiveSupport::Notifications.subscribe("sql.active_record") do |name, started, finished, id, payload|
|
|
49
53
|
sql_count = Fiber[:opentrace_sql_count]
|
|
50
54
|
collector = Fiber[:opentrace_collector]
|
|
@@ -81,8 +85,8 @@ if defined?(::Rails::Railtie)
|
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
# Flag slow queries for background EXPLAIN (opt-in)
|
|
84
|
-
if
|
|
85
|
-
duration_ms >
|
|
88
|
+
if explain_enabled &&
|
|
89
|
+
duration_ms > explain_threshold &&
|
|
86
90
|
explainable_query?(raw_sql)
|
|
87
91
|
pending = Fiber[:opentrace_pending_explains] ||= []
|
|
88
92
|
if pending.size < 3
|
|
@@ -328,6 +332,12 @@ if defined?(::Rails::Railtie)
|
|
|
328
332
|
return unless OpenTrace.enabled?
|
|
329
333
|
|
|
330
334
|
duration = duration_ms&.round(2)
|
|
335
|
+
|
|
336
|
+
# Determine level BEFORE doing any expensive work (regex, hashing).
|
|
337
|
+
# Most SQL logs are DEBUG — skip everything if DEBUG is filtered.
|
|
338
|
+
level = (duration && duration > 1000) ? "WARN" : "DEBUG"
|
|
339
|
+
return unless OpenTrace.config.level_allowed?(level)
|
|
340
|
+
|
|
331
341
|
threshold = OpenTrace.config.sql_duration_threshold_ms
|
|
332
342
|
|
|
333
343
|
# Skip if below threshold
|
|
@@ -354,7 +364,6 @@ if defined?(::Rails::Railtie)
|
|
|
354
364
|
metadata[:sql_table] = $1
|
|
355
365
|
end
|
|
356
366
|
|
|
357
|
-
level = (duration && duration > 1000) ? "WARN" : "DEBUG"
|
|
358
367
|
message = "SQL #{payload[:name]} #{duration}ms"
|
|
359
368
|
|
|
360
369
|
OpenTrace.log(level, message, metadata)
|
data/lib/opentrace/version.rb
CHANGED