Skip to content

Commit 562a3b9

Browse files
Merge pull request #19 from statsig-io/releases/v1.25.2
v1.25.2
2 parents 0dcdafb + ef3f43f commit 562a3b9

23 files changed

+609
-317
lines changed

.rubocop.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,10 @@ Style/Documentation:
1717
Style/IfUnlessModifier:
1818
Enabled: false
1919
Style/ConditionalAssignment:
20+
Enabled: false
21+
Style/RedundantReturn:
22+
Enabled: false
23+
Style/SlicingWithRange:
24+
Enabled: false
25+
Style/AccessorGrouping:
2026
Enabled: false

lib/diagnostics.rb

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,92 @@ class Diagnostics
1212
sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
1313
attr_reader :markers
1414

15-
sig { params(context: String).void }
16-
1715
def initialize(context)
1816
@context = context
1917
@markers = []
2018
end
2119

22-
sig { params(key: String, action: String, step: T.any(String, NilClass), value: T.any(String, Integer, T::Boolean, NilClass)).void }
20+
sig do
21+
params(
22+
key: String,
23+
action: String,
24+
step: T.any(String, NilClass),
25+
value: T.any(String, Integer, T::Boolean, NilClass),
26+
metadata: T.any(T::Hash[Symbol, T.untyped], NilClass)
27+
).void
28+
end
2329

24-
def mark(key, action, step = nil, value = nil)
30+
def mark(key, action, step = nil, value = nil, metadata = nil)
2531
@markers.push({
2632
key: key,
2733
step: step,
2834
action: action,
2935
value: value,
36+
metadata: metadata,
3037
timestamp: (Time.now.to_f * 1000).to_i
3138
})
3239
end
3340

41+
sig do
42+
params(
43+
key: String,
44+
step: T.any(String, NilClass),
45+
value: T.any(String, Integer, T::Boolean, NilClass),
46+
metadata: T.any(T::Hash[Symbol, T.untyped], NilClass)
47+
).returns(Tracker)
48+
end
49+
def track(key, step = nil, value = nil, metadata = nil)
50+
tracker = Tracker.new(self, key, step, metadata)
51+
tracker.start(value)
52+
tracker
53+
end
54+
3455
sig { returns(T::Hash[Symbol, T.untyped]) }
3556

3657
def serialize
3758
{
38-
context: @context,
39-
markers: @markers
59+
context: @context.clone,
60+
markers: @markers.clone
4061
}
4162
end
42-
end
4363

44-
end
64+
def clear_markers
65+
@markers.clear
66+
end
67+
68+
class Context
69+
INITIALIZE = 'initialize'.freeze
70+
CONFIG_SYNC = 'config_sync'.freeze
71+
API_CALL = 'api_call'.freeze
72+
end
73+
74+
API_CALL_KEYS = %w[check_gate get_config get_experiment get_layer].freeze
75+
76+
class Tracker
77+
extend T::Sig
78+
79+
sig do
80+
params(
81+
diagnostics: Diagnostics,
82+
key: String,
83+
step: T.any(String, NilClass),
84+
metadata: T.any(T::Hash[Symbol, T.untyped], NilClass)
85+
).void
86+
end
87+
def initialize(diagnostics, key, step, metadata)
88+
@diagnostics = diagnostics
89+
@key = key
90+
@step = step
91+
@metadata = metadata
92+
end
93+
94+
def start(value = nil)
95+
@diagnostics.mark(@key, 'start', @step, value, @metadata)
96+
end
97+
98+
def end(value = nil)
99+
@diagnostics.mark(@key, 'end', @step, value, @metadata)
100+
end
101+
end
102+
end
103+
end

lib/error_boundary.rb

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,46 @@
1-
require "statsig_errors"
1+
# typed: true
2+
3+
require 'statsig_errors'
4+
require 'sorbet-runtime'
25

36
$endpoint = 'https://statsigapi.net/v1/sdk_exception'
47

58
module Statsig
69
class ErrorBoundary
10+
extend T::Sig
11+
12+
sig { returns(T.any(StatsigLogger, NilClass)) }
13+
attr_accessor :logger
14+
15+
sig { params(sdk_key: String).void }
716
def initialize(sdk_key)
817
@sdk_key = sdk_key
918
@seen = Set.new
1019
end
1120

12-
def capture(task, recover = -> {})
21+
def sample_diagnostics
22+
rand(10_000).zero?
23+
end
24+
25+
def capture(task:, recover: -> {}, caller: nil)
26+
if !caller.nil? && Diagnostics::API_CALL_KEYS.include?(caller) && sample_diagnostics
27+
diagnostics = Diagnostics.new('api_call')
28+
tracker = diagnostics.track(caller)
29+
end
1330
begin
14-
return task.call
31+
res = task.call
32+
tracker&.end(true)
1533
rescue StandardError => e
34+
tracker&.end(false)
1635
if e.is_a?(Statsig::UninitializedError) or e.is_a?(Statsig::ValueError)
1736
raise e
1837
end
19-
puts "[Statsig]: An unexpected exception occurred."
38+
puts '[Statsig]: An unexpected exception occurred.'
2039
log_exception(e)
21-
return recover.call
40+
res = recover.call
2241
end
42+
@logger&.log_diagnostics_event(diagnostics)
43+
return res
2344
end
2445

2546
private
@@ -35,18 +56,18 @@ def log_exception(exception)
3556
meta = Statsig.get_statsig_metadata
3657
http = HTTP.headers(
3758
{
38-
"STATSIG-API-KEY" => @sdk_key,
39-
"STATSIG-SDK-TYPE" => meta['sdkType'],
40-
"STATSIG-SDK-VERSION" => meta['sdkVersion'],
41-
"Content-Type" => "application/json; charset=UTF-8"
59+
'STATSIG-API-KEY' => @sdk_key,
60+
'STATSIG-SDK-TYPE' => meta['sdkType'],
61+
'STATSIG-SDK-VERSION' => meta['sdkVersion'],
62+
'Content-Type' => 'application/json; charset=UTF-8'
4263
}).accept(:json)
4364
body = {
44-
"exception" => name,
45-
"info" => {
46-
"trace" => exception.backtrace.to_s,
47-
"message" => exception.message
65+
'exception' => name,
66+
'info' => {
67+
'trace' => exception.backtrace.to_s,
68+
'message' => exception.message
4869
}.to_s,
49-
"statsigMetadata" => meta
70+
'statsigMetadata' => meta
5071
}
5172
http.post($endpoint, body: JSON.generate(body))
5273
rescue

lib/evaluator.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ module Statsig
1717
class Evaluator
1818
attr_accessor :spec_store
1919

20-
def initialize(network, options, error_callback, init_diagnostics = nil)
21-
@spec_store = Statsig::SpecStore.new(network, options, error_callback, init_diagnostics)
20+
def initialize(network, options, error_callback, diagnostics)
21+
@spec_store = Statsig::SpecStore.new(network, options, error_callback, diagnostics)
2222
UAParser.initialize_async
2323
CountryLookup.initialize_async
2424

lib/network.rb

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require 'json'
55
require 'securerandom'
66
require 'sorbet-runtime'
7+
require 'uri_helper'
78

89
$retry_codes = [408, 500, 502, 503, 504, 522, 524, 599]
910

@@ -24,12 +25,8 @@ class Network
2425

2526
def initialize(server_secret, options, backoff_mult = 10)
2627
super()
27-
api = options.api_url_base
28-
unless api.end_with?('/')
29-
api += '/'
30-
end
28+
URIHelper.initialize(options)
3129
@server_secret = server_secret
32-
@api = api
3330
@local_mode = options.local_mode
3431
@timeout = options.network_timeout
3532
@backoff_multiplier = backoff_mult
@@ -67,16 +64,17 @@ def post_helper(endpoint, body, retries = 0, backoff = 1)
6764
backoff_adjusted = @post_logs_retry_backoff.call(retries)
6865
end
6966
end
67+
url = URIHelper.build_url(endpoint)
7068
begin
71-
res = http.post(@api + endpoint, body: body)
69+
res = http.post(url, body: body)
7270
rescue StandardError => e
7371
## network error retry
7472
return nil, e unless retries > 0
7573
sleep backoff_adjusted
7674
return post_helper(endpoint, body, retries - 1, backoff * @backoff_multiplier)
7775
end
7876
return res, nil if res.status.success?
79-
return nil, NetworkError.new("Got an exception when making request to #{@api + endpoint}: #{res.to_s}", res.status.to_i) unless retries > 0 && $retry_codes.include?(res.code)
77+
return nil, NetworkError.new("Got an exception when making request to #{url}: #{res.to_s}", res.status.to_i) unless retries > 0 && $retry_codes.include?(res.code)
8078
## status code retry
8179
sleep backoff_adjusted
8280
post_helper(endpoint, body, retries - 1, backoff * @backoff_multiplier)

0 commit comments

Comments
 (0)