tracelit 0.1.8 → 0.1.9
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/tracelit/error_span_processor.rb +70 -3
- data/lib/tracelit/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e7f493aa08c7a1d3595be84019013d49bfa48e2daae3a653cb38b17ad702a8f4
|
|
4
|
+
data.tar.gz: 07e1c738fb2a5eee274b48f30ff6fea1b97c613b14778de081471fd1fa9ed1d0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4a9c56ef732bc424fbc7a04484c5967bba3d9714d1f520f2b017b07c9fd939b8126b6fc7ff575fe538911be951a0a0da8025dde7e50724c42bdab005703219a8
|
|
7
|
+
data.tar.gz: 728eefa18600408fcb6475ec87fe83669a0f373500bcbe2a010e2f0f0776c8bd8a5120c4f16ffcca886125be307a58ab369e38161345ed1df567464ee7777ec8
|
|
@@ -13,12 +13,27 @@ module Tracelit
|
|
|
13
13
|
# so there is no double-export for sampled error spans
|
|
14
14
|
#
|
|
15
15
|
# NOTE: opentelemetry-sdk 1.x uses on_finish (not on_end) as the hook name.
|
|
16
|
+
#
|
|
17
|
+
# Important: this processor must never block application threads. Exporting an
|
|
18
|
+
# unsampled error span synchronously in on_finish can block request / console
|
|
19
|
+
# threads when the ingest endpoint is slow or retrying. We enqueue span data
|
|
20
|
+
# into a bounded in-memory queue and export on a background worker thread.
|
|
16
21
|
class ErrorSpanProcessor
|
|
22
|
+
QUEUE_CAPACITY = 512
|
|
23
|
+
SHUTDOWN_SENTINEL = Object.new
|
|
24
|
+
|
|
17
25
|
def initialize(exporter)
|
|
18
26
|
@exporter = exporter
|
|
27
|
+
@queue = SizedQueue.new(QUEUE_CAPACITY)
|
|
28
|
+
@shutdown = false
|
|
29
|
+
@worker = Thread.new do
|
|
30
|
+
Thread.current[:tracelit_error_export_worker] = true
|
|
31
|
+
worker_loop
|
|
32
|
+
end
|
|
33
|
+
@worker.abort_on_exception = false
|
|
19
34
|
end
|
|
20
35
|
|
|
21
|
-
def on_start(
|
|
36
|
+
def on_start(_span, _parent_context)
|
|
22
37
|
# nothing to do at start
|
|
23
38
|
end
|
|
24
39
|
|
|
@@ -30,19 +45,71 @@ module Tracelit
|
|
|
30
45
|
# This prevents double-export of error spans on traces that were sampled.
|
|
31
46
|
return if span.context.trace_flags.sampled?
|
|
32
47
|
|
|
33
|
-
#
|
|
34
|
-
|
|
48
|
+
# Queue for background export; never block the caller.
|
|
49
|
+
enqueue(span.to_span_data)
|
|
35
50
|
rescue StandardError
|
|
36
51
|
# Never let processor errors propagate to the application
|
|
37
52
|
end
|
|
38
53
|
|
|
39
54
|
def force_flush(timeout: nil)
|
|
55
|
+
wait_for_queue_drain(timeout)
|
|
40
56
|
@exporter.force_flush(timeout: timeout)
|
|
41
57
|
end
|
|
42
58
|
|
|
43
59
|
def shutdown(timeout: nil)
|
|
60
|
+
return if @shutdown
|
|
61
|
+
@shutdown = true
|
|
62
|
+
enqueue_shutdown_signal
|
|
63
|
+
@worker&.join(timeout || 1)
|
|
44
64
|
# Do not shut down the shared exporter here —
|
|
45
65
|
# the BatchSpanProcessor owns its lifecycle
|
|
46
66
|
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def worker_loop
|
|
71
|
+
loop do
|
|
72
|
+
item = @queue.pop
|
|
73
|
+
break if item.equal?(SHUTDOWN_SENTINEL)
|
|
74
|
+
|
|
75
|
+
begin
|
|
76
|
+
@exporter.export([item])
|
|
77
|
+
rescue StandardError
|
|
78
|
+
# Never let exporter failures crash the app worker thread
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
rescue StandardError
|
|
82
|
+
# Last-ditch guard: processor background failures must stay isolated.
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def enqueue(span_data)
|
|
86
|
+
@queue.push(span_data, true)
|
|
87
|
+
rescue ThreadError
|
|
88
|
+
# Queue full — drop to protect application latency.
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def enqueue_shutdown_signal
|
|
92
|
+
@queue.push(SHUTDOWN_SENTINEL, true)
|
|
93
|
+
rescue ThreadError
|
|
94
|
+
# Queue is full: drop one oldest item and retry so shutdown can proceed.
|
|
95
|
+
begin
|
|
96
|
+
@queue.pop(true)
|
|
97
|
+
rescue ThreadError
|
|
98
|
+
# no-op
|
|
99
|
+
end
|
|
100
|
+
begin
|
|
101
|
+
@queue.push(SHUTDOWN_SENTINEL, true)
|
|
102
|
+
rescue ThreadError
|
|
103
|
+
# no-op — join timeout is a final guard
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def wait_for_queue_drain(timeout)
|
|
108
|
+
deadline = timeout ? Time.now + timeout : nil
|
|
109
|
+
until @queue.empty?
|
|
110
|
+
break if deadline && Time.now >= deadline
|
|
111
|
+
sleep(0.01)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
47
114
|
end
|
|
48
115
|
end
|
data/lib/tracelit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tracelit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tracelit
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: opentelemetry-sdk
|