bitfab 0.75.0 → 0.75.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6976d07abea8e8c456185b0f5a76bbe861148e2a10baa1c3a65ac1a694b6993d
4
- data.tar.gz: 072af5081f4c15e748478dbd058a8cc4c249804b345dcc70ed47b3e47f3c5830
3
+ metadata.gz: fad2341a7e82e22c18faf4809a1807407660eed238b04886b2687e4dc15989b2
4
+ data.tar.gz: 7a46b9c4935290898decf6f835257d5b8551281eb1ddebb1680128fcd5ac8c74
5
5
  SHA512:
6
- metadata.gz: 5189232282c64908bada35335eac364e16bb6fcadfe9b677cdc5b3330735f59dbdebc6ff71fe4a2984ad1a5c8386b45ade841710c0b2ec1ac0d26c0d07c7d44f
7
- data.tar.gz: 90b5fd0acb0d266e6f2e7d2b6d04dc4a08c66d3e1b25ce46f51425e5020cf372167c40ba141cf05c9f7e4f2348cc9a106f1888e9a5b792bbbe9a4f08d2bb0b80
6
+ metadata.gz: 82ef99ecba72308fc1e865257f260756cab829bae0167404f50f8317dd0d921446b02f4379f5c254e98f8deb3fb68104afa73075c4081cc9d5a7b7345243611f
7
+ data.tar.gz: 696fb090a73f51ab3bb9ca07277e89a0529dd3031a8c96bfa581f7c54235ba3205f804df4790e5d83163d635dfa5228f9d0be05e4e37d4c1805fb7271a920732
data/lib/bitfab/client.rb CHANGED
@@ -722,7 +722,8 @@ module Bitfab
722
722
  explicit_span_receiver:,
723
723
  explicit_span_method_name: explicit_span_method_name&.to_sym,
724
724
  surface:, recording_override:, content_withheld:,
725
- sends_on_completion: sends_on_completion
725
+ sends_on_completion: sends_on_completion,
726
+ trace_function_key:
726
727
  ) do
727
728
  invoke = -> { around_body ? around_body.call { yield } : yield }
728
729
  result = if explicit_span_receiver
@@ -769,7 +770,8 @@ module Bitfab
769
770
  surface:,
770
771
  around_body:,
771
772
  explicit_span_receiver:,
772
- explicit_span_method_name:
773
+ explicit_span_method_name:,
774
+ trace_function_key:
773
775
  )
774
776
  end
775
777
 
@@ -812,7 +814,7 @@ module Bitfab
812
814
  end
813
815
 
814
816
  def root_trace_function_key(trace_id, trace_function_key)
815
- TraceState.get(trace_id)&.dig(:trace_function_key) || trace_function_key
817
+ TraceState.trace_function_key(trace_id) || trace_function_key
816
818
  end
817
819
 
818
820
  def wait_for_simulation_plan
@@ -902,8 +904,10 @@ module Bitfab
902
904
  # span output. The span is sent exactly once: when iteration finishes,
903
905
  # raises, or the wrapper is `.close`d.
904
906
  def wrap_enumerator(source, trace_id:, span_id:, complete:, explicit_span_receiver: nil,
905
- explicit_span_method_name: nil, surface: nil, around_body: nil)
907
+ explicit_span_method_name: nil, surface: nil, around_body: nil, trace_function_key: nil)
906
908
  span_entry = {trace_id:, span_id:, surface:}
909
+ SpanContext.record_trace_function_keys(span_entry, trace_function_key)
910
+ trace_function_keys = span_entry[:trace_function_keys]
907
911
  if explicit_span_receiver
908
912
  span_entry[:explicit_span_receiver] = explicit_span_receiver
909
913
  span_entry[:explicit_span_method_name] = explicit_span_method_name&.to_sym
@@ -916,7 +920,7 @@ module Bitfab
916
920
  # the right parent. The fiber bridge carries the same parent into
917
921
  # Enumerator.new / enum_for source fibers on this thread.
918
922
  ReplayContext.with_span(trace_id:, span_id:) do
919
- SpanContext.with_fiber_bridge(trace_id:, span_id:, surface:) do
923
+ SpanContext.with_fiber_bridge(trace_id:, span_id:, surface:, trace_function_key:, trace_function_keys:) do
920
924
  SpanContext.stack.push(span_entry)
921
925
  begin
922
926
  iterate = lambda do
@@ -19,6 +19,16 @@ module Bitfab
19
19
  @span_state[:trace_id]
20
20
  end
21
21
 
22
+ # The keys of every trace function running at this point, outermost first,
23
+ # each listed once. A trace function called inside another one comes after
24
+ # it, so a cost recorded here can be counted toward each of them. Empty
25
+ # outside a trace.
26
+ def trace_function_keys
27
+ span_keys = @span_state[:trace_function_keys] || []
28
+ root_keys = Subtree.active_sessions.reverse.map(&:trace_function_key).uniq
29
+ (root_keys - span_keys) + span_keys
30
+ end
31
+
22
32
  # Add a context entry to this span.
23
33
  # The entire hash is pushed as a single entry in the contexts array.
24
34
  # Context entries are accumulated - multiple calls add to the list.
@@ -53,6 +63,15 @@ module Bitfab
53
63
  @trace_id = trace_id
