statsig 2.0.1 → 2.8.1
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/api_config.rb +1 -1
- data/lib/client_initialize_helpers.rb +30 -21
- data/lib/config_result.rb +21 -2
- data/lib/constants.rb +9 -0
- data/lib/dynamic_config.rb +14 -2
- data/lib/error_boundary.rb +1 -1
- data/lib/evaluation_helpers.rb +13 -1
- data/lib/evaluator.rb +368 -18
- data/lib/hash_utils.rb +48 -3
- data/lib/layer.rb +23 -4
- data/lib/memo.rb +5 -1
- data/lib/network.rb +10 -3
- data/lib/sdk_configs.rb +37 -0
- data/lib/spec_store.rb +97 -49
- data/lib/statsig.rb +59 -8
- data/lib/statsig_driver.rb +76 -28
- data/lib/statsig_event.rb +1 -2
- data/lib/statsig_logger.rb +137 -17
- data/lib/statsig_options.rb +7 -2
- data/lib/statsig_user.rb +1 -1
- data/lib/ttl_set.rb +36 -0
- data/lib/user_persistent_storage_utils.rb +27 -5
- metadata +9 -7
data/lib/network.rb
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
require 'connection_pool'
|
|
1
2
|
require 'http'
|
|
2
3
|
require 'json'
|
|
3
4
|
require 'securerandom'
|
|
4
5
|
require 'zlib'
|
|
5
6
|
|
|
6
|
-
require 'connection_pool'
|
|
7
|
-
|
|
8
7
|
RETRY_CODES = [408, 500, 502, 503, 504, 522, 524, 599].freeze
|
|
9
8
|
|
|
10
9
|
module Statsig
|
|
@@ -53,7 +52,11 @@ module Statsig
|
|
|
53
52
|
|
|
54
53
|
def download_config_specs(since_time)
|
|
55
54
|
url = @options.download_config_specs_url
|
|
56
|
-
|
|
55
|
+
dcs_url = "#{url}#{@server_secret}.json"
|
|
56
|
+
if since_time.positive?
|
|
57
|
+
dcs_url += "?sinceTime=#{since_time}"
|
|
58
|
+
end
|
|
59
|
+
get(dcs_url)
|
|
57
60
|
end
|
|
58
61
|
|
|
59
62
|
def post_logs(events, error_boundary)
|
|
@@ -64,6 +67,10 @@ module Statsig
|
|
|
64
67
|
gzip << json_body
|
|
65
68
|
|
|
66
69
|
response, e = post(url, gzip.close.string, @post_logs_retry_limit, 1, true, event_count)
|
|
70
|
+
|
|
71
|
+
# Consume response body to ensure connection can be closed.
|
|
72
|
+
response&.flush
|
|
73
|
+
|
|
67
74
|
unless e == nil
|
|
68
75
|
message = "Failed to log #{event_count} events after #{@post_logs_retry_limit} retries"
|
|
69
76
|
puts "[Statsig]: #{message}"
|
data/lib/sdk_configs.rb
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'concurrent-ruby'
|
|
2
|
+
|
|
3
|
+
module Statsig
|
|
4
|
+
class SDKConfigs
|
|
5
|
+
def initialize
|
|
6
|
+
@configs = Concurrent::Hash.new
|
|
7
|
+
@flags = Concurrent::Hash.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def set_flags(new_flags)
|
|
11
|
+
@flags = new_flags || Concurrent::Hash.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def set_configs(new_configs)
|
|
15
|
+
@configs = new_configs || Concurrent::Hash.new
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def on(flag)
|
|
19
|
+
@flags[flag.to_sym] == true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def get_config_num_value(config)
|
|
23
|
+
value = @configs[config.to_sym]
|
|
24
|
+
value.is_a?(Numeric) ? value.to_f : nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def get_config_string_value(config)
|
|
28
|
+
value = @configs[config.to_sym]
|
|
29
|
+
value.is_a?(String) ? value : nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def get_config_int_value(config)
|
|
33
|
+
value = @configs[config.to_sym]
|
|
34
|
+
value.is_a?(Integer) ? value : nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/spec_store.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
require 'concurrent-ruby'
|
|
1
2
|
require 'net/http'
|
|
2
3
|
require 'uri'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
require 'api_config'
|
|
4
|
+
require_relative 'api_config'
|
|
5
|
+
require_relative 'evaluation_details'
|
|
6
|
+
require_relative 'hash_utils'
|
|
7
|
+
require_relative 'id_list'
|
|
8
8
|
|
|
9
9
|
module Statsig
|
|
10
10
|
class SpecStore
|
|
@@ -19,8 +19,11 @@ module Statsig
|
|
|
19
19
|
attr_accessor :sdk_keys_to_app_ids
|
|
20
20
|
attr_accessor :hashed_sdk_keys_to_app_ids
|
|
21
21
|
attr_accessor :unsupported_configs
|
|
22
|
+
attr_accessor :cmab_configs
|
|
23
|
+
attr_accessor :overrides
|
|
24
|
+
attr_accessor :override_rules
|
|
22
25
|
|
|
23
|
-
def initialize(network, options, error_callback, diagnostics, error_boundary, logger, secret_key)
|
|
26
|
+
def initialize(network, options, error_callback, diagnostics, error_boundary, logger, secret_key, sdk_config)
|
|
24
27
|
@init_reason = EvaluationReason::UNINITIALIZED
|
|
25
28
|
@network = network
|
|
26
29
|
@options = options
|
|
@@ -33,16 +36,22 @@ module Statsig
|
|
|
33
36
|
@gates = {}
|
|
34
37
|
@configs = {}
|
|
35
38
|
@layers = {}
|
|
39
|
+
@cmab_configs = {}
|
|
36
40
|
@condition_map = {}
|
|
37
41
|
@id_lists = {}
|
|
38
42
|
@experiment_to_layer = {}
|
|
39
43
|
@sdk_keys_to_app_ids = {}
|
|
40
44
|
@hashed_sdk_keys_to_app_ids = {}
|
|
45
|
+
@overrides = {}
|
|
46
|
+
@override_rules = {}
|
|
41
47
|
@diagnostics = diagnostics
|
|
42
48
|
@error_boundary = error_boundary
|
|
43
49
|
@logger = logger
|
|
44
50
|
@secret_key = secret_key
|
|
45
51
|
@unsupported_configs = Set.new
|
|
52
|
+
@sdk_configs = sdk_config
|
|
53
|
+
|
|
54
|
+
startTime = (Time.now.to_f * 1000).to_i
|
|
46
55
|
|
|
47
56
|
@id_list_thread_pool = Concurrent::FixedThreadPool.new(
|
|
48
57
|
options.idlist_threadpool_size,
|
|
@@ -57,7 +66,7 @@ module Statsig
|
|
|
57
66
|
else
|
|
58
67
|
tracker = @diagnostics.track('initialize','bootstrap', 'process')
|
|
59
68
|
begin
|
|
60
|
-
if process_specs(options.bootstrap_values)
|
|
69
|
+
if process_specs(options.bootstrap_values).nil?
|
|
61
70
|
@init_reason = EvaluationReason::BOOTSTRAP
|
|
62
71
|
end
|
|
63
72
|
rescue StandardError
|
|
@@ -68,13 +77,15 @@ module Statsig
|
|
|
68
77
|
end
|
|
69
78
|
end
|
|
70
79
|
|
|
80
|
+
failure_details = nil
|
|
81
|
+
|
|
71
82
|
unless @options.data_store.nil?
|
|
72
83
|
@options.data_store.init
|
|
73
|
-
load_config_specs_from_storage_adapter('initialize')
|
|
84
|
+
failure_details = load_config_specs_from_storage_adapter('initialize')
|
|
74
85
|
end
|
|
75
86
|
|
|
76
87
|
if @init_reason == EvaluationReason::UNINITIALIZED
|
|
77
|
-
download_config_specs('initialize')
|
|
88
|
+
failure_details = download_config_specs('initialize')
|
|
78
89
|
end
|
|
79
90
|
|
|
80
91
|
@initial_config_sync_time = @last_config_sync_time == 0 ? -1 : @last_config_sync_time
|
|
@@ -86,12 +97,18 @@ module Statsig
|
|
|
86
97
|
|
|
87
98
|
@config_sync_thread = spawn_sync_config_specs_thread
|
|
88
99
|
@id_lists_sync_thread = spawn_sync_id_lists_thread
|
|
100
|
+
endTime = (Time.now.to_f * 1000).to_i
|
|
101
|
+
@initialization_details = {duration: endTime - startTime, isSDKReady: true, configSpecReady: @init_reason != EvaluationReason::UNINITIALIZED, failureDetails: failure_details}
|
|
89
102
|
end
|
|
90
103
|
|
|
91
104
|
def is_ready_for_checks
|
|
92
105
|
@last_config_sync_time != 0
|
|
93
106
|
end
|
|
94
107
|
|
|
108
|
+
def get_initialization_details
|
|
109
|
+
@initialization_details
|
|
110
|
+
end
|
|
111
|
+
|
|
95
112
|
def shutdown
|
|
96
113
|
@config_sync_thread&.exit
|
|
97
114
|
@id_lists_sync_thread&.exit
|
|
@@ -114,6 +131,13 @@ module Statsig
|
|
|
114
131
|
@layers.key?(layer_name.to_sym)
|
|
115
132
|
end
|
|
116
133
|
|
|
134
|
+
def has_cmab_config?(config_name)
|
|
135
|
+
if @cmab_configs.nil?
|
|
136
|
+
return false
|
|
137
|
+
end
|
|
138
|
+
@cmab_configs.key?(config_name.to_sym)
|
|
139
|
+
end
|
|
140
|
+
|
|
117
141
|
def get_gate(gate_name)
|
|
118
142
|
gate_sym = gate_name.to_sym
|
|
119
143
|
return nil unless has_gate?(gate_sym)
|
|
@@ -134,6 +158,12 @@ module Statsig
|
|
|
134
158
|
@layers[layer_sym]
|
|
135
159
|
end
|
|
136
160
|
|
|
161
|
+
def get_cmab_config(config_name)
|
|
162
|
+
config_sym = config_name.to_sym
|
|
163
|
+
return nil unless has_cmab_config?(config_sym)
|
|
164
|
+
@cmab_configs[config_sym]
|
|
165
|
+
end
|
|
166
|
+
|
|
137
167
|
def get_condition(condition_hash)
|
|
138
168
|
@condition_map[condition_hash.to_sym]
|
|
139
169
|
end
|
|
@@ -202,13 +232,19 @@ module Statsig
|
|
|
202
232
|
return if cached_values.nil?
|
|
203
233
|
|
|
204
234
|
tracker = @diagnostics.track(context, 'data_store_config_specs', 'process')
|
|
205
|
-
process_specs(cached_values, from_adapter: true)
|
|
206
|
-
|
|
207
|
-
|
|
235
|
+
failure_details = process_specs(cached_values, from_adapter: true)
|
|
236
|
+
if failure_details.nil?
|
|
237
|
+
@init_reason = EvaluationReason::DATA_ADAPTER
|
|
238
|
+
tracker.end(success: true)
|
|
239
|
+
else
|
|
240
|
+
tracker.end(success: false)
|
|
241
|
+
return download_config_specs(context)
|
|
242
|
+
end
|
|
243
|
+
return failure_details
|
|
208
244
|
rescue StandardError
|
|
209
245
|
# Fallback to network
|
|
210
246
|
tracker.end(success: false)
|
|
211
|
-
download_config_specs(context)
|
|
247
|
+
return download_config_specs(context)
|
|
212
248
|
end
|
|
213
249
|
|
|
214
250
|
def save_rulesets_to_storage_adapter(rulesets_string)
|
|
@@ -253,18 +289,21 @@ module Statsig
|
|
|
253
289
|
tracker = @diagnostics.track(context, 'download_config_specs', 'network_request')
|
|
254
290
|
|
|
255
291
|
error = nil
|
|
292
|
+
failure_details = nil
|
|
256
293
|
begin
|
|
257
294
|
response, e = @network.download_config_specs(@last_config_sync_time)
|
|
258
295
|
code = response&.status.to_i
|
|
259
296
|
if e.is_a? NetworkError
|
|
260
297
|
code = e.http_code
|
|
298
|
+
failure_details = {statusCode: code, exception: e, reason: "CONFIG_SPECS_NETWORK_ERROR"}
|
|
261
299
|
end
|
|
262
300
|
tracker.end(statusCode: code, success: e.nil?, sdkRegion: response&.headers&.[]('X-Statsig-Region'))
|
|
263
301
|
|
|
264
302
|
if e.nil?
|
|
265
303
|
unless response.nil?
|
|
266
304
|
tracker = @diagnostics.track(context, 'download_config_specs', 'process')
|
|
267
|
-
|
|
305
|
+
failure_details = process_specs(response.body.to_s)
|
|
306
|
+
if failure_details.nil?
|
|
268
307
|
@init_reason = EvaluationReason::NETWORK
|
|
269
308
|
end
|
|
270
309
|
tracker.end(success: @init_reason == EvaluationReason::NETWORK)
|
|
@@ -274,59 +313,68 @@ module Statsig
|
|
|
274
313
|
@last_config_sync_time)
|
|
275
314
|
end
|
|
276
315
|
end
|
|
277
|
-
|
|
278
|
-
nil
|
|
279
316
|
else
|
|
280
317
|
error = e
|
|
281
318
|
end
|
|
282
319
|
rescue StandardError => e
|
|
320
|
+
failure_details = {exception: e, reason: "INTERNAL_ERROR"}
|
|
283
321
|
error = e
|
|
284
322
|
end
|
|
285
323
|
|
|
286
324
|
@error_callback.call(error) unless error.nil? or @error_callback.nil?
|
|
325
|
+
return failure_details
|
|
287
326
|
end
|
|
288
327
|
|
|
289
328
|
def process_specs(specs_string, from_adapter: false)
|
|
290
329
|
if specs_string.nil?
|
|
291
|
-
return
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
specs_json = JSON.parse(specs_string, { symbolize_names: true })
|
|
295
|
-
return false unless specs_json.is_a? Hash
|
|
296
|
-
|
|
297
|
-
hashed_sdk_key_used = specs_json[:hashed_sdk_key_used]
|
|
298
|
-
unless hashed_sdk_key_used.nil? or hashed_sdk_key_used == Statsig::HashUtils.djb2(@secret_key)
|
|
299
|
-
err_boundary.log_exception(Statsig::InvalidSDKKeyResponse.new)
|
|
300
|
-
return false
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
new_specs_sync_time = specs_json[:time]
|
|
304
|
-
if new_specs_sync_time.nil? \
|
|
305
|
-
|| new_specs_sync_time < @last_config_sync_time \
|
|
306
|
-
|| specs_json[:has_updates] != true \
|
|
307
|
-
|| specs_json[:feature_gates].nil? \
|
|
308
|
-
|| specs_json[:dynamic_configs].nil? \
|
|
309
|
-
|| specs_json[:layer_configs].nil?
|
|
310
|
-
return false
|
|
330
|
+
return {reason: "EMPTY_SPEC"}
|
|
311
331
|
end
|
|
312
332
|
|
|
313
|
-
|
|
314
|
-
|
|
333
|
+
begin
|
|
334
|
+
specs_json = JSON.parse(specs_string, { symbolize_names: true })
|
|
335
|
+
return {reason: "PARSE_RESPONSE_ERROR"} unless specs_json.is_a? Hash
|
|
315
336
|
|
|
316
|
-
|
|
337
|
+
hashed_sdk_key_used = specs_json[:hashed_sdk_key_used]
|
|
338
|
+
unless hashed_sdk_key_used.nil? or hashed_sdk_key_used == Statsig::HashUtils.djb2(@secret_key)
|
|
339
|
+
err_boundary.log_exception(Statsig::InvalidSDKKeyResponse.new)
|
|
340
|
+
return {reason: "PARSE_RESPONSE_ERROR"}
|
|
341
|
+
end
|
|
317
342
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
343
|
+
new_specs_sync_time = specs_json[:time]
|
|
344
|
+
if new_specs_sync_time.nil? \
|
|
345
|
+
|| new_specs_sync_time < @last_config_sync_time \
|
|
346
|
+
|| specs_json[:has_updates] != true \
|
|
347
|
+
|| specs_json[:feature_gates].nil? \
|
|
348
|
+
|| specs_json[:dynamic_configs].nil? \
|
|
349
|
+
|| specs_json[:layer_configs].nil?
|
|
350
|
+
return {reason: "PARSE_RESPONSE_ERROR"}
|
|
351
|
+
end
|
|
325
352
|
|
|
326
|
-
|
|
327
|
-
|
|
353
|
+
@last_config_sync_time = new_specs_sync_time
|
|
354
|
+
@unsupported_configs.clear
|
|
355
|
+
|
|
356
|
+
specs_json[:diagnostics]&.each { |key, value| @diagnostics.sample_rates[key.to_s] = value }
|
|
357
|
+
|
|
358
|
+
@gates = specs_json[:feature_gates]
|
|
359
|
+
@configs = specs_json[:dynamic_configs]
|
|
360
|
+
@layers = specs_json[:layer_configs]
|
|
361
|
+
@cmab_configs = specs_json[:cmab_configs]
|
|
362
|
+
@condition_map = specs_json[:condition_map]
|
|
363
|
+
@experiment_to_layer = specs_json[:experiment_to_layer]
|
|
364
|
+
@sdk_keys_to_app_ids = specs_json[:sdk_keys_to_app_ids] || {}
|
|
365
|
+
@hashed_sdk_keys_to_app_ids = specs_json[:hashed_sdk_keys_to_app_ids] || {}
|
|
366
|
+
@sdk_configs.set_flags(specs_json[:sdk_flags])
|
|
367
|
+
@sdk_configs.set_configs(specs_json[:sdk_configs])
|
|
368
|
+
@overrides = specs_json[:overrides] || {}
|
|
369
|
+
@override_rules = specs_json[:override_rules] || {}
|
|
370
|
+
|
|
371
|
+
unless from_adapter
|
|
372
|
+
save_rulesets_to_storage_adapter(specs_string)
|
|
373
|
+
end
|
|
374
|
+
rescue StandardError => e
|
|
375
|
+
return {reason: "PARSE_RESPONSE_ERROR"}
|
|
328
376
|
end
|
|
329
|
-
|
|
377
|
+
nil
|
|
330
378
|
end
|
|
331
379
|
|
|
332
380
|
def get_id_lists_from_adapter(context)
|
data/lib/statsig.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require 'statsig_errors'
|
|
1
|
+
require_relative 'statsig_driver'
|
|
2
|
+
require_relative 'statsig_errors'
|
|
4
3
|
|
|
5
4
|
module Statsig
|
|
6
5
|
|
|
@@ -20,6 +19,13 @@ module Statsig
|
|
|
20
19
|
@shared_instance = StatsigDriver.new(secret_key, options, error_callback)
|
|
21
20
|
end
|
|
22
21
|
|
|
22
|
+
def self.get_initialization_details
|
|
23
|
+
if not defined? @shared_instance or @shared_instance.nil?
|
|
24
|
+
return {duration: 0, isSDKReady: false, configSpecReady: false, failure_details: {exception: Statsig::UninitializedError.new, reason: 'INTERNAL_ERROR'}}
|
|
25
|
+
end
|
|
26
|
+
@shared_instance.get_initialization_details
|
|
27
|
+
end
|
|
28
|
+
|
|
23
29
|
class GetGateOptions
|
|
24
30
|
attr_accessor :disable_log_exposure, :skip_evaluation, :disable_evaluation_details
|
|
25
31
|
|
|
@@ -65,7 +71,7 @@ module Statsig
|
|
|
65
71
|
end
|
|
66
72
|
|
|
67
73
|
##
|
|
68
|
-
# @deprecated - use check_gate(user, gate, options)
|
|
74
|
+
# @deprecated - use check_gate(user, gate, options) with CheckGateOptions.new(disable_log_exposure: true) as options
|
|
69
75
|
# Gets the boolean result of a gate, evaluated against the given user.
|
|
70
76
|
#
|
|
71
77
|
# @param user A StatsigUser object used for the evaluation
|
|
@@ -85,6 +91,11 @@ module Statsig
|
|
|
85
91
|
@shared_instance&.manually_log_gate_exposure(user, gate_name)
|
|
86
92
|
end
|
|
87
93
|
|
|
94
|
+
def self.get_fields_used_for_gate(gate_name)
|
|
95
|
+
ensure_initialized
|
|
96
|
+
@shared_instance&.get_fields_used_for_gate(gate_name)
|
|
97
|
+
end
|
|
98
|
+
|
|
88
99
|
class GetConfigOptions
|
|
89
100
|
attr_accessor :disable_log_exposure, :disable_evaluation_details, :ignore_local_overrides
|
|
90
101
|
|
|
@@ -108,7 +119,7 @@ module Statsig
|
|
|
108
119
|
end
|
|
109
120
|
|
|
110
121
|
##
|
|
111
|
-
# @deprecated - use get_config(user, config, options)
|
|
122
|
+
# @deprecated - use get_config(user, config, options) with GetConfigOptions.new(disable_log_exposure: true) as options
|
|
112
123
|
# Get the values of a dynamic config, evaluated against the given user.
|
|
113
124
|
#
|
|
114
125
|
# @param [StatsigUser] user A StatsigUser object used for the evaluation
|
|
@@ -129,6 +140,11 @@ module Statsig
|
|
|
129
140
|
@shared_instance&.manually_log_config_exposure(user, dynamic_config)
|
|
130
141
|
end
|
|
131
142
|
|
|
143
|
+
def self.get_fields_used_for_config(config_name)
|
|
144
|
+
ensure_initialized
|
|
145
|
+
@shared_instance&.get_fields_used_for_config(config_name)
|
|
146
|
+
end
|
|
147
|
+
|
|
132
148
|
class GetExperimentOptions
|
|
133
149
|
attr_accessor :disable_log_exposure, :user_persisted_values, :disable_evaluation_details, :ignore_local_overrides
|
|
134
150
|
|
|
@@ -152,7 +168,7 @@ module Statsig
|
|
|
152
168
|
end
|
|
153
169
|
|
|
154
170
|
##
|
|
155
|
-
# @deprecated - use get_experiment(user, experiment, options)
|
|
171
|
+
# @deprecated - use get_experiment(user, experiment, options) with GetExperimentOptions.new(disable_log_exposure: true) as options
|
|
156
172
|
# Get the values of an experiment, evaluated against the given user.
|
|
157
173
|
#
|
|
158
174
|
# @param [StatsigUser] user A StatsigUser object used for the evaluation
|
|
@@ -177,6 +193,11 @@ module Statsig
|
|
|
177
193
|
@shared_instance&.get_user_persisted_values(user, id_type)
|
|
178
194
|
end
|
|
179
195
|
|
|
196
|
+
def self.get_fields_used_for_experiment(experiment_name)
|
|
197
|
+
ensure_initialized
|
|
198
|
+
@shared_instance&.get_fields_used_for_config(experiment_name)
|
|
199
|
+
end
|
|
200
|
+
|
|
180
201
|
class GetLayerOptions
|
|
181
202
|
attr_accessor :disable_log_exposure, :disable_evaluation_details
|
|
182
203
|
|
|
@@ -199,7 +220,7 @@ module Statsig
|
|
|
199
220
|
end
|
|
200
221
|
|
|
201
222
|
##
|
|
202
|
-
# @deprecated - use get_layer(user, gate, options)
|
|
223
|
+
# @deprecated - use get_layer(user, gate, options) with GetLayerOptions.new(disable_log_exposure: true) as options
|
|
203
224
|
# Get the values of a layer, evaluated against the given user.
|
|
204
225
|
#
|
|
205
226
|
# @param user A StatsigUser object used for the evaluation
|
|
@@ -220,6 +241,11 @@ module Statsig
|
|
|
220
241
|
@shared_instance&.manually_log_layer_parameter_exposure(user, layer_name, parameter_name)
|
|
221
242
|
end
|
|
222
243
|
|
|
244
|
+
def self.get_fields_used_for_layer(layer_name)
|
|
245
|
+
ensure_initialized
|
|
246
|
+
@shared_instance&.get_fields_used_for_layer(layer_name)
|
|
247
|
+
end
|
|
248
|
+
|
|
223
249
|
##
|
|
224
250
|
# Logs an event to Statsig with the provided values.
|
|
225
251
|
#
|
|
@@ -321,6 +347,17 @@ module Statsig
|
|
|
321
347
|
@shared_instance&.override_config(config_name, config_value)
|
|
322
348
|
end
|
|
323
349
|
|
|
350
|
+
|
|
351
|
+
##
|
|
352
|
+
# Overrides an experiment to return the value for a specific group name.
|
|
353
|
+
#
|
|
354
|
+
# @param experiment_name The name of the experiment to be overridden
|
|
355
|
+
# @param group_name The name of the group whose value should be returned
|
|
356
|
+
def self.override_experiment_by_group_name(experiment_name, group_name)
|
|
357
|
+
ensure_initialized
|
|
358
|
+
@shared_instance&.override_experiment_by_group_name(experiment_name, group_name)
|
|
359
|
+
end
|
|
360
|
+
|
|
324
361
|
def self.remove_config_override(config_name)
|
|
325
362
|
ensure_initialized
|
|
326
363
|
@shared_instance&.remove_config_override(config_name)
|
|
@@ -331,6 +368,16 @@ module Statsig
|
|
|
331
368
|
@shared_instance&.clear_config_overrides
|
|
332
369
|
end
|
|
333
370
|
|
|
371
|
+
def self.clear_experiment_overrides
|
|
372
|
+
ensure_initialized
|
|
373
|
+
@shared_instance&.clear_experiment_overrides
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def self.remove_experiment_override(experiment_name)
|
|
377
|
+
ensure_initialized
|
|
378
|
+
@shared_instance&.remove_experiment_override(experiment_name)
|
|
379
|
+
end
|
|
380
|
+
|
|
334
381
|
##
|
|
335
382
|
# @param [HashTable] debug information log with exposure events
|
|
336
383
|
def self.set_debug_info(debug_info)
|
|
@@ -363,11 +410,15 @@ module Statsig
|
|
|
363
410
|
def self.get_statsig_metadata
|
|
364
411
|
{
|
|
365
412
|
'sdkType' => 'ruby-server',
|
|
366
|
-
'sdkVersion' => '2.
|
|
413
|
+
'sdkVersion' => '2.8.1',
|
|
367
414
|
'languageVersion' => RUBY_VERSION
|
|
368
415
|
}
|
|
369
416
|
end
|
|
370
417
|
|
|
418
|
+
def self.get_options
|
|
419
|
+
@driver&.instance_variable_get(:@options)
|
|
420
|
+
end
|
|
421
|
+
|
|
371
422
|
private
|
|
372
423
|
|
|
373
424
|
def self.ensure_initialized
|