opentrace 0.14.1 → 0.15.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/circuit_breaker.rb +16 -2
- data/lib/opentrace/client.rb +22 -6
- data/lib/opentrace/config.rb +10 -2
- data/lib/opentrace/middleware.rb +21 -11
- data/lib/opentrace/payload_builder.rb +3 -1
- data/lib/opentrace/stats.rb +1 -3
- data/lib/opentrace/version.rb +1 -1
- data/lib/opentrace.rb +5 -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: ad0233533a9c236a70cf379346c1f64f7ffecc58cf91ce413e55665e8b4f5675
|
|
4
|
+
data.tar.gz: 92d7052f7901fad33897b767441ea01f8ed299bc47d90d43153110a2fdd22c1e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6f9b631bf0faab3e6671a41eccc04039339f2f95cfa90a6c380517572256c08c3115bb4c30ddae230933bac18f8c9858195a55beacda27ff2e44c5efb02ef4f7
|
|
7
|
+
data.tar.gz: 3671e28a4393225a5e891c09a38a734b974c05b70fd393ff892b06bb816fd5954880f7eab5da257248fe025df948f96b0fb94b2f526338d060a928514d5a4917
|
|
@@ -14,6 +14,7 @@ module OpenTrace
|
|
|
14
14
|
@state = CLOSED
|
|
15
15
|
@failure_count = 0
|
|
16
16
|
@last_failure_at = nil
|
|
17
|
+
@half_open_probe_sent = false
|
|
17
18
|
@mutex = Mutex.new
|
|
18
19
|
end
|
|
19
20
|
|
|
@@ -25,12 +26,18 @@ module OpenTrace
|
|
|
25
26
|
when OPEN
|
|
26
27
|
if Time.now - @last_failure_at >= @recovery_timeout
|
|
27
28
|
@state = HALF_OPEN
|
|
29
|
+
@half_open_probe_sent = true
|
|
28
30
|
true
|
|
29
31
|
else
|
|
30
32
|
false
|
|
31
33
|
end
|
|
32
34
|
when HALF_OPEN
|
|
33
|
-
|
|
35
|
+
if @half_open_probe_sent
|
|
36
|
+
false
|
|
37
|
+
else
|
|
38
|
+
@half_open_probe_sent = true
|
|
39
|
+
true
|
|
40
|
+
end
|
|
34
41
|
end
|
|
35
42
|
end
|
|
36
43
|
end
|
|
@@ -38,6 +45,7 @@ module OpenTrace
|
|
|
38
45
|
def record_success
|
|
39
46
|
@mutex.synchronize do
|
|
40
47
|
@failure_count = 0
|
|
48
|
+
@half_open_probe_sent = false
|
|
41
49
|
@state = CLOSED
|
|
42
50
|
end
|
|
43
51
|
end
|
|
@@ -46,7 +54,12 @@ module OpenTrace
|
|
|
46
54
|
@mutex.synchronize do
|
|
47
55
|
@failure_count += 1
|
|
48
56
|
@last_failure_at = Time.now
|
|
49
|
-
|
|
57
|
+
if @state == HALF_OPEN
|
|
58
|
+
@half_open_probe_sent = false
|
|
59
|
+
@state = OPEN
|
|
60
|
+
elsif @failure_count >= @failure_threshold
|
|
61
|
+
@state = OPEN
|
|
62
|
+
end
|
|
50
63
|
end
|
|
51
64
|
end
|
|
52
65
|
|
|
@@ -55,6 +68,7 @@ module OpenTrace
|
|
|
55
68
|
@state = CLOSED
|
|
56
69
|
@failure_count = 0
|
|
57
70
|
@last_failure_at = nil
|
|
71
|
+
@half_open_probe_sent = false
|
|
58
72
|
end
|
|
59
73
|
end
|
|
60
74
|
end
|
data/lib/opentrace/client.rb
CHANGED
|
@@ -322,11 +322,20 @@ module OpenTrace
|
|
|
322
322
|
@rate_limit_until = Time.now + retry_after
|
|
323
323
|
|
|
324
324
|
# Re-enqueue batch items if space allows
|
|
325
|
+
re_enqueued = 0
|
|
325
326
|
batch.each do |payload|
|
|
326
327
|
break if @queue.size >= MAX_QUEUE_SIZE
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
328
|
+
begin
|
|
329
|
+
@queue.push(payload)
|
|
330
|
+
re_enqueued += 1
|
|
331
|
+
rescue ClosedQueueError
|
|
332
|
+
break
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
dropped = batch.size - re_enqueued
|
|
336
|
+
if dropped > 0
|
|
337
|
+
@stats.increment(:dropped_error, dropped)
|
|
338
|
+
fire_on_drop(dropped, :shutdown)
|
|
330
339
|
end
|
|
331
340
|
end
|
|
332
341
|
|
|
@@ -404,6 +413,8 @@ module OpenTrace
|
|
|
404
413
|
end
|
|
405
414
|
|
|
406
415
|
def unix_socket_send(json)
|
|
416
|
+
require "socket" unless defined?(UNIXSocket)
|
|
417
|
+
|
|
407
418
|
payload = if @config.compression && json.bytesize > @config.compression_threshold
|
|
408
419
|
gzip_compress(json)
|
|
409
420
|
else
|
|
@@ -416,9 +427,14 @@ module OpenTrace
|
|
|
416
427
|
socket.write(payload)
|
|
417
428
|
socket.flush
|
|
418
429
|
|
|
419
|
-
# Read 4-byte status code response
|
|
420
|
-
|
|
421
|
-
|
|
430
|
+
# Read 4-byte status code response with timeout
|
|
431
|
+
if IO.select([socket], nil, nil, 5)
|
|
432
|
+
response_data = socket.read(4)
|
|
433
|
+
status = response_data&.unpack1("N") || 500
|
|
434
|
+
else
|
|
435
|
+
@stats.increment(:socket_timeouts)
|
|
436
|
+
status = 500
|
|
437
|
+
end
|
|
422
438
|
socket.close
|
|
423
439
|
|
|
424
440
|
UnixSocketResponse.new(status)
|
data/lib/opentrace/config.rb
CHANGED
|
@@ -23,7 +23,7 @@ module OpenTrace
|
|
|
23
23
|
:trace_propagation,
|
|
24
24
|
:log_forwarding, :view_tracking, :cache_tracking,
|
|
25
25
|
:deprecation_tracking, :detailed_request_log,
|
|
26
|
-
:
|
|
26
|
+
:sampler, :before_send,
|
|
27
27
|
:sql_normalization, :log_trace_injection,
|
|
28
28
|
:source_context, :before_breadcrumb,
|
|
29
29
|
:pii_scrubbing, :pii_patterns, :pii_disabled_patterns,
|
|
@@ -35,7 +35,7 @@ module OpenTrace
|
|
|
35
35
|
:runtime_metrics, :runtime_metrics_interval
|
|
36
36
|
|
|
37
37
|
# Custom writers that invalidate caches
|
|
38
|
-
attr_reader :enabled, :min_level, :allowed_levels, :ignore_paths
|
|
38
|
+
attr_reader :enabled, :min_level, :allowed_levels, :ignore_paths, :sample_rate
|
|
39
39
|
|
|
40
40
|
def enabled=(val)
|
|
41
41
|
@enabled = val
|
|
@@ -56,6 +56,14 @@ module OpenTrace
|
|
|
56
56
|
@ignore_paths = val
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
def sample_rate=(val)
|
|
60
|
+
val = val.to_f
|
|
61
|
+
unless (0.0..1.0).cover?(val)
|
|
62
|
+
raise ArgumentError, "sample_rate must be between 0.0 and 1.0, got #{val}"
|
|
63
|
+
end
|
|
64
|
+
@sample_rate = val
|
|
65
|
+
end
|
|
66
|
+
|
|
59
67
|
def initialize
|
|
60
68
|
@endpoint = nil
|
|
61
69
|
@api_key = nil
|
data/lib/opentrace/middleware.rb
CHANGED
|
@@ -5,6 +5,22 @@ require_relative "trace_context"
|
|
|
5
5
|
|
|
6
6
|
module OpenTrace
|
|
7
7
|
class Middleware
|
|
8
|
+
# All Fiber-local keys managed by this middleware.
|
|
9
|
+
# Centralised so cleanup never misses one.
|
|
10
|
+
FIBER_KEYS = %i[
|
|
11
|
+
opentrace_collector
|
|
12
|
+
opentrace_cached_context
|
|
13
|
+
opentrace_sql_count
|
|
14
|
+
opentrace_sql_total_ms
|
|
15
|
+
opentrace_trace_id
|
|
16
|
+
opentrace_span_id
|
|
17
|
+
opentrace_parent_span_id
|
|
18
|
+
opentrace_transaction_name
|
|
19
|
+
opentrace_breadcrumbs
|
|
20
|
+
opentrace_session_id
|
|
21
|
+
opentrace_pending_explains
|
|
22
|
+
].freeze
|
|
23
|
+
|
|
8
24
|
def initialize(app)
|
|
9
25
|
@app = app
|
|
10
26
|
end
|
|
@@ -65,22 +81,16 @@ module OpenTrace
|
|
|
65
81
|
collector.memory_after = current_rss_mb
|
|
66
82
|
end
|
|
67
83
|
|
|
68
|
-
|
|
69
|
-
Fiber[:opentrace_cached_context] = nil
|
|
70
|
-
Fiber[:opentrace_sql_count] = nil
|
|
71
|
-
Fiber[:opentrace_sql_total_ms] = nil
|
|
72
|
-
Fiber[:opentrace_trace_id] = nil
|
|
73
|
-
Fiber[:opentrace_span_id] = nil
|
|
74
|
-
Fiber[:opentrace_parent_span_id] = nil
|
|
75
|
-
Fiber[:opentrace_transaction_name] = nil
|
|
76
|
-
Fiber[:opentrace_breadcrumbs] = nil
|
|
77
|
-
Fiber[:opentrace_session_id] = nil
|
|
78
|
-
Fiber[:opentrace_pending_explains] = nil
|
|
84
|
+
cleanup_fiber_locals
|
|
79
85
|
OpenTrace.current_request_id = nil
|
|
80
86
|
end
|
|
81
87
|
|
|
82
88
|
private
|
|
83
89
|
|
|
90
|
+
def cleanup_fiber_locals
|
|
91
|
+
FIBER_KEYS.each { |key| Fiber[key] = nil }
|
|
92
|
+
end
|
|
93
|
+
|
|
84
94
|
# Extract trace context from incoming request headers.
|
|
85
95
|
# Priority: W3C traceparent > X-Trace-ID > request_id > generate new
|
|
86
96
|
def extract_trace_context(env)
|
|
@@ -13,7 +13,9 @@ module OpenTrace
|
|
|
13
13
|
elsif entry.is_a?(Hash)
|
|
14
14
|
entry # legacy direct payload
|
|
15
15
|
end
|
|
16
|
-
rescue StandardError
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
OpenTrace.stats.increment(:payload_build_errors) if OpenTrace.respond_to?(:stats)
|
|
18
|
+
$stderr.puts "[OpenTrace] PayloadBuilder error: #{e.class}: #{e.message}" if OpenTrace.respond_to?(:config) && OpenTrace.config.respond_to?(:debug) && OpenTrace.config.debug
|
|
17
19
|
nil
|
|
18
20
|
end
|
|
19
21
|
|
data/lib/opentrace/stats.rb
CHANGED
|
@@ -26,10 +26,8 @@ module OpenTrace
|
|
|
26
26
|
@started_at = Time.now
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
# Hot path: no mutex. Under CRuby's GIL, Hash#[]= with integer
|
|
30
|
-
# increment is effectively atomic for single operations.
|
|
31
29
|
def increment(counter, amount = 1)
|
|
32
|
-
@counters[counter] += amount
|
|
30
|
+
@mutex.synchronize { @counters[counter] += amount }
|
|
33
31
|
end
|
|
34
32
|
|
|
35
33
|
def get(counter)
|
data/lib/opentrace/version.rb
CHANGED
data/lib/opentrace.rb
CHANGED
|
@@ -25,13 +25,17 @@ module OpenTrace
|
|
|
25
25
|
# Null object for when OpenTrace is not configured.
|
|
26
26
|
# All methods are no-ops, avoiding nil checks on the hot path.
|
|
27
27
|
class NilClient
|
|
28
|
+
def initialize
|
|
29
|
+
@nil_stats = NilStats.new
|
|
30
|
+
end
|
|
31
|
+
|
|
28
32
|
def enqueue(_) = nil
|
|
29
33
|
def shutdown(timeout: 5) = nil
|
|
30
34
|
def queue_size = 0
|
|
31
35
|
def circuit_state = :closed
|
|
32
36
|
def auth_suspended? = false
|
|
33
37
|
def stats_snapshot = { queue_size: 0, circuit_state: :closed, auth_suspended: false }
|
|
34
|
-
def stats =
|
|
38
|
+
def stats = @nil_stats
|
|
35
39
|
def supports?(_) = false
|
|
36
40
|
end
|
|
37
41
|
|