54
64
  end
55
65
 
66
+ # The key of the trace function the current trace is stored under (the one
67
+ # that started it). A bitfab_span or get_function call inside another trace
68
+ # function joins that trace, so it reports the outer key. A bitfab_trace
69
+ # root inside another root starts its own trace, so it reports its own key.
70
+ # Empty string outside a trace.
71
+ def trace_function_key
72
+ TraceState.trace_function_key(@trace_id) || ""
73
+ end
74
+
56
75
  # Set the session ID for this trace.
57
76
  # Session ID is used to group traces from the same user session.
58
77
  # This is stored as a database column.
@@ -121,7 +140,8 @@ module Bitfab
121
140
  end
122
141
 
123
142
  # Thread-local span stack for tracking nested spans.
124
- # Each entry is a Hash with :trace_id and :span_id keys.
143
+ # Each entry is a Hash with :trace_id and :span_id keys, plus the span's own
144
+ # :trace_function_key and the :trace_function_keys running at it.
125
145
  module SpanContext
126
146
  STACK_KEY = :__bitfab_span_stack
127
147
  FIBER_BRIDGE_STACK_KEY = :__bitfab_span_fiber_bridge_stack
@@ -139,8 +159,9 @@ module Bitfab
139
159
  # Enumerator.new and enum_for run their source body in another Fiber on
140
160
  # the same thread. Bridge only the active Enumerator parent across that
141
161
  # boundary; ordinary fiber-local span stacks remain isolated.
142
- def with_fiber_bridge(trace_id:, span_id:, surface: nil)
162
+ def with_fiber_bridge(trace_id:, span_id:, surface: nil, trace_function_key: nil, trace_function_keys: nil)
143
163
  entry = {trace_id:, span_id:}
164
+ record_trace_function_keys(entry, trace_function_key, trace_function_keys)
144
165
  entry[:surface] = surface if surface
145
166
  fiber_bridge_stack.push(entry)
146
167
  yield
@@ -150,8 +171,9 @@ module Bitfab
150
171
 
151
172
  # Execute a block with a new span pushed onto the stack.
152
173
  # The span is automatically popped when the block completes.
153
- def with_span(trace_id:, span_id:, explicit_span_receiver: nil, explicit_span_method_name: nil, surface: nil, recording_override: nil, content_withheld: nil, sends_on_completion: nil)
174
+ def with_span(trace_id:, span_id:, explicit_span_receiver: nil, explicit_span_method_name: nil, surface: nil, recording_override: nil, content_withheld: nil, sends_on_completion: nil, trace_function_key: nil)
154
175
  entry = {trace_id:, span_id:}
176
+ record_trace_function_keys(entry, trace_function_key)
155
177
  entry[:sends_on_completion] = sends_on_completion if sends_on_completion
156
178
  entry[:surface] = surface if surface
157
179
  entry[:recording_override] = recording_override if recording_override
@@ -166,6 +188,22 @@ module Bitfab
166
188
  stack.pop
167
189
  end
168
190
 
191
+ # The trace function keys running at this point with the given key added
192
+ # at the end, each listed once. A nil key returns the running keys as is.
193
+ def trace_function_keys_with(trace_function_key)
194
+ running = current&.dig(:trace_function_keys) || []
195
+ trace_function_key ? running | [trace_function_key] : running
196
+ end
197
+
198
+ # Store a span's own trace function key and the keys running at that span
199
+ # on its stack entry, computing the running keys from the current span
200
+ # when they are not given. Nothing is stored when no key is running.
201
+ def record_trace_function_keys(entry, trace_function_key, trace_function_keys = nil)
202
+ entry[:trace_function_key] = trace_function_key if trace_function_key
203
+ keys = trace_function_keys || trace_function_keys_with(trace_function_key)
204
+ entry[:trace_function_keys] = keys unless keys.empty?
205
+ end
206
+
169
207
  def fiber_bridge_stack
170
208
  current_thread = Thread.current
171
209
  current_thread.thread_variable_get(FIBER_BRIDGE_STACK_KEY) || begin
@@ -208,6 +246,10 @@ module Bitfab
208
246
  end
209
247
  end
210
248
 
249
+ def trace_function_key(trace_id)
250
+ get(trace_id)&.dig(:trace_function_key)
251
+ end
252
+
211
253
  def delete(trace_id)
212
254
  @states_mutex.synchronize { @states.delete(trace_id) }
213
255
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bitfab
4
- VERSION = "0.75.0"
4
+ VERSION = "0.75.1"
5
5
  end
data/lib/bitfab.rb CHANGED
@@ -49,6 +49,10 @@ module Bitfab
49
49
  ""
50
50
  end
51
51
 
52
+ def trace_function_keys
53
+ []
54
+ end
55
+
52
56
  def add_context(_context)
53
57
  # No-op
54
58
  end
@@ -61,6 +65,10 @@ module Bitfab
61
65
  # No-op trace handle returned when outside a span context.
62
66
  # All methods do nothing, preventing crashes when called outside traced code.
63
67
  class NoOpCurrentTrace
68
+ def trace_function_key
69
+ ""
70
+ end
71
+
64
72
  def set_session_id(_session_id)
65
73
  # No-op
66
74
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitfab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.75.0
4
+ version: 0.75.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harvest Team