bitfab 0.22.1 → 0.23.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb8d7ab7e95fed00c067b1653c4d8271c1814b6a9d42bc8ffbb320596ac2190e
4
- data.tar.gz: 6050620ec20d4172045e7a7c29930349e488cd886132cb54758ca98d789be34f
3
+ metadata.gz: 26ad3b53b9f3da35c01496ecc236ce0f5d27e7921761c7baca7654d1fb8de31e
4
+ data.tar.gz: e653a93c4bf8e5263b22a6114ebcc2a52db6cc3db6eecc7774cb7b6ed07c51c3
5
5
  SHA512:
6
- metadata.gz: c94a534717dfbf682ca6d4f1fb6e9501fba8df1057bd6390457c4f561616a23bf53092bfc4bc8cc966f67037d1a7a9b8f2eadc4edff92645a99e2b0a9ffcf33b
7
- data.tar.gz: 7e416c3b5af6248ada3bda42d56d2853d68792e7adcf3bb4a1e1af98b5b4740ee92cd7e25ba8c86fee0bc0b0acaa5acd102bb1d8e561d03d0e669d24de877048
6
+ metadata.gz: 7c31a1ffd2e8be0cd31fd94941479351176823eabeadf453972bd493aeadbbc7de97002f484787a6e009024a42a6ed1e3a8fc99ded4b94eb3fd842d6e03772e9
7
+ data.tar.gz: 01ee591f9c3a51254abc101229ba261bc054acd02bfe7c67471367fd8cb0cc2fa015a1c1affc149358caf7dc5af98c7ea4f5351973153b60c6983befbc4d7ac7
data/lib/bitfab/client.rb CHANGED
@@ -20,21 +20,40 @@ module Bitfab
20
20
  # outputs (which may themselves be nil or false).
21
21
  MOCK_REPLAY_MISS = Object.new.freeze
22
22
 
23
- attr_reader :api_key, :service_url, :enabled
23
+ attr_reader :service_url
24
24
 
25
- def initialize(api_key:, service_url: nil, enabled: true)
26
- @api_key = api_key
25
+ def initialize(api_key: nil, service_url: nil, enabled: true, strict: false)
26
+ @api_key_config = api_key
27
27
  @service_url = service_url || DEFAULT_SERVICE_URL
28
- @enabled = enabled
29
- if @enabled && (@api_key.nil? || @api_key.to_s.strip.empty?)
30
- warn "Bitfab: api_key is empty: tracing is disabled. Provide a valid API key to enable tracing."
31
- @enabled = false
32
- end
33
- @http_client = HttpClient.new(api_key:, service_url: @service_url)
28
+ # The user's on/off intent; effective enabled also requires a resolved key.
29
+ @explicitly_enabled = enabled
30
+ @strict = strict
31
+ # Cached only once a non-empty key is found, so an early resolve (before
32
+ # env loaded) can't poison a later one.
33
+ @resolved_api_key = nil
34
+ @api_key_warned = false
35
+ # The key is NOT read here. HttpClient gets a proc so the key is resolved
36
+ # at send time, after any env loading has run.
37
+ @http_client = HttpClient.new(api_key: -> { resolve_api_key }, service_url: @service_url)
34
38
  @pending_span_threads = {}
35
39
  @pending_span_mutex = Mutex.new
36
40
  end
37
41
 
42
+ # The configured API key (a proc is resolved on read). Reflects what was
43
+ # passed to the client; the ENV["BITFAB_API_KEY"] fallback applied during
44
+ # actual tracing is not surfaced here, and reading this never warns.
45
+ def api_key
46
+ @api_key_config.respond_to?(:call) ? @api_key_config.call : @api_key_config
47
+ end
48
+
49
+ # Effective tracing state, evaluated lazily: enabled only when not
50
+ # explicitly disabled AND a key resolves. Reading this resolves the key
51
+ # (and may emit the one-time empty-key warning), exactly as the first traced
52
+ # call would.
53
+ def enabled
54
+ tracing_enabled?
55
+ end
56
+
38
57
  # Replay historical traces through a method and create a test run.
39
58
  #
40
59
  # @param receiver [Object, Class] an instance for instance methods, or a Class for class methods
@@ -100,7 +119,10 @@ module Bitfab
100
119
  # Called by Traceable, not intended for direct use.
101
120
  def execute_span(trace_function_key:, span_name:, span_type:, function_name:, args:, kwargs:,
102
121
  mock_on_replay: false)
103
- return yield unless @enabled
122
+ # Decide at CALL time, not construction. The key may be set after the
123
+ # client is built (env loaded later), so re-checking per call lets a
124
+ # late-resolved key take effect.
125
+ return yield unless tracing_enabled?
104
126
 
105
127
  # Span setup runs before the user's block. Tracing is a side-channel, so
106
128
  # if anything here raises (id generation, trace-state bookkeeping, a
@@ -321,6 +343,48 @@ module Bitfab
321
343
 
322
344
  private
323
345
 
346
+ # Resolve the API key lazily, the first time a span actually needs it.
347
+ #
348
+ # The key is intentionally NOT read at construction: a client built when a
349
+ # file is required can run before the app loads its env, so the key would be
350
+ # empty at construction even though it is set moments later. Resolution
351
+ # order: the configured value (a proc is called while still unresolved),
352
+ # then a fallback read of ENV["BITFAB_API_KEY"]. Once a non-empty key is
353
+ # found it is cached.
354
+ def resolve_api_key
355
+ return @resolved_api_key unless @resolved_api_key.nil?
356
+
357
+ from_config = @api_key_config.respond_to?(:call) ? @api_key_config.call : @api_key_config
358
+ candidate = if from_config && !from_config.to_s.strip.empty?
359
+ from_config
360
+ else
361
+ ENV["BITFAB_API_KEY"]
362
+ end
363
+ key = (candidate && !candidate.to_s.strip.empty?) ? candidate : nil
364
+ if key
365
+ @resolved_api_key = key
366
+ return key
367
+ end
368
+ if @strict
369
+ raise "Bitfab: no API key resolved. Set BITFAB_API_KEY or pass api_key: to " \
370
+ "Bitfab.configure. If a script loads env later, load it before the first " \
371
+ "traced call, or pass api_key: -> { ENV[\"BITFAB_API_KEY\"] }."
372
+ end
373
+ if @explicitly_enabled && !@api_key_warned
374
+ @api_key_warned = true
375
+ warn "Bitfab: api_key is empty: tracing is disabled. Provide a valid API key to enable tracing."
376
+ end
377
+ nil
378
+ end
379
+
380
+ # Whether tracing should run, decided lazily at call time. An explicit
381
+ # `enabled: false` short-circuits without ever touching the key.
382
+ def tracing_enabled?
383
+ return false unless @explicitly_enabled
384
+
385
+ !resolve_api_key.nil?
386
+ end
387
+
324
388
  # Build an Enumerator that drives `source`, restoring `[trace_id, span_id]`
325
389
  # on the iterating fiber so nested `bitfab_span` calls inside lazy / `each`
326
390
  # callbacks nest under the parent span. Yielded values are collected as the
@@ -226,9 +226,12 @@ module Bitfab
226
226
  end
227
227
 
228
228
  def headers
229
+ # Resolve the key at request time, invoking the proc form if one was
230
+ # supplied (never read at construction).
231
+ key = @api_key.respond_to?(:call) ? @api_key.call : @api_key
229
232
  {
230
233
  "Content-Type" => "application/json",
231
- "Authorization" => "Bearer #{@api_key}"
234
+ "Authorization" => "Bearer #{key}"
232
235
  }
233
236
  end
234
237
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bitfab
4
- VERSION = "0.22.1"
4
+ VERSION = "0.23.0"
5
5
  end
data/lib/bitfab.rb CHANGED
@@ -59,8 +59,8 @@ module Bitfab
59
59
  # @example
60
60
  # Bitfab.configure(api_key: ENV["BITFAB_API_KEY"])
61
61
  #
62
- def configure(api_key:, service_url: nil, enabled: true)
63
- @client = Client.new(api_key:, service_url:, enabled:)
62
+ def configure(api_key: nil, service_url: nil, enabled: true, strict: false)
63
+ @client = Client.new(api_key:, service_url:, enabled:, strict:)
64
64
  end
65
65
 
66
66
  # Returns the global client, raising if not configured.
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.22.1
4
+ version: 0.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harvest Team