bitfab 0.36.0 → 0.36.2
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/bitfab/client.rb +4 -0
- data/lib/bitfab/http_client.rb +10 -5
- data/lib/bitfab/replay.rb +13 -7
- data/lib/bitfab/replay_branch.rb +59 -9
- 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: 44af81a548095fe4bf8a347b6e58bb1c3bdcf2726becd78f029ec5c7c9507ca9
|
|
4
|
+
data.tar.gz: 4a00a95452cf45e5992e7eee4754850923eed8767713368a063fa1fed84d4b7c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9043c05ffb79c8830299127c39de0dc77b77dc3fa1fd2a573813696bcd9a7ba3fa95d7a06a7371ff596ed04781f439311f773bdff24afe055b252b36e0d36bb5
|
|
7
|
+
data.tar.gz: d73327657254114a22c091bb58503c17f1f8d0fcc19f0179c283b452df4c7240d446ff8d36962b16fcc47ea13e0315c80f554280b79f47b684f24ba50b11ce23
|
data/lib/bitfab/client.rb
CHANGED
|
@@ -407,6 +407,7 @@ module Bitfab
|
|
|
407
407
|
{
|
|
408
408
|
neon_branch_id: lease["neonBranchId"],
|
|
409
409
|
snapshot_timestamp: lease["snapshotTimestamp"],
|
|
410
|
+
region: lease["region"],
|
|
410
411
|
original_trace_id: replay_ctx[:source_bitfab_trace_id],
|
|
411
412
|
# Deprecated wire alias, kept so this SDK still reports usage
|
|
412
413
|
# against servers that predate the rename.
|
|
@@ -593,6 +594,9 @@ module Bitfab
|
|
|
593
594
|
if db_snapshot_usage[:snapshot_timestamp]
|
|
594
595
|
usage["snapshot_timestamp"] = db_snapshot_usage[:snapshot_timestamp]
|
|
595
596
|
end
|
|
597
|
+
if db_snapshot_usage[:region]
|
|
598
|
+
usage["region"] = db_snapshot_usage[:region]
|
|
599
|
+
end
|
|
596
600
|
if db_snapshot_usage[:original_trace_id]
|
|
597
601
|
usage["original_trace_id"] = db_snapshot_usage[:original_trace_id]
|
|
598
602
|
# Deprecated wire alias, kept so this SDK still reports usage
|
data/lib/bitfab/http_client.rb
CHANGED
|
@@ -181,9 +181,11 @@ module Bitfab
|
|
|
181
181
|
request("/api/sdk/replay/start", payload, timeout:)
|
|
182
182
|
end
|
|
183
183
|
|
|
184
|
-
# Fetch an external span by ID. Blocking GET request.
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
# Fetch an external span by ID. Blocking GET request. The replay view keeps
|
|
185
|
+
# only the input/output serialization fields used by replay.
|
|
186
|
+
def get_external_span(span_id, replay_view: false)
|
|
187
|
+
query = replay_view ? "?view=replay" : ""
|
|
188
|
+
get("/api/sdk/externalSpans/#{span_id}#{query}", timeout: 30)
|
|
187
189
|
end
|
|
188
190
|
|
|
189
191
|
def get_trace_span(trace_id, id: nil, name: nil, occurrence: "last")
|
|
@@ -210,9 +212,12 @@ module Bitfab
|
|
|
210
212
|
# payloads so only the spans actually mocked are fetched later (by
|
|
211
213
|
# externalSpanId), avoiding dragging down every span's output when only a
|
|
212
214
|
# few are mocked.
|
|
213
|
-
def get_span_tree(external_span_id, include_outputs: true)
|
|
215
|
+
def get_span_tree(external_span_id, include_outputs: true, include_root_output: true)
|
|
214
216
|
endpoint = "/api/sdk/replay/spanTree/#{external_span_id}"
|
|
215
|
-
|
|
217
|
+
query = []
|
|
218
|
+
query << "includeOutputs=false" unless include_outputs
|
|
219
|
+
query << "includeRootOutput=false" unless include_root_output
|
|
220
|
+
endpoint += "?#{query.join("&")}" unless query.empty?
|
|
216
221
|
get(endpoint, timeout: 30)
|
|
217
222
|
end
|
|
218
223
|
|
data/lib/bitfab/replay.rb
CHANGED
|
@@ -62,10 +62,12 @@ module Bitfab
|
|
|
62
62
|
# (via +database_url+). Reported on the trace
|
|
63
63
|
# completion inside the +db_snapshot_usage+ record (its +accessed+
|
|
64
64
|
# field) so the server can distinguish "branch was provisioned and
|
|
65
|
-
# exposed" from "branch URL was actually consumed".
|
|
66
|
-
#
|
|
67
|
-
# (e.g. a process-isolated runner writing an env overlay) must
|
|
68
|
-
#
|
|
65
|
+
# exposed" from "branch URL was actually consumed". Only an explicit
|
|
66
|
+
# +database_url+ read may set it. A path that hands the URL over by other
|
|
67
|
+
# means (e.g. a process-isolated runner writing an env overlay) must
|
|
68
|
+
# leave it alone: setting it there would make every such replay report
|
|
69
|
+
# accessed for free, and the flag would stop separating "branch was
|
|
70
|
+
# used" from "branch was offered".
|
|
69
71
|
ctx[:db_branch_lease] = db_branch_lease if db_branch_lease
|
|
70
72
|
ctx[:source_bitfab_trace_id] = source_bitfab_trace_id if source_bitfab_trace_id
|
|
71
73
|
Thread.current[REPLAY_CONTEXT_KEY] = ctx
|
|
@@ -674,7 +676,7 @@ module Bitfab
|
|
|
674
676
|
"produce a result that looks valid but did not use the historical data you asked for."
|
|
675
677
|
end
|
|
676
678
|
|
|
677
|
-
span = http_client.get_external_span(original_span_id)
|
|
679
|
+
span = http_client.get_external_span(original_span_id, replay_view: true)
|
|
678
680
|
item_data = extract_span_data(span)
|
|
679
681
|
|
|
680
682
|
# Fetch the span tree when the base strategy needs recorded outputs
|
|
@@ -692,7 +694,11 @@ module Bitfab
|
|
|
692
694
|
mock_tree = nil
|
|
693
695
|
if mock_strategy == "all" || mock_strategy == "marked" || overrides_present
|
|
694
696
|
begin
|
|
695
|
-
tree = http_client.get_span_tree(
|
|
697
|
+
tree = http_client.get_span_tree(
|
|
698
|
+
original_span_id,
|
|
699
|
+
include_outputs:,
|
|
700
|
+
include_root_output: false
|
|
701
|
+
)
|
|
696
702
|
mock_tree = build_mock_tree(tree["root"] || {})
|
|
697
703
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
698
704
|
raise if e.is_a?(SystemExit) || e.is_a?(SignalException)
|
|
@@ -841,7 +847,7 @@ module Bitfab
|
|
|
841
847
|
lambda do |external_span_id|
|
|
842
848
|
return cache[external_span_id] if cache.key?(external_span_id)
|
|
843
849
|
|
|
844
|
-
span = http_client.get_external_span(external_span_id)
|
|
850
|
+
span = http_client.get_external_span(external_span_id, replay_view: true)
|
|
845
851
|
span_data = (span["rawData"] || {})["span_data"] || {}
|
|
846
852
|
# Prefer the Ruby Marshal payload (output_serialized) written by this
|
|
847
853
|
# SDK; fall back to another SDK's output_meta, then the raw JSON output.
|
data/lib/bitfab/replay_branch.rb
CHANGED
|
@@ -17,9 +17,20 @@ module Bitfab
|
|
|
17
17
|
# protocol term). Its useful fields are exposed directly here so customer code
|
|
18
18
|
# never sees the word.
|
|
19
19
|
class ReplayBranch
|
|
20
|
+
# The provider's own id for this branch, e.g. for correlating with its console.
|
|
21
|
+
attr_reader :neon_branch_id
|
|
22
|
+
|
|
23
|
+
# Env var name the customer's app reads, e.g. "DATABASE_URL".
|
|
24
|
+
attr_reader :env_key
|
|
25
|
+
|
|
20
26
|
# When this branch's URL stops being valid. ISO-8601.
|
|
21
27
|
attr_reader :expires_at
|
|
22
28
|
|
|
29
|
+
# The instant this branch is pinned to: the source trace's wall clock, read
|
|
30
|
+
# just before the traced method ran. Compare it against the trace you meant
|
|
31
|
+
# to replay to confirm the branch is the right point in history.
|
|
32
|
+
attr_reader :snapshot_timestamp
|
|
33
|
+
|
|
23
34
|
# Deep link to the branch in the provider console, if available.
|
|
24
35
|
attr_reader :provider_console_url
|
|
25
36
|
|
|
@@ -36,13 +47,28 @@ module Bitfab
|
|
|
36
47
|
|
|
37
48
|
# Built by Bitfab.current_replay_branch; never constructed by callers.
|
|
38
49
|
def initialize(lease, trace_id, context)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
# Copy the lease wholesale minus the connection string, so a field the
|
|
51
|
+
# server starts sending reaches customer code without an SDK release.
|
|
52
|
+
# Everything set here must stay plain data: #database_url is the only
|
|
53
|
+
# member allowed to mark the branch as accessed.
|
|
54
|
+
# The internals are underscore-prefixed because the loop below writes an
|
|
55
|
+
# ivar per lease key: snake_case never emits a leading underscore, so no
|
|
56
|
+
# field the server invents can collide with them. A plain @fields would
|
|
57
|
+
# be clobbered mid-loop by a key named "fields", corrupting #as_json.
|
|
58
|
+
fields = {}
|
|
59
|
+
lease.each do |key, value|
|
|
60
|
+
next if key == "databaseUrl"
|
|
61
|
+
|
|
62
|
+
name = snake_case(key)
|
|
63
|
+
fields[name] = value
|
|
64
|
+
instance_variable_set(:"@#{name}", value)
|
|
65
|
+
define_singleton_method(name) { value } unless respond_to?(name)
|
|
66
|
+
end
|
|
43
67
|
@trace_id = trace_id
|
|
44
|
-
|
|
45
|
-
@
|
|
68
|
+
fields["trace_id"] = trace_id
|
|
69
|
+
@_fields = fields.freeze
|
|
70
|
+
@_url = lease["databaseUrl"]
|
|
71
|
+
@_context = context
|
|
46
72
|
freeze
|
|
47
73
|
end
|
|
48
74
|
|
|
@@ -54,15 +80,39 @@ module Bitfab
|
|
|
54
80
|
# was actually used". The other readers inspect the lease without exposing
|
|
55
81
|
# the connection string, so they deliberately do not record anything.
|
|
56
82
|
def database_url
|
|
57
|
-
@
|
|
58
|
-
@
|
|
83
|
+
@_context[:db_snapshot_accessed] = true
|
|
84
|
+
@_url
|
|
59
85
|
end
|
|
60
86
|
|
|
61
87
|
# Redact the connection string so a logged or inspected branch cannot leak it.
|
|
62
88
|
def inspect
|
|
63
89
|
"#<Bitfab::ReplayBranch trace_id=#{@trace_id.inspect} " \
|
|
64
90
|
"expires_at=#{@expires_at.inspect} region=#{@region.inspect} " \
|
|
65
|
-
"read_only=#{@read_only.inspect}
|
|
91
|
+
"read_only=#{@read_only.inspect} " \
|
|
92
|
+
"snapshot_timestamp=#{@snapshot_timestamp.inspect}>"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# ActiveSupport gives every object a +to_json+ that serializes its instance
|
|
96
|
+
# variables, so under Rails a branch reaching a log line or an API response
|
|
97
|
+
# would carry the connection string and the whole replay context. Serialize
|
|
98
|
+
# the exposed fields only, the same set +inspect+ shows.
|
|
99
|
+
def as_json(_options = nil)
|
|
100
|
+
@_fields.dup
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def to_json(*args)
|
|
104
|
+
as_json.to_json(*args)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
# Two passes so a run of capitals stays one word: "dbURL" is "db_url", not
|
|
110
|
+
# "db_u_r_l". Must match the Python SDK's conversion exactly, or the same
|
|
111
|
+
# server field would arrive under different names in the two SDKs.
|
|
112
|
+
def snake_case(key)
|
|
113
|
+
key.gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
|
114
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
115
|
+
.downcase
|
|
66
116
|
end
|
|
67
117
|
end
|
|
68
118
|
end
|
data/lib/bitfab/version.rb
CHANGED