bitfab 0.57.8 → 0.58.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/README.md +1 -1
- data/lib/bitfab/client.rb +13 -9
- data/lib/bitfab/http_client.rb +6 -2
- data/lib/bitfab/simulation_plan.rb +8 -6
- data/lib/bitfab/subtree.rb +14 -39
- data/lib/bitfab/trace_completion.rb +4 -0
- data/lib/bitfab/traceable.rb +5 -16
- data/lib/bitfab/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: 49c5627d0b0880adf5971614d2b017bf97a1886313776b757996d1bdab1d1f92
|
|
4
|
+
data.tar.gz: cce67f5a022711dc884d9b391d2daa4547b5fc11fdff1ab159c7a5b82fb404bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 28f813f00802eda3f55615bf5acba0264d6e9a80130117522436eefb943be3fbd17753289a6a2f7e6295ed9772380221a89a9c3e8477041b974f5d3f4cde917f
|
|
7
|
+
data.tar.gz: a15a81f27f2ef548b854a7b53cdd32a813583b31066a0cba8a40aa364c1bdf9e771f9534bd0aab8b5355bc146fbff18ec0a1cfb9a417634e28ab9691e6cdc6c7
|
data/README.md
CHANGED
|
@@ -235,7 +235,7 @@ class OrderPipeline
|
|
|
235
235
|
end
|
|
236
236
|
```
|
|
237
237
|
|
|
238
|
-
Capture uses `TracePoint` only during the root call. It skips Ruby/runtime code, dependency gems, Bitfab SDK internals, blocks, lambdas, and forwarding wrappers. When the root belongs to an installed application gem, that gem is the first-party boundary; neighboring dependency gems remain excluded. It follows recursion, modules, inheritance, `define_method`, and same-thread child Fibers; aliases are recorded and excluded by the name that was invoked. Child Fibers created during capture inherit node policies, trace identity, parenting, and depth limits while retaining separate call stacks. Pre-existing Fibers, `Fiber.new(storage: nil)`, and child threads do not inherit subtree context. When an inner capture ends, child Fibers retain any still-active outer capture; inherited context expires once all enclosing captures end. While a root remains active, hitting a span limit stops new capture but allows already-open spans in every Fiber to finish. `max_depth:` (default `30`), `max_captured_subtree_spans:` (default `500`), `
|
|
238
|
+
Capture uses `TracePoint` only during the root call. It skips Ruby/runtime code, dependency gems, Bitfab SDK internals, blocks, lambdas, and forwarding wrappers. When the root belongs to an installed application gem, that gem is the first-party boundary; neighboring dependency gems remain excluded. It follows recursion, modules, inheritance, `define_method`, and same-thread child Fibers; aliases are recorded and excluded by the name that was invoked. Child Fibers created during capture inherit node policies, trace identity, parenting, and depth limits while retaining separate call stacks. Pre-existing Fibers, `Fiber.new(storage: nil)`, and child threads do not inherit subtree context. When an inner capture ends, child Fibers retain any still-active outer capture; inherited context expires once all enclosing captures end. While a root remains active, hitting a span limit stops new capture but allows already-open spans in every Fiber to finish. `max_depth:` (default `30`), `max_captured_subtree_spans:` (default `500`), `exclude:`, and `include_wrappers:` control the subtree. There is no cap on the total number of spans one trace root sends. `max_spans:` was removed, and passing it raises `ArgumentError`. `max_captured_subtree_spans:` caps discovered calls sent with their inputs and outputs. It does not count `bitfab_node` calls, nested trace roots, or spans the loaded sim plan turned capture off for, so those keep recording past it. Spans sent without inputs and outputs only because the sim plan could not be read still count toward it. Past it, further discovered calls with capture on record nothing. Once the plan has loaded, the SDK does not send a span whose capture it turned off, and that span's children move up to the nearest visible parent. The trace's root span, a framework integration span, and a span that recorded an error are still sent, and the SDK never builds their inputs or outputs. A `bitfab_node` call and a nested trace root ignore the plan and always keep their inputs and outputs. The client starts reading the sim plan when it is built. A `bitfab_trace` root that starts while that first read is still running waits for it, for at most five seconds. Once the first read has finished, whether it succeeded or failed, no later root waits. Nested roots and the calls beneath a root never wait, and nothing waits when the plan is disabled. If that first read fails, spans other than each trace's root span, `bitfab_node` calls, and nested trace roots are sent without inputs and outputs until a read succeeds, and they still count toward `max_captured_subtree_spans:`. Automatically captured calls are not replay mock targets. Declare a call with `bitfab_node` when replay must substitute it. The configured node records once in each enclosing trace. Mixing explicit spans with subtree tracing raises `Bitfab::MixedTracingError`.
|
|
239
239
|
|
|
240
240
|
When capture ends, already-open automatic calls in suspended Fibers are emitted once with a nil output and `Subtree capture ended before the call returned` as the error, unless a real error was already observed. Their inputs and parenting are retained. The SDK does not resume Fibers, and later resumption cannot add spans to the ended capture. If hot reload moves the root to an unresolved source, the last valid first-party boundary and its exclusions remain in use.
|
|
241
241
|
|
data/lib/bitfab/client.rb
CHANGED
|
@@ -376,7 +376,7 @@ module Bitfab
|
|
|
376
376
|
capture_when: "always", mock_on_replay: false, independent_root: false,
|
|
377
377
|
explicit_span_receiver: nil, explicit_span_method_name: nil, test_run_id: nil, finalize: nil,
|
|
378
378
|
surface: nil, on_start: nil, on_complete: nil, around_body: nil, span_data: {}, managed_root: false,
|
|
379
|
-
result_recorded_elsewhere: false)
|
|
379
|
+
result_recorded_elsewhere: false, declared_node: false)
|
|
380
380
|
return yield unless should_record?
|
|
381
381
|
|
|
382
382
|
@http_client.refresh_simulation_plan
|
|
@@ -477,7 +477,8 @@ module Bitfab
|
|
|
477
477
|
test_run_id: resolved_test_run_id,
|
|
478
478
|
input_source_span_id: resolved_input_source_span_id,
|
|
479
479
|
mock_source:,
|
|
480
|
-
instrumentation: (surface == :trace) ? "trace" : "span"
|
|
480
|
+
instrumentation: (surface == :trace) ? "trace" : "span",
|
|
481
|
+
declared_node:
|
|
481
482
|
)
|
|
482
483
|
on_complete&.call(result: mocked_output, error: nil, ended_at: Bitfab.now_iso_timestamp)
|
|
483
484
|
return mocked_output
|
|
@@ -509,6 +510,8 @@ module Bitfab
|
|
|
509
510
|
@http_client.trace_completion.start(trace_id, span_id)
|
|
510
511
|
recording_override = managed_root ? {} : nil
|
|
511
512
|
content_withheld = lambda do
|
|
513
|
+
next false if declared_node
|
|
514
|
+
|
|
512
515
|
instrumentation = recording_override&.dig(:instrumentation) || ((surface == :trace) ? "trace" : "span")
|
|
513
516
|
content_off_by_simulation_plan?(
|
|
514
517
|
trace_id:, trace_function_key:, span_name: recording_override&.dig(:name) || span_name, instrumentation:
|
|
@@ -544,6 +547,7 @@ module Bitfab
|
|
|
544
547
|
send_span(
|
|
545
548
|
span_data: content_off ? span_data.merge("content_off_by_simulation_plan" => true) : span_data,
|
|
546
549
|
instrumentation: recorded_instrumentation,
|
|
550
|
+
declared_node:,
|
|
547
551
|
trace_function_key:,
|
|
548
552
|
trace_id:,
|
|
549
553
|
span_id:,
|
|
@@ -921,7 +925,7 @@ module Bitfab
|
|
|
921
925
|
def send_span(trace_function_key:, trace_id:, span_id:, parent_span_id:,
|
|
922
926
|
span_name:, span_type:, function_name:, contexts:, prompt:, args:, kwargs:, result:, error:,
|
|
923
927
|
started_at:, ended_at:, test_run_id: nil, input_source_span_id: nil, mocked: false,
|
|
924
|
-
mock_target: nil, mock_source: nil, span_data: {}, instrumentation: "span")
|
|
928
|
+
mock_target: nil, mock_source: nil, span_data: {}, instrumentation: "span", declared_node: false)
|
|
925
929
|
extra_span_data = span_data
|
|
926
930
|
# If drop() was called on this trace, suppress the span PAYLOAD upload for
|
|
927
931
|
# every span that completes after the flag was set. The trace completion
|
|
@@ -933,9 +937,9 @@ module Bitfab
|
|
|
933
937
|
# Human-readable JSON (input/output fields). The *_with_report variants
|
|
934
938
|
# also report what could not be faithfully captured so a lossy span is
|
|
935
939
|
# marked non-replayable below instead of shipping as if it round-trips.
|
|
936
|
-
content_off = extra_span_data["content_off_by_simulation_plan"] == true ||
|
|
940
|
+
content_off = !declared_node && (extra_span_data["content_off_by_simulation_plan"] == true ||
|
|
937
941
|
content_off_by_simulation_plan?(trace_id:, trace_function_key:, span_name:, instrumentation:) ||
|
|
938
|
-
(!parent_span_id.nil? && simulation_plan_unavailable?(instrumentation:))
|
|
942
|
+
(!parent_span_id.nil? && simulation_plan_unavailable?(instrumentation:)))
|
|
939
943
|
if content_off
|
|
940
944
|
dropped = []
|
|
941
945
|
span_data = {"name" => span_name, "type" => span_type, "function_name" => function_name}
|
|
@@ -1011,7 +1015,7 @@ module Bitfab
|
|
|
1011
1015
|
}]
|
|
1012
1016
|
end
|
|
1013
1017
|
|
|
1014
|
-
@http_client.send_external_span(payload)
|
|
1018
|
+
@http_client.send_external_span(payload, declared_node)
|
|
1015
1019
|
end
|
|
1016
1020
|
|
|
1017
1021
|
# Advance the per-(key, name) call counter when this invocation is a
|
|
@@ -1141,7 +1145,7 @@ module Bitfab
|
|
|
1141
1145
|
# output as the result and no error.
|
|
1142
1146
|
def send_mocked_span(trace_function_key:, trace_id:, span_id:, parent_span_id:,
|
|
1143
1147
|
span_name:, span_type:, function_name:, args:, kwargs:, mocked_output:,
|
|
1144
|
-
started_at:, test_run_id:, input_source_span_id:, mock_source:, instrumentation: "span")
|
|
1148
|
+
started_at:, test_run_id:, input_source_span_id:, mock_source:, instrumentation: "span", declared_node: false)
|
|
1145
1149
|
ended_at = Bitfab.now_iso_timestamp
|
|
1146
1150
|
send_span(
|
|
1147
1151
|
trace_function_key:,
|
|
@@ -1163,6 +1167,7 @@ module Bitfab
|
|
|
1163
1167
|
input_source_span_id:,
|
|
1164
1168
|
mocked: true,
|
|
1165
1169
|
instrumentation:,
|
|
1170
|
+
declared_node:,
|
|
1166
1171
|
# Both paths short-circuit the call, so the target is always the
|
|
1167
1172
|
# output; only where the value came from differs.
|
|
1168
1173
|
mock_target: "output",
|
|
@@ -1223,7 +1228,7 @@ module Bitfab
|
|
|
1223
1228
|
|
|
1224
1229
|
# Experimentally trace an existing method and its first-party call subtree.
|
|
1225
1230
|
def trace(klass, method_name, name: nil, type: "custom",
|
|
1226
|
-
max_depth: Subtree::DEFAULT_MAX_DEPTH,
|
|
1231
|
+
max_depth: Subtree::DEFAULT_MAX_DEPTH,
|
|
1227
1232
|
max_captured_subtree_spans: Subtree::DEFAULT_MAX_CAPTURED_SUBTREE_SPANS,
|
|
1228
1233
|
exclude: [], include_wrappers: false, mock_on_replay_default: false)
|
|
1229
1234
|
Bitfab::Traceable.trace(
|
|
@@ -1232,7 +1237,6 @@ module Bitfab
|
|
|
1232
1237
|
name:,
|
|
1233
1238
|
type:,
|
|
1234
1239
|
max_depth:,
|
|
1235
|
-
max_spans:,
|
|
1236
1240
|
max_captured_subtree_spans:,
|
|
1237
1241
|
exclude:,
|
|
1238
1242
|
include_wrappers:,
|
data/lib/bitfab/http_client.rb
CHANGED
|
@@ -188,7 +188,7 @@ module Bitfab
|
|
|
188
188
|
end
|
|
189
189
|
|
|
190
190
|
# Queue an external span on this client's trace transport (fire-and-forget).
|
|
191
|
-
def send_external_span(payload)
|
|
191
|
+
def send_external_span(payload, declared_node = false)
|
|
192
192
|
if (data = payload.dig("rawSpan", "span_data")).is_a?(Hash) && !data.key?("runtime")
|
|
193
193
|
payload = payload.merge("rawSpan" => payload["rawSpan"].merge("span_data" => data.merge("runtime" => ThreadPropagation.runtime)))
|
|
194
194
|
end
|
|
@@ -204,7 +204,11 @@ module Bitfab
|
|
|
204
204
|
recorded_meta("external_span", record, ref)
|
|
205
205
|
)
|
|
206
206
|
}
|
|
207
|
-
|
|
207
|
+
discard = ->(record) {
|
|
208
|
+
ref = carrier_ref(record)
|
|
209
|
+
@trace_completion.discard(ref.trace_id, ref.span_id) if ref&.span_id
|
|
210
|
+
}
|
|
211
|
+
@simulation_plan ? @simulation_plan.send_span(payload, declared_node:, discard:, &submit) : submit.call(payload)
|
|
208
212
|
end
|
|
209
213
|
|
|
210
214
|
def send_internal_trace(function_id, payload)
|
|
@@ -69,7 +69,7 @@ module Bitfab
|
|
|
69
69
|
@mutex.synchronize { start_reader(0) if @thread.nil? && now >= @refresh_after }
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
def send_span(payload, &submit)
|
|
72
|
+
def send_span(payload, declared_node: false, discard: nil, &submit)
|
|
73
73
|
refresh
|
|
74
74
|
data = payload.dig("rawSpan", "span_data")
|
|
75
75
|
key = payload["rootTraceFunctionKey"] || payload["traceFunctionKey"]
|
|
@@ -77,7 +77,7 @@ module Bitfab
|
|
|
77
77
|
submit.call(payload)
|
|
78
78
|
return
|
|
79
79
|
end
|
|
80
|
-
entry = [payload, key, submit]
|
|
80
|
+
entry = [payload, key, submit, discard, declared_node]
|
|
81
81
|
ready = @mutex.synchronize { reading? ? hold(entry) : entry }
|
|
82
82
|
deliver(*ready) if ready
|
|
83
83
|
end
|
|
@@ -164,6 +164,7 @@ module Bitfab
|
|
|
164
164
|
names = @mutex.synchronize { @content_off&.fetch(key, nil) }
|
|
165
165
|
data = payload.dig("rawSpan", "span_data")
|
|
166
166
|
return payload unless data.is_a?(Hash) && names&.include?(data["name"])
|
|
167
|
+
return nil unless root?(payload) || data["error"]
|
|
167
168
|
|
|
168
169
|
without_content(payload, data)
|
|
169
170
|
end
|
|
@@ -196,12 +197,13 @@ module Bitfab
|
|
|
196
197
|
@held.shift if @held.length > MAX_HELD
|
|
197
198
|
end
|
|
198
199
|
|
|
199
|
-
def deliver(payload, key, submit)
|
|
200
|
-
|
|
200
|
+
def deliver(payload, key, submit, discard = nil, declared_node = false)
|
|
201
|
+
record = declared_node ? payload : prepare(payload, key)
|
|
202
|
+
record ? submit.call(record) : discard&.call(payload)
|
|
201
203
|
end
|
|
202
204
|
|
|
203
|
-
def deliver_safely(payload, key, submit)
|
|
204
|
-
deliver(payload, key, submit)
|
|
205
|
+
def deliver_safely(payload, key, submit, discard = nil, declared_node = false)
|
|
206
|
+
deliver(payload, key, submit, discard, declared_node)
|
|
205
207
|
rescue => error
|
|
206
208
|
Bitfab.warn_once("sim-plan-held-span-dropped", "Held record could not be sent: #{error}")
|
|
207
209
|
end
|
data/lib/bitfab/subtree.rb
CHANGED
|
@@ -10,9 +10,8 @@ module Bitfab
|
|
|
10
10
|
|
|
11
11
|
module Subtree
|
|
12
12
|
DEFAULT_MAX_DEPTH = 30
|
|
13
|
-
DEFAULT_MAX_SPANS = 10_000
|
|
14
13
|
DEFAULT_MAX_CAPTURED_SUBTREE_SPANS = 500
|
|
15
|
-
LIMIT_ORDER = %i[max_depth
|
|
14
|
+
LIMIT_ORDER = %i[max_depth max_captured_subtree_spans].freeze
|
|
16
15
|
SESSION_KEY = :bitfab_subtree_session
|
|
17
16
|
DISPATCHER_KEY = :bitfab_subtree_dispatcher
|
|
18
17
|
FIBER_CONTEXT_KEY = :bitfab_subtree_fiber_context
|
|
@@ -53,6 +52,7 @@ module Bitfab
|
|
|
53
52
|
:span_type,
|
|
54
53
|
:test_run_id,
|
|
55
54
|
:span_data,
|
|
55
|
+
:declared_node,
|
|
56
56
|
keyword_init: true
|
|
57
57
|
)
|
|
58
58
|
|
|
@@ -175,7 +175,7 @@ module Bitfab
|
|
|
175
175
|
CaptureConfig.new(root: nil, root_path: nil, exclude: {}.freeze).freeze
|
|
176
176
|
end
|
|
177
177
|
|
|
178
|
-
def capture(client:, trace_function_key:, config:, max_depth:,
|
|
178
|
+
def capture(client:, trace_function_key:, config:, max_depth:, include_wrappers:,
|
|
179
179
|
root_receiver:, root_method_name:, max_captured_subtree_spans: DEFAULT_MAX_CAPTURED_SUBTREE_SPANS, mock_on_replay_default: false)
|
|
180
180
|
return yield unless config.root
|
|
181
181
|
|
|
@@ -193,7 +193,6 @@ module Bitfab
|
|
|
193
193
|
input_source_span_id: replay&.dig(:input_source_span_id),
|
|
194
194
|
config:,
|
|
195
195
|
max_depth:,
|
|
196
|
-
max_spans:,
|
|
197
196
|
max_captured_subtree_spans:,
|
|
198
197
|
include_wrappers:,
|
|
199
198
|
mock_on_replay_default:,
|
|
@@ -418,7 +417,7 @@ module Bitfab
|
|
|
418
417
|
end
|
|
419
418
|
|
|
420
419
|
def initialize(client:, trace_function_key:, trace_id:, root_span_id:, test_run_id:,
|
|
421
|
-
input_source_span_id:, config:, max_depth:,
|
|
420
|
+
input_source_span_id:, config:, max_depth:, include_wrappers:,
|
|
422
421
|
root_receiver:, root_method_name:, max_captured_subtree_spans: DEFAULT_MAX_CAPTURED_SUBTREE_SPANS, mock_on_replay_default: false)
|
|
423
422
|
@mock_on_replay_default = mock_on_replay_default
|
|
424
423
|
@client = client
|
|
@@ -433,8 +432,7 @@ module Bitfab
|
|
|
433
432
|
@root_method_name = root_method_name.to_sym
|
|
434
433
|
@skip_root_call = true
|
|
435
434
|
@max_depth = max_depth
|
|
436
|
-
@
|
|
437
|
-
@max_captured_subtree_spans = [max_captured_subtree_spans, max_spans].min
|
|
435
|
+
@max_captured_subtree_spans = max_captured_subtree_spans
|
|
438
436
|
@exclude = config.exclude
|
|
439
437
|
@include_wrappers = include_wrappers
|
|
440
438
|
@stacks = {}
|
|
@@ -443,7 +441,6 @@ module Bitfab
|
|
|
443
441
|
@suppressed_depths = {}
|
|
444
442
|
@owned_paths = {}
|
|
445
443
|
@method_metadata = Hash.new { |owners, owner| owners[owner] = {} }
|
|
446
|
-
@spans_used = 1
|
|
447
444
|
@captured_subtree_count = 0
|
|
448
445
|
@limits_fired = Set.new
|
|
449
446
|
@dropped_spans = 0
|
|
@@ -524,14 +521,9 @@ module Bitfab
|
|
|
524
521
|
|
|
525
522
|
def reserve_node
|
|
526
523
|
stack = current_stack(Fiber.current.object_id)
|
|
527
|
-
if captured_depth(stack)
|
|
528
|
-
drop(:max_depth)
|
|
529
|
-
return false
|
|
530
|
-
end
|
|
531
|
-
return true if take_slot(discovered: false)
|
|
524
|
+
return true if captured_depth(stack) < @max_depth
|
|
532
525
|
|
|
533
|
-
drop(:
|
|
534
|
-
@exhausted = true
|
|
526
|
+
drop(:max_depth)
|
|
535
527
|
false
|
|
536
528
|
end
|
|
537
529
|
|
|
@@ -547,7 +539,7 @@ module Bitfab
|
|
|
547
539
|
span_id: SecureRandom.uuid,
|
|
548
540
|
parent_span_id: current_parent_span_id,
|
|
549
541
|
name:, span_type: type, args:, kwargs:, test_run_id:, started_at: now,
|
|
550
|
-
span_data: {}
|
|
542
|
+
span_data: {}, declared_node: true
|
|
551
543
|
)
|
|
552
544
|
@configured_entries[entry.object_id] = entry
|
|
553
545
|
entry
|
|
@@ -652,9 +644,9 @@ module Bitfab
|
|
|
652
644
|
return
|
|
653
645
|
end
|
|
654
646
|
content_off = content_off?(metadata.name)
|
|
655
|
-
if
|
|
656
|
-
drop(
|
|
657
|
-
stop_discovery(fiber_id) unless
|
|
647
|
+
if !content_off && @captured_subtree_count >= @max_captured_subtree_spans
|
|
648
|
+
drop(:max_captured_subtree_spans)
|
|
649
|
+
stop_discovery(fiber_id) unless content_off_names?
|
|
658
650
|
return
|
|
659
651
|
end
|
|
660
652
|
|
|
@@ -665,7 +657,7 @@ module Bitfab
|
|
|
665
657
|
return
|
|
666
658
|
end
|
|
667
659
|
|
|
668
|
-
|
|
660
|
+
@captured_subtree_count += 1 unless content_off
|
|
669
661
|
span_id = SecureRandom.uuid
|
|
670
662
|
without_content = content_off || plan_unavailable?
|
|
671
663
|
args, kwargs = without_content ? [[], {}] : inputs(event)
|
|
@@ -741,6 +733,7 @@ module Bitfab
|
|
|
741
733
|
span_name: entry.name,
|
|
742
734
|
span_type: entry.span_type || "function",
|
|
743
735
|
instrumentation: "trace",
|
|
736
|
+
declared_node: entry.declared_node == true,
|
|
744
737
|
span_data: entry.span_data || {},
|
|
745
738
|
function_name: entry.name,
|
|
746
739
|
contexts: nil,
|
|
@@ -890,24 +883,6 @@ module Bitfab
|
|
|
890
883
|
@suppressed_depths[fiber_id] = 1
|
|
891
884
|
end
|
|
892
885
|
|
|
893
|
-
def limit_reached(discovered:, content_off: false)
|
|
894
|
-
return :max_spans if @spans_used >= @max_spans
|
|
895
|
-
|
|
896
|
-
:max_captured_subtree_spans if discovered && !content_off && @captured_subtree_count >= @max_captured_subtree_spans
|
|
897
|
-
end
|
|
898
|
-
|
|
899
|
-
def take_slot(discovered:)
|
|
900
|
-
return false if limit_reached(discovered:)
|
|
901
|
-
|
|
902
|
-
count_span(discovered:, content_off: false)
|
|
903
|
-
true
|
|
904
|
-
end
|
|
905
|
-
|
|
906
|
-
def count_span(discovered:, content_off:)
|
|
907
|
-
@spans_used += 1
|
|
908
|
-
@captured_subtree_count += 1 if discovered && !content_off
|
|
909
|
-
end
|
|
910
|
-
|
|
911
886
|
def stop_discovery(fiber_id)
|
|
912
887
|
@exhausted = true
|
|
913
888
|
if captured_calls_drained?
|
|
@@ -968,7 +943,7 @@ module Bitfab
|
|
|
968
943
|
Bitfab.warn_once(
|
|
969
944
|
"subtree-truncated:#{@trace_function_key}",
|
|
970
945
|
"'#{@trace_function_key}' hit a subtree capture limit (max_depth=#{@max_depth}, " \
|
|
971
|
-
"max_captured_subtree_spans=#{@max_captured_subtree_spans}
|
|
946
|
+
"max_captured_subtree_spans=#{@max_captured_subtree_spans}) and its trace is incomplete. " \
|
|
972
947
|
"Raise the limits, add bitfab_node to the calls that matter, or narrow what is traced with exclude: [...]."
|
|
973
948
|
)
|
|
974
949
|
end
|
data/lib/bitfab/traceable.rb
CHANGED
|
@@ -82,10 +82,9 @@ module Bitfab
|
|
|
82
82
|
# The root records with the requested type; first-party Ruby methods called
|
|
83
83
|
# beneath it record automatically as function spans.
|
|
84
84
|
def self.trace(klass, method_name, trace_function_key:, name: nil, type: "custom",
|
|
85
|
-
max_depth: Subtree::DEFAULT_MAX_DEPTH,
|
|
85
|
+
max_depth: Subtree::DEFAULT_MAX_DEPTH,
|
|
86
86
|
max_captured_subtree_spans: Subtree::DEFAULT_MAX_CAPTURED_SUBTREE_SPANS,
|
|
87
87
|
exclude: [], include_wrappers: false, mock_on_replay_default: false, client: nil)
|
|
88
|
-
validate_trace_options!(max_spans:)
|
|
89
88
|
capture_config = Subtree.prepare(root_source: source_of(klass, method_name), exclude:)
|
|
90
89
|
method_name_str = method_name.to_s
|
|
91
90
|
bound_client = client
|
|
@@ -106,7 +105,7 @@ module Bitfab
|
|
|
106
105
|
SpanContext.current[:surface] = :trace
|
|
107
106
|
next Subtree.capture(
|
|
108
107
|
client: target_client, trace_function_key:, config: capture_config,
|
|
109
|
-
max_depth:,
|
|
108
|
+
max_depth:, max_captured_subtree_spans:, include_wrappers:, mock_on_replay_default:,
|
|
110
109
|
root_receiver: self, root_method_name: method_name
|
|
111
110
|
) { super(*args, **kwargs, &block) }
|
|
112
111
|
end
|
|
@@ -120,7 +119,7 @@ module Bitfab
|
|
|
120
119
|
around_body: call.method(:run)) do
|
|
121
120
|
Subtree.capture(
|
|
122
121
|
client: target_client, trace_function_key:, config: capture_config,
|
|
123
|
-
max_depth:,
|
|
122
|
+
max_depth:, max_captured_subtree_spans:, include_wrappers:, mock_on_replay_default:,
|
|
124
123
|
root_receiver: self, root_method_name: method_name
|
|
125
124
|
) { super(*args, **kwargs, &block) }
|
|
126
125
|
end
|
|
@@ -165,7 +164,7 @@ module Bitfab
|
|
|
165
164
|
span_name:, span_type: type, function_name: method_name_str,
|
|
166
165
|
args:, kwargs:, capture_when: "nested", mock_on_replay: policy,
|
|
167
166
|
explicit_span_receiver: self, explicit_span_method_name: method_name,
|
|
168
|
-
test_run_id:, finalize:, surface: :trace, result_recorded_elsewhere: call.recorded_elsewhere?,
|
|
167
|
+
test_run_id:, finalize:, surface: :trace, result_recorded_elsewhere: call.recorded_elsewhere?, declared_node: true,
|
|
169
168
|
on_start: call.method(:start), on_complete: call.method(:complete),
|
|
170
169
|
around_body: call.method(:run)) { super(*args, **kwargs, &block) }
|
|
171
170
|
end
|
|
@@ -193,14 +192,6 @@ module Bitfab
|
|
|
193
192
|
end
|
|
194
193
|
private_class_method :preserve_visibility
|
|
195
194
|
|
|
196
|
-
def self.validate_trace_options!(max_spans:)
|
|
197
|
-
return if max_spans.is_a?(Integer) && max_spans >= 1
|
|
198
|
-
|
|
199
|
-
raise ArgumentError,
|
|
200
|
-
"bitfab_trace max_spans must be an integer of at least 1 because the root span takes one slot, got #{max_spans.inspect}."
|
|
201
|
-
end
|
|
202
|
-
private_class_method :validate_trace_options!
|
|
203
|
-
|
|
204
195
|
def self.validate_node_options!(capture:, mock_on_replay:)
|
|
205
196
|
return unless !capture && mock_on_replay
|
|
206
197
|
|
|
@@ -304,10 +295,9 @@ module Bitfab
|
|
|
304
295
|
# EXPERIMENTAL. Trace a method and every first-party Ruby method it calls.
|
|
305
296
|
# Descendants require no Bitfab declarations and record as function spans.
|
|
306
297
|
def bitfab_trace(method_name, trace_function_key: nil, name: nil, type: "custom",
|
|
307
|
-
max_depth: Subtree::DEFAULT_MAX_DEPTH,
|
|
298
|
+
max_depth: Subtree::DEFAULT_MAX_DEPTH,
|
|
308
299
|
max_captured_subtree_spans: Subtree::DEFAULT_MAX_CAPTURED_SUBTREE_SPANS,
|
|
309
300
|
exclude: [], include_wrappers: false, mock_on_replay_default: false)
|
|
310
|
-
Traceable.send(:validate_trace_options!, max_spans:)
|
|
311
301
|
trace_function_key ||= @bitfab_function_key
|
|
312
302
|
unless trace_function_key
|
|
313
303
|
raise "No trace function key provided. Pass `trace_function_key:` to `bitfab_trace` " \
|
|
@@ -319,7 +309,6 @@ module Bitfab
|
|
|
319
309
|
name:,
|
|
320
310
|
type:,
|
|
321
311
|
max_depth:,
|
|
322
|
-
max_spans:,
|
|
323
312
|
max_captured_subtree_spans:,
|
|
324
313
|
exclude:,
|
|
325
314
|
include_wrappers:,
|
data/lib/bitfab/version.rb
CHANGED