statsig 2.1.0 → 2.5.5
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/client_initialize_helpers.rb +13 -17
- data/lib/config_result.rb +16 -1
- data/lib/constants.rb +3 -0
- data/lib/evaluator.rb +258 -8
- data/lib/hash_utils.rb +48 -3
- data/lib/memo.rb +5 -1
- data/lib/sdk_configs.rb +37 -0
- data/lib/spec_store.rb +83 -41
- data/lib/statsig.rb +32 -5
- data/lib/statsig_driver.rb +27 -13
- data/lib/statsig_event.rb +1 -2
- data/lib/statsig_logger.rb +129 -15
- data/lib/statsig_options.rb +7 -2
- data/lib/ttl_set.rb +36 -0
- data/lib/user_persistent_storage_utils.rb +26 -4
- metadata +9 -7
data/lib/spec_store.rb
CHANGED
@@ -19,8 +19,9 @@ 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
|
22
23
|
|
23
|
-
def initialize(network, options, error_callback, diagnostics, error_boundary, logger, secret_key)
|
24
|
+
def initialize(network, options, error_callback, diagnostics, error_boundary, logger, secret_key, sdk_config)
|
24
25
|
@init_reason = EvaluationReason::UNINITIALIZED
|
25
26
|
@network = network
|
26
27
|
@options = options
|
@@ -33,6 +34,7 @@ module Statsig
|
|
33
34
|
@gates = {}
|
34
35
|
@configs = {}
|
35
36
|
@layers = {}
|
37
|
+
@cmab_configs = {}
|
36
38
|
@condition_map = {}
|
37
39
|
@id_lists = {}
|
38
40
|
@experiment_to_layer = {}
|
@@ -43,6 +45,9 @@ module Statsig
|
|
43
45
|
@logger = logger
|
44
46
|
@secret_key = secret_key
|
45
47
|
@unsupported_configs = Set.new
|
48
|
+
@sdk_configs = sdk_config
|
49
|
+
|
50
|
+
startTime = (Time.now.to_f * 1000).to_i
|
46
51
|
|
47
52
|
@id_list_thread_pool = Concurrent::FixedThreadPool.new(
|
48
53
|
options.idlist_threadpool_size,
|
@@ -57,7 +62,7 @@ module Statsig
|
|
57
62
|
else
|
58
63
|
tracker = @diagnostics.track('initialize','bootstrap', 'process')
|
59
64
|
begin
|
60
|
-
if process_specs(options.bootstrap_values)
|
65
|
+
if process_specs(options.bootstrap_values).nil?
|
61
66
|
@init_reason = EvaluationReason::BOOTSTRAP
|
62
67
|
end
|
63
68
|
rescue StandardError
|
@@ -68,13 +73,15 @@ module Statsig
|
|
68
73
|
end
|
69
74
|
end
|
70
75
|
|
76
|
+
failure_details = nil
|
77
|
+
|
71
78
|
unless @options.data_store.nil?
|
72
79
|
@options.data_store.init
|
73
|
-
load_config_specs_from_storage_adapter('initialize')
|
80
|
+
failure_details = load_config_specs_from_storage_adapter('initialize')
|
74
81
|
end
|
75
82
|
|
76
83
|
if @init_reason == EvaluationReason::UNINITIALIZED
|
77
|
-
download_config_specs('initialize')
|
84
|
+
failure_details = download_config_specs('initialize')
|
78
85
|
end
|
79
86
|
|
80
87
|
@initial_config_sync_time = @last_config_sync_time == 0 ? -1 : @last_config_sync_time
|
@@ -86,12 +93,18 @@ module Statsig
|
|
86
93
|
|
87
94
|
@config_sync_thread = spawn_sync_config_specs_thread
|
88
95
|
@id_lists_sync_thread = spawn_sync_id_lists_thread
|
96
|
+
endTime = (Time.now.to_f * 1000).to_i
|
97
|
+
@initialization_details = {duration: endTime - startTime, isSDKReady: true, configSpecReady: @init_reason != EvaluationReason::UNINITIALIZED, failureDetails: failure_details}
|
89
98
|
end
|
90
99
|
|
91
100
|
def is_ready_for_checks
|
92
101
|
@last_config_sync_time != 0
|
93
102
|
end
|
94
103
|
|
104
|
+
def get_initialization_details
|
105
|
+
@initialization_details
|
106
|
+
end
|
107
|
+
|
95
108
|
def shutdown
|
96
109
|
@config_sync_thread&.exit
|
97
110
|
@id_lists_sync_thread&.exit
|
@@ -114,6 +127,13 @@ module Statsig
|
|
114
127
|
@layers.key?(layer_name.to_sym)
|
115
128
|
end
|
116
129
|
|
130
|
+
def has_cmab_config?(config_name)
|
131
|
+
if @cmab_configs.nil?
|
132
|
+
return false
|
133
|
+
end
|
134
|
+
@cmab_configs.key?(config_name.to_sym)
|
135
|
+
end
|
136
|
+
|
117
137
|
def get_gate(gate_name)
|
118
138
|
gate_sym = gate_name.to_sym
|
119
139
|
return nil unless has_gate?(gate_sym)
|
@@ -134,6 +154,12 @@ module Statsig
|
|
134
154
|
@layers[layer_sym]
|
135
155
|
end
|
136
156
|
|
157
|
+
def get_cmab_config(config_name)
|
158
|
+
config_sym = config_name.to_sym
|
159
|
+
return nil unless has_cmab_config?(config_sym)
|
160
|
+
@cmab_configs[config_sym]
|
161
|
+
end
|
162
|
+
|
137
163
|
def get_condition(condition_hash)
|
138
164
|
@condition_map[condition_hash.to_sym]
|
139
165
|
end
|
@@ -202,13 +228,19 @@ module Statsig
|
|
202
228
|
return if cached_values.nil?
|
203
229
|
|
204
230
|
tracker = @diagnostics.track(context, 'data_store_config_specs', 'process')
|
205
|
-
process_specs(cached_values, from_adapter: true)
|
206
|
-
|
207
|
-
|
231
|
+
failure_details = process_specs(cached_values, from_adapter: true)
|
232
|
+
if failure_details.nil?
|
233
|
+
@init_reason = EvaluationReason::DATA_ADAPTER
|
234
|
+
tracker.end(success: true)
|
235
|
+
else
|
236
|
+
tracker.end(success: false)
|
237
|
+
return download_config_specs(context)
|
238
|
+
end
|
239
|
+
return failure_details
|
208
240
|
rescue StandardError
|
209
241
|
# Fallback to network
|
210
242
|
tracker.end(success: false)
|
211
|
-
download_config_specs(context)
|
243
|
+
return download_config_specs(context)
|
212
244
|
end
|
213
245
|
|
214
246
|
def save_rulesets_to_storage_adapter(rulesets_string)
|
@@ -253,18 +285,21 @@ module Statsig
|
|
253
285
|
tracker = @diagnostics.track(context, 'download_config_specs', 'network_request')
|
254
286
|
|
255
287
|
error = nil
|
288
|
+
failure_details = nil
|
256
289
|
begin
|
257
290
|
response, e = @network.download_config_specs(@last_config_sync_time)
|
258
291
|
code = response&.status.to_i
|
259
292
|
if e.is_a? NetworkError
|
260
293
|
code = e.http_code
|
294
|
+
failure_details = {statusCode: code, exception: e, reason: "CONFIG_SPECS_NETWORK_ERROR"}
|
261
295
|
end
|
262
296
|
tracker.end(statusCode: code, success: e.nil?, sdkRegion: response&.headers&.[]('X-Statsig-Region'))
|
263
297
|
|
264
298
|
if e.nil?
|
265
299
|
unless response.nil?
|
266
300
|
tracker = @diagnostics.track(context, 'download_config_specs', 'process')
|
267
|
-
|
301
|
+
failure_details = process_specs(response.body.to_s)
|
302
|
+
if failure_details.nil?
|
268
303
|
@init_reason = EvaluationReason::NETWORK
|
269
304
|
end
|
270
305
|
tracker.end(success: @init_reason == EvaluationReason::NETWORK)
|
@@ -274,59 +309,66 @@ module Statsig
|
|
274
309
|
@last_config_sync_time)
|
275
310
|
end
|
276
311
|
end
|
277
|
-
|
278
|
-
nil
|
279
312
|
else
|
280
313
|
error = e
|
281
314
|
end
|
282
315
|
rescue StandardError => e
|
316
|
+
failure_details = {exception: e, reason: "INTERNAL_ERROR"}
|
283
317
|
error = e
|
284
318
|
end
|
285
319
|
|
286
320
|
@error_callback.call(error) unless error.nil? or @error_callback.nil?
|
321
|
+
return failure_details
|
287
322
|
end
|
288
323
|
|
289
324
|
def process_specs(specs_string, from_adapter: false)
|
290
325
|
if specs_string.nil?
|
291
|
-
return
|
326
|
+
return {reason: "EMPTY_SPEC"}
|
292
327
|
end
|
293
328
|
|
294
|
-
|
295
|
-
|
329
|
+
begin
|
330
|
+
specs_json = JSON.parse(specs_string, { symbolize_names: true })
|
331
|
+
return {reason: "PARSE_RESPONSE_ERROR"} unless specs_json.is_a? Hash
|
296
332
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
333
|
+
hashed_sdk_key_used = specs_json[:hashed_sdk_key_used]
|
334
|
+
unless hashed_sdk_key_used.nil? or hashed_sdk_key_used == Statsig::HashUtils.djb2(@secret_key)
|
335
|
+
err_boundary.log_exception(Statsig::InvalidSDKKeyResponse.new)
|
336
|
+
return {reason: "PARSE_RESPONSE_ERROR"}
|
337
|
+
end
|
302
338
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
339
|
+
new_specs_sync_time = specs_json[:time]
|
340
|
+
if new_specs_sync_time.nil? \
|
341
|
+
|| new_specs_sync_time < @last_config_sync_time \
|
342
|
+
|| specs_json[:has_updates] != true \
|
343
|
+
|| specs_json[:feature_gates].nil? \
|
344
|
+
|| specs_json[:dynamic_configs].nil? \
|
345
|
+
|| specs_json[:layer_configs].nil?
|
346
|
+
return {reason: "PARSE_RESPONSE_ERROR"}
|
347
|
+
end
|
312
348
|
|
313
|
-
|
314
|
-
|
349
|
+
@last_config_sync_time = new_specs_sync_time
|
350
|
+
@unsupported_configs.clear
|
315
351
|
|
316
|
-
|
352
|
+
specs_json[:diagnostics]&.each { |key, value| @diagnostics.sample_rates[key.to_s] = value }
|
317
353
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
354
|
+
@gates = specs_json[:feature_gates]
|
355
|
+
@configs = specs_json[:dynamic_configs]
|
356
|
+
@layers = specs_json[:layer_configs]
|
357
|
+
@cmab_configs = specs_json[:cmab_configs]
|
358
|
+
@condition_map = specs_json[:condition_map]
|
359
|
+
@experiment_to_layer = specs_json[:experiment_to_layer]
|
360
|
+
@sdk_keys_to_app_ids = specs_json[:sdk_keys_to_app_ids] || {}
|
361
|
+
@hashed_sdk_keys_to_app_ids = specs_json[:hashed_sdk_keys_to_app_ids] || {}
|
362
|
+
@sdk_configs.set_flags(specs_json[:sdk_flags])
|
363
|
+
@sdk_configs.set_configs(specs_json[:sdk_configs])
|
325
364
|
|
326
|
-
|
327
|
-
|
365
|
+
unless from_adapter
|
366
|
+
save_rulesets_to_storage_adapter(specs_string)
|
367
|
+
end
|
368
|
+
rescue StandardError => e
|
369
|
+
return {reason: "PARSE_RESPONSE_ERROR"}
|
328
370
|
end
|
329
|
-
|
371
|
+
nil
|
330
372
|
end
|
331
373
|
|
332
374
|
def get_id_lists_from_adapter(context)
|
data/lib/statsig.rb
CHANGED
@@ -20,6 +20,13 @@ module Statsig
|
|
20
20
|
@shared_instance = StatsigDriver.new(secret_key, options, error_callback)
|
21
21
|
end
|
22
22
|
|
23
|
+
def self.get_initialization_details
|
24
|
+
if not defined? @shared_instance or @shared_instance.nil?
|
25
|
+
return {duration: 0, isSDKReady: false, configSpecReady: false, failure_details: {exception: Statsig::UninitializedError.new, reason: 'INTERNAL_ERROR'}}
|
26
|
+
end
|
27
|
+
@shared_instance.get_initialization_details
|
28
|
+
end
|
29
|
+
|
23
30
|
class GetGateOptions
|
24
31
|
attr_accessor :disable_log_exposure, :skip_evaluation, :disable_evaluation_details
|
25
32
|
|
@@ -65,7 +72,7 @@ module Statsig
|
|
65
72
|
end
|
66
73
|
|
67
74
|
##
|
68
|
-
# @deprecated - use check_gate(user, gate, options)
|
75
|
+
# @deprecated - use check_gate(user, gate, options) with CheckGateOptions.new(disable_log_exposure: true) as options
|
69
76
|
# Gets the boolean result of a gate, evaluated against the given user.
|
70
77
|
#
|
71
78
|
# @param user A StatsigUser object used for the evaluation
|
@@ -108,7 +115,7 @@ module Statsig
|
|
108
115
|
end
|
109
116
|
|
110
117
|
##
|
111
|
-
# @deprecated - use get_config(user, config, options)
|
118
|
+
# @deprecated - use get_config(user, config, options) with GetConfigOptions.new(disable_log_exposure: true) as options
|
112
119
|
# Get the values of a dynamic config, evaluated against the given user.
|
113
120
|
#
|
114
121
|
# @param [StatsigUser] user A StatsigUser object used for the evaluation
|
@@ -152,7 +159,7 @@ module Statsig
|
|
152
159
|
end
|
153
160
|
|
154
161
|
##
|
155
|
-
# @deprecated - use get_experiment(user, experiment, options)
|
162
|
+
# @deprecated - use get_experiment(user, experiment, options) with GetExperimentOptions.new(disable_log_exposure: true) as options
|
156
163
|
# Get the values of an experiment, evaluated against the given user.
|
157
164
|
#
|
158
165
|
# @param [StatsigUser] user A StatsigUser object used for the evaluation
|
@@ -199,7 +206,7 @@ module Statsig
|
|
199
206
|
end
|
200
207
|
|
201
208
|
##
|
202
|
-
# @deprecated - use get_layer(user, gate, options)
|
209
|
+
# @deprecated - use get_layer(user, gate, options) with GetLayerOptions.new(disable_log_exposure: true) as options
|
203
210
|
# Get the values of a layer, evaluated against the given user.
|
204
211
|
#
|
205
212
|
# @param user A StatsigUser object used for the evaluation
|
@@ -321,6 +328,17 @@ module Statsig
|
|
321
328
|
@shared_instance&.override_config(config_name, config_value)
|
322
329
|
end
|
323
330
|
|
331
|
+
|
332
|
+
##
|
333
|
+
# Overrides an experiment to return the value for a specific group name.
|
334
|
+
#
|
335
|
+
# @param experiment_name The name of the experiment to be overridden
|
336
|
+
# @param group_name The name of the group whose value should be returned
|
337
|
+
def self.override_experiment_by_group_name(experiment_name, group_name)
|
338
|
+
ensure_initialized
|
339
|
+
@shared_instance&.override_experiment_by_group_name(experiment_name, group_name)
|
340
|
+
end
|
341
|
+
|
324
342
|
def self.remove_config_override(config_name)
|
325
343
|
ensure_initialized
|
326
344
|
@shared_instance&.remove_config_override(config_name)
|
@@ -331,6 +349,11 @@ module Statsig
|
|
331
349
|
@shared_instance&.clear_config_overrides
|
332
350
|
end
|
333
351
|
|
352
|
+
def self.clear_experiment_overrides
|
353
|
+
ensure_initialized
|
354
|
+
@shared_instance&.clear_experiment_overrides
|
355
|
+
end
|
356
|
+
|
334
357
|
##
|
335
358
|
# @param [HashTable] debug information log with exposure events
|
336
359
|
def self.set_debug_info(debug_info)
|
@@ -363,11 +386,15 @@ module Statsig
|
|
363
386
|
def self.get_statsig_metadata
|
364
387
|
{
|
365
388
|
'sdkType' => 'ruby-server',
|
366
|
-
'sdkVersion' => '2.
|
389
|
+
'sdkVersion' => '2.5.5',
|
367
390
|
'languageVersion' => RUBY_VERSION
|
368
391
|
}
|
369
392
|
end
|
370
393
|
|
394
|
+
def self.get_options
|
395
|
+
@driver&.instance_variable_get(:@options)
|
396
|
+
end
|
397
|
+
|
371
398
|
private
|
372
399
|
|
373
400
|
def self.ensure_initialized
|
data/lib/statsig_driver.rb
CHANGED
@@ -13,6 +13,7 @@ require 'error_boundary'
|
|
13
13
|
require 'layer'
|
14
14
|
require 'memo'
|
15
15
|
require 'diagnostics'
|
16
|
+
require 'sdk_configs'
|
16
17
|
|
17
18
|
class StatsigDriver
|
18
19
|
|
@@ -27,15 +28,16 @@ class StatsigDriver
|
|
27
28
|
|
28
29
|
@err_boundary = Statsig::ErrorBoundary.new(secret_key, !options.nil? && options.local_mode)
|
29
30
|
@err_boundary.capture(caller: __method__) do
|
30
|
-
@diagnostics = Statsig::Diagnostics.new
|
31
|
+
@diagnostics = Statsig::Diagnostics.new
|
32
|
+
@sdk_configs = Statsig::SDKConfigs.new
|
31
33
|
tracker = @diagnostics.track('initialize', 'overall')
|
32
34
|
@options = options || StatsigOptions.new
|
33
35
|
@shutdown = false
|
34
36
|
@secret_key = secret_key
|
35
37
|
@net = Statsig::Network.new(secret_key, @options)
|
36
|
-
@logger = Statsig::StatsigLogger.new(@net, @options, @err_boundary)
|
38
|
+
@logger = Statsig::StatsigLogger.new(@net, @options, @err_boundary, @sdk_configs)
|
37
39
|
@persistent_storage_utils = Statsig::UserPersistentStorageUtils.new(@options)
|
38
|
-
@store = Statsig::SpecStore.new(@net, @options, error_callback, @diagnostics, @err_boundary, @logger, secret_key)
|
40
|
+
@store = Statsig::SpecStore.new(@net, @options, error_callback, @diagnostics, @err_boundary, @logger, secret_key, @sdk_configs)
|
39
41
|
@evaluator = Statsig::Evaluator.new(@store, @options, @persistent_storage_utils)
|
40
42
|
tracker.end(success: true)
|
41
43
|
|
@@ -43,6 +45,10 @@ class StatsigDriver
|
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
48
|
+
def get_initialization_details
|
49
|
+
@store.get_initialization_details
|
50
|
+
end
|
51
|
+
|
46
52
|
def get_gate_impl(
|
47
53
|
user,
|
48
54
|
gate_name,
|
@@ -59,7 +65,7 @@ class StatsigDriver
|
|
59
65
|
|
60
66
|
user = verify_inputs(user, gate_name, 'gate_name')
|
61
67
|
|
62
|
-
Statsig::Memo.for(user.get_memo, :get_gate_impl, gate_name) do
|
68
|
+
Statsig::Memo.for(user.get_memo, :get_gate_impl, gate_name, disable_evaluation_memoization: @options.disable_evaluation_memoization) do
|
63
69
|
res = Statsig::ConfigResult.new(
|
64
70
|
name: gate_name,
|
65
71
|
disable_exposures: disable_log_exposure,
|
@@ -68,9 +74,7 @@ class StatsigDriver
|
|
68
74
|
@evaluator.check_gate(user, gate_name, res, ignore_local_overrides: ignore_local_overrides)
|
69
75
|
|
70
76
|
unless disable_log_exposure
|
71
|
-
@logger.log_gate_exposure(
|
72
|
-
user, res.name, res.gate_value, res.rule_id, res.secondary_exposures, res.evaluation_details
|
73
|
-
)
|
77
|
+
@logger.log_gate_exposure(user, res)
|
74
78
|
end
|
75
79
|
|
76
80
|
FeatureGate.from_config_result(res)
|
@@ -109,7 +113,7 @@ class StatsigDriver
|
|
109
113
|
res = Statsig::ConfigResult.new(name: gate_name)
|
110
114
|
@evaluator.check_gate(user, gate_name, res)
|
111
115
|
context = { :is_manual_exposure => true }
|
112
|
-
@logger.log_gate_exposure(user,
|
116
|
+
@logger.log_gate_exposure(user, res, context)
|
113
117
|
end
|
114
118
|
end
|
115
119
|
|
@@ -150,7 +154,7 @@ class StatsigDriver
|
|
150
154
|
@evaluator.get_config(user, config_name, res)
|
151
155
|
|
152
156
|
context = { :is_manual_exposure => true }
|
153
|
-
@logger.log_config_exposure(user, res
|
157
|
+
@logger.log_config_exposure(user, res, context)
|
154
158
|
end
|
155
159
|
end
|
156
160
|
|
@@ -167,7 +171,7 @@ class StatsigDriver
|
|
167
171
|
@err_boundary.capture(caller: __method__, recover: -> { Layer.new(layer_name) }) do
|
168
172
|
run_with_diagnostics(caller: :get_layer) do
|
169
173
|
user = verify_inputs(user, layer_name, "layer_name")
|
170
|
-
Statsig::Memo.for(user.get_memo, :get_layer, layer_name) do
|
174
|
+
Statsig::Memo.for(user.get_memo, :get_layer, layer_name, disable_evaluation_memoization: @options.disable_evaluation_memoization) do
|
171
175
|
exposures_disabled = options&.disable_log_exposure == true
|
172
176
|
res = Statsig::ConfigResult.new(
|
173
177
|
name: layer_name,
|
@@ -300,6 +304,12 @@ class StatsigDriver
|
|
300
304
|
end
|
301
305
|
end
|
302
306
|
|
307
|
+
def clear_experiment_overrides
|
308
|
+
@err_boundary.capture(caller: __method__) do
|
309
|
+
@evaluator.clear_experiment_overrides
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
303
313
|
def set_debug_info(debug_info)
|
304
314
|
@err_boundary.capture(caller: __method__) do
|
305
315
|
@logger.set_debug_info(debug_info)
|
@@ -333,6 +343,10 @@ class StatsigDriver
|
|
333
343
|
end
|
334
344
|
end
|
335
345
|
|
346
|
+
def override_experiment_by_group_name(experiment_name, group_name)
|
347
|
+
@evaluator.override_experiment_by_group_name(experiment_name, group_name)
|
348
|
+
end
|
349
|
+
|
336
350
|
private
|
337
351
|
|
338
352
|
def run_with_diagnostics(caller:)
|
@@ -357,7 +371,7 @@ class StatsigDriver
|
|
357
371
|
|
358
372
|
def verify_inputs(user, config_name, variable_name)
|
359
373
|
validate_user(user)
|
360
|
-
user = Statsig::Memo.for(user.get_memo(), :verify_inputs, 0) do
|
374
|
+
user = Statsig::Memo.for(user.get_memo(), :verify_inputs, 0, disable_evaluation_memoization: @options.disable_evaluation_memoization) do
|
361
375
|
user = normalize_user(user)
|
362
376
|
check_shutdown
|
363
377
|
maybe_restart_background_threads
|
@@ -372,7 +386,7 @@ class StatsigDriver
|
|
372
386
|
end
|
373
387
|
|
374
388
|
def get_config_impl(user, config_name, disable_log_exposure, user_persisted_values: nil, disable_evaluation_details: false, ignore_local_overrides: false)
|
375
|
-
Statsig::Memo.for(user.get_memo, :get_config_impl, config_name) do
|
389
|
+
Statsig::Memo.for(user.get_memo, :get_config_impl, config_name, disable_evaluation_memoization: @options.disable_evaluation_memoization) do
|
376
390
|
res = Statsig::ConfigResult.new(
|
377
391
|
name: config_name,
|
378
392
|
disable_exposures: disable_log_exposure,
|
@@ -381,7 +395,7 @@ class StatsigDriver
|
|
381
395
|
@evaluator.get_config(user, config_name, res, user_persisted_values: user_persisted_values, ignore_local_overrides: ignore_local_overrides)
|
382
396
|
|
383
397
|
unless disable_log_exposure
|
384
|
-
@logger.log_config_exposure(user, res
|
398
|
+
@logger.log_config_exposure(user, res)
|
385
399
|
end
|
386
400
|
|
387
401
|
DynamicConfig.new(res.name, res.json_value, res.rule_id, res.group_name, res.id_type, res.evaluation_details)
|
data/lib/statsig_event.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
class StatsigEvent
|
3
2
|
attr_accessor :value, :metadata, :statsig_metadata, :secondary_exposures
|
4
3
|
attr_reader :user
|
@@ -15,7 +14,7 @@ class StatsigEvent
|
|
15
14
|
|
16
15
|
def user=(value)
|
17
16
|
if value.is_a?(StatsigUser)
|
18
|
-
@user = Statsig::Memo.for(value.get_memo(), :serialize, 0) do
|
17
|
+
@user = Statsig::Memo.for(value.get_memo(), :serialize, 0, disable_evaluation_memoization: Statsig.get_options&.disable_evaluation_memoization) do
|
19
18
|
value.serialize(true)
|
20
19
|
end
|
21
20
|
end
|