Module: Bitfab
- Defined in:
- lib/bitfab.rb,
lib/bitfab/client.rb,
lib/bitfab/replay.rb,
lib/bitfab/version.rb,
lib/bitfab/constants.rb,
lib/bitfab/serialize.rb,
lib/bitfab/traceable.rb,
lib/bitfab/warn_once.rb,
lib/bitfab/db_snapshot.rb,
lib/bitfab/http_client.rb,
lib/bitfab/span_context.rb,
lib/bitfab/mock_override.rb,
lib/bitfab/replay_branch.rb
Defined Under Namespace
Modules: DbSnapshot, MockOverride, Replay, ReplayContext, Serialize, SpanContext, TraceState, Traceable Classes: BitfabFunction, Client, CurrentSpan, CurrentTrace, HttpClient, NoOpCurrentSpan, NoOpCurrentTrace, ReplayBranch
Constant Summary collapse
- NO_OP_SPAN =
NoOpCurrentSpan.new.freeze
- NO_OP_TRACE =
NoOpCurrentTrace.new.freeze
- MOCK_STRATEGIES =
Replay mock strategies. Mirrors the Python and TypeScript SDKs.
- "marked" : only spans declared with mock_on_replay: true return historical output; everything else runs real code (default)
- "none" : every child span runs real code
- "all" : every child span returns its historical output
%w[none all marked].freeze
- VERSION =
"0.33.5"- DEFAULT_SERVICE_URL =
"https://bitfab.ai"- REPLAY_CONTEXT_KEY =
:__bitfab_replay_context- BITFAB_PROGRESS_PREFIX =
Wire prefix the Bitfab plugin scans for on stderr to report live progress while a replay runs. One trailing space, then the progress object as JSON.
"@@bitfab:progress "
Class Method Summary collapse
-
._reset_warn_once ⇒ Object
Test-only: clear the dedup set so a warning can fire again.
-
._run_in_background(&block) ⇒ Object
Run a block in a background thread with tracking.
-
.client ⇒ Object
Returns the global client, raising if not configured.
-
.client_or_nil ⇒ Object
Returns the global client, or nil if not configured.
-
.configure(api_key: nil, service_url: nil, enabled: true, strict: false) ⇒ Object
Configure the global Bitfab client.
-
.current_replay_branch ⇒ ReplayBranch?
Get the database branch the current replay item is running against.
-
.current_span ⇒ CurrentSpan, NoOpCurrentSpan
Get a handle to the current active span.
-
.current_trace ⇒ CurrentTrace, NoOpCurrentTrace
Get a handle to the current active trace.
-
.flush_traces(timeout: 30) ⇒ Object
Wait for all pending background threads to complete.
-
.report_replay_progress(progress) ⇒ Object
A ready-made on_progress callback for replay: writes one @@bitfab:progress line per trace to stderr, which the Bitfab plugin polls to report live progress while the replay runs in the background, so replay scripts never hand-format the protocol.
-
.reset! ⇒ Object
Reset the global client (primarily for testing).
- .warn_once(key, message) ⇒ Object
Class Method Details
._reset_warn_once ⇒ Object
Test-only: clear the dedup set so a warning can fire again.
31 32 33 |
# File 'lib/bitfab/warn_once.rb', line 31 def _reset_warn_once @warn_once_mutex.synchronize { @warn_once_seen.clear } end |
._run_in_background(&block) ⇒ Object
Run a block in a background thread with tracking. Returns the thread for callers that need to join on it.
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/bitfab/http_client.rb', line 292 def _run_in_background(&block) thread = Thread.new do block.call rescue => e Bitfab.warn_once( "send-request-failed", "failed to send a request to the backend (further occurrences " \ "suppressed): #{e.}" ) ensure @pending_threads_mutex.synchronize { @pending_threads.delete(Thread.current) } end @pending_threads_mutex.synchronize { @pending_threads << thread } thread end |
.client ⇒ Object
Returns the global client, raising if not configured.
76 77 78 |
# File 'lib/bitfab.rb', line 76 def client @client or raise "Bitfab not configured. Call Bitfab.configure(api_key: '...') first." end |
.client_or_nil ⇒ Object
Returns the global client, or nil if not configured. Used on the traced call path so a method invoked before Bitfab.configure runs untraced rather than crashing the host app with a "not configured" error.
83 84 85 |
# File 'lib/bitfab.rb', line 83 def client_or_nil @client end |
.configure(api_key: nil, service_url: nil, enabled: true, strict: false) ⇒ Object
Configure the global Bitfab client.
71 72 73 |
# File 'lib/bitfab.rb', line 71 def configure(api_key: nil, service_url: nil, enabled: true, strict: false) @client = Client.new(api_key:, service_url:, enabled:, strict:) end |
.current_replay_branch ⇒ ReplayBranch?
Get the database branch the current replay item is running against.
Call this from inside a method being replayed with
client.replay(db_branch: ...) and point your database client at
branch.database_url so the replay reads the data as it was at trace
time:
branch = Bitfab.current_replay_branch
url = branch ? branch.database_url : ENV["DATABASE_URL"]
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/bitfab.rb', line 117 def current_replay_branch ctx = ReplayContext.current return nil unless ctx lease = ctx[:db_branch_lease] return nil unless lease # Surface the Bitfab trace ID (what the customer sees in the dashboard), # not the external one. Falling back to the external ID keeps replays from # external sources working until that path is fully wired. trace_id = ctx[:source_bitfab_trace_id] || ctx[:input_source_trace_id] return nil unless trace_id ReplayBranch.new(lease, trace_id, ctx) end |
.current_span ⇒ CurrentSpan, NoOpCurrentSpan
Get a handle to the current active span.
Call this from inside a traced method to get a span handle that allows setting metadata at runtime.
98 99 100 101 102 103 |
# File 'lib/bitfab.rb', line 98 def current_span entry = SpanContext.current return NO_OP_SPAN unless entry CurrentSpan.new(entry) end |
.current_trace ⇒ CurrentTrace, NoOpCurrentTrace
Get a handle to the current active trace.
Call this from inside a traced method to get a trace handle that allows setting trace-level context at runtime.
139 140 141 142 143 144 |
# File 'lib/bitfab.rb', line 139 def current_trace entry = SpanContext.current return NO_OP_TRACE unless entry CurrentTrace.new(entry[:trace_id]) end |
.flush_traces(timeout: 30) ⇒ Object
Wait for all pending background threads to complete.
310 311 312 313 |
# File 'lib/bitfab/http_client.rb', line 310 def flush_traces(timeout: 30) threads = @pending_threads_mutex.synchronize { @pending_threads.dup } threads.each { |t| t.join(timeout) } end |
.report_replay_progress(progress) ⇒ Object
A ready-made on_progress callback for replay: writes one @@bitfab:progress line per trace to stderr, which the Bitfab plugin polls to report live progress while the replay runs in the background, so replay scripts never hand-format the protocol. stdout stays the ReplayResult JSON. Never raises (progress must not crash a run). The progress hash's item is forwarded verbatim through to_json, so the plugin sees the source trace id, local replay trace id, outputs, error, and duration of the item that just settled.
160 161 162 163 164 |
# File 'lib/bitfab.rb', line 160 def report_replay_progress(progress) warn "#{BITFAB_PROGRESS_PREFIX}#{progress.to_json}" rescue nil end |
.reset! ⇒ Object
Reset the global client (primarily for testing).
88 89 90 |
# File 'lib/bitfab.rb', line 88 def reset! @client = nil end |
.warn_once(key, message) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/bitfab/warn_once.rb', line 17 def warn_once(key, ) @warn_once_mutex.synchronize do return if @warn_once_seen.include?(key) @warn_once_seen.add(key) end begin warn "Bitfab: #{}" rescue Exception # rubocop:disable Lint/RescueException # Logging must never crash the host app (e.g. a closed $stderr). end end |