statsig 1.31.1 → 1.32.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/api_config.rb +128 -0
- data/lib/client_initialize_helpers.rb +78 -88
- data/lib/config_result.rb +17 -32
- data/lib/constants.rb +60 -0
- data/lib/diagnostics.rb +1 -38
- data/lib/dynamic_config.rb +1 -24
- data/lib/error_boundary.rb +0 -5
- data/lib/evaluation_details.rb +4 -1
- data/lib/evaluation_helpers.rb +35 -3
- data/lib/evaluator.rb +332 -327
- data/lib/feature_gate.rb +0 -24
- data/lib/id_list.rb +1 -1
- data/lib/interfaces/data_store.rb +1 -1
- data/lib/interfaces/user_persistent_storage.rb +1 -1
- data/lib/layer.rb +1 -20
- data/lib/network.rb +6 -33
- data/lib/spec_store.rb +86 -74
- data/lib/statsig.rb +72 -97
- data/lib/statsig_driver.rb +63 -70
- data/lib/statsig_errors.rb +1 -1
- data/lib/statsig_event.rb +8 -8
- data/lib/statsig_logger.rb +21 -21
- data/lib/statsig_options.rb +0 -50
- data/lib/statsig_user.rb +27 -68
- data/lib/ua_parser.rb +1 -1
- data/lib/uri_helper.rb +1 -9
- data/lib/user_persistent_storage_utils.rb +0 -17
- metadata +8 -6
data/lib/statsig.rb
CHANGED
@@ -1,13 +1,9 @@
|
|
1
|
-
# typed: true
|
2
|
-
|
3
1
|
require 'statsig_driver'
|
4
|
-
|
2
|
+
|
5
3
|
require 'statsig_errors'
|
6
4
|
|
7
5
|
module Statsig
|
8
|
-
extend T::Sig
|
9
6
|
|
10
|
-
sig { params(secret_key: String, options: T.any(StatsigOptions, NilClass), error_callback: T.any(Method, Proc, NilClass)).void }
|
11
7
|
##
|
12
8
|
# Initializes the Statsig SDK.
|
13
9
|
#
|
@@ -21,46 +17,54 @@ module Statsig
|
|
21
17
|
return @shared_instance
|
22
18
|
end
|
23
19
|
|
24
|
-
self.bind_sorbet_loggers(options)
|
25
|
-
|
26
20
|
@shared_instance = StatsigDriver.new(secret_key, options, error_callback)
|
27
21
|
end
|
28
22
|
|
29
|
-
class GetGateOptions
|
30
|
-
|
31
|
-
|
23
|
+
class GetGateOptions
|
24
|
+
attr_accessor :disable_log_exposure, :skip_evaluation, :disable_evaluation_details
|
25
|
+
|
26
|
+
def initialize(disable_log_exposure: false, skip_evaluation: false, disable_evaluation_details: false)
|
27
|
+
@disable_log_exposure = disable_log_exposure
|
28
|
+
@skip_evaluation = skip_evaluation
|
29
|
+
@disable_evaluation_details = disable_evaluation_details
|
30
|
+
end
|
32
31
|
end
|
33
32
|
|
34
|
-
sig { params(user: StatsigUser, gate_name: String, options: GetGateOptions).returns(FeatureGate) }
|
35
33
|
##
|
36
34
|
# Gets the gate, evaluated against the given user. An exposure event will automatically be logged for the gate.
|
37
35
|
#
|
38
|
-
# @param user A StatsigUser object used for the evaluation
|
39
|
-
# @param gate_name The name of the gate being checked
|
40
|
-
# @param options Additional options for evaluating the gate
|
41
|
-
|
36
|
+
# @param [StatsigUser] user A StatsigUser object used for the evaluation
|
37
|
+
# @param [String] gate_name The name of the gate being checked
|
38
|
+
# @param [GetGateOptions] options Additional options for evaluating the gate
|
39
|
+
# @return [FeatureGate]
|
40
|
+
def self.get_gate(user, gate_name, options)
|
42
41
|
ensure_initialized
|
43
42
|
@shared_instance&.get_gate(user, gate_name, options)
|
44
43
|
end
|
45
44
|
|
46
|
-
class CheckGateOptions
|
47
|
-
|
45
|
+
class CheckGateOptions
|
46
|
+
attr_accessor :disable_log_exposure, :disable_evaluation_details
|
47
|
+
|
48
|
+
def initialize(disable_log_exposure: false, disable_evaluation_details: false)
|
49
|
+
@disable_log_exposure = disable_log_exposure
|
50
|
+
@disable_evaluation_details = disable_evaluation_details
|
51
|
+
end
|
48
52
|
end
|
49
53
|
|
50
|
-
sig { params(user: StatsigUser, gate_name: String, options: CheckGateOptions).returns(T::Boolean) }
|
51
54
|
##
|
52
55
|
# Gets the boolean result of a gate, evaluated against the given user. An exposure event will automatically be logged for the gate.
|
53
56
|
#
|
54
|
-
# @param user A StatsigUser object used for the evaluation
|
55
|
-
# @param gate_name The name of the gate being checked
|
56
|
-
# @param options Additional options for evaluating the gate
|
57
|
-
|
57
|
+
# @param [StatsigUser] user A StatsigUser object used for the evaluation
|
58
|
+
# @param [String] gate_name The name of the gate being checked
|
59
|
+
# @param [CheckGateOptions] options Additional options for evaluating the gate
|
60
|
+
# @return [Boolean]
|
61
|
+
def self.check_gate(user, gate_name, options = nil)
|
58
62
|
ensure_initialized
|
59
63
|
@shared_instance&.check_gate(user, gate_name, options)
|
60
64
|
end
|
61
65
|
|
62
|
-
sig { params(user: StatsigUser, gate_name: String).returns(T::Boolean) }
|
63
66
|
##
|
67
|
+
# @deprecated - use check_gate(user, gate, options) and disable_exposure_logging in options
|
64
68
|
# Gets the boolean result of a gate, evaluated against the given user.
|
65
69
|
#
|
66
70
|
# @param user A StatsigUser object used for the evaluation
|
@@ -70,7 +74,6 @@ module Statsig
|
|
70
74
|
@shared_instance&.check_gate(user, gate_name, CheckGateOptions.new(disable_log_exposure: true))
|
71
75
|
end
|
72
76
|
|
73
|
-
sig { params(user: StatsigUser, gate_name: String).void }
|
74
77
|
##
|
75
78
|
# Logs an exposure event for the gate
|
76
79
|
#
|
@@ -81,34 +84,39 @@ module Statsig
|
|
81
84
|
@shared_instance&.manually_log_gate_exposure(user, gate_name)
|
82
85
|
end
|
83
86
|
|
84
|
-
class GetConfigOptions
|
85
|
-
|
87
|
+
class GetConfigOptions
|
88
|
+
attr_accessor :disable_log_exposure, :disable_evaluation_details
|
89
|
+
|
90
|
+
def initialize(disable_log_exposure: false, disable_evaluation_details: false)
|
91
|
+
@disable_log_exposure = disable_log_exposure
|
92
|
+
@disable_evaluation_details = disable_evaluation_details
|
93
|
+
end
|
86
94
|
end
|
87
95
|
|
88
|
-
sig { params(user: StatsigUser, dynamic_config_name: String, options: GetConfigOptions).returns(DynamicConfig) }
|
89
96
|
##
|
90
97
|
# Get the values of a dynamic config, evaluated against the given user. An exposure event will automatically be logged for the dynamic config.
|
91
98
|
#
|
92
|
-
# @param user A StatsigUser object used for the evaluation
|
93
|
-
# @param dynamic_config_name The name of the dynamic config
|
94
|
-
# @param options Additional options for evaluating the config
|
95
|
-
|
99
|
+
# @param [StatsigUser] user A StatsigUser object used for the evaluation
|
100
|
+
# @param [String] dynamic_config_name The name of the dynamic config
|
101
|
+
# @param [GetConfigOptions] options Additional options for evaluating the config
|
102
|
+
# @return [DynamicConfig]
|
103
|
+
def self.get_config(user, dynamic_config_name, options = nil)
|
96
104
|
ensure_initialized
|
97
105
|
@shared_instance&.get_config(user, dynamic_config_name, options)
|
98
106
|
end
|
99
107
|
|
100
|
-
sig { params(user: StatsigUser, dynamic_config_name: String).returns(DynamicConfig) }
|
101
108
|
##
|
109
|
+
# @deprecated - use get_config(user, config, options) and disable_exposure_logging in options
|
102
110
|
# Get the values of a dynamic config, evaluated against the given user.
|
103
111
|
#
|
104
|
-
# @param user A StatsigUser object used for the evaluation
|
105
|
-
# @param dynamic_config_name The name of the dynamic config
|
112
|
+
# @param [StatsigUser] user A StatsigUser object used for the evaluation
|
113
|
+
# @param [String] dynamic_config_name The name of the dynamic config
|
114
|
+
# @return [DynamicConfig]
|
106
115
|
def self.get_config_with_exposure_logging_disabled(user, dynamic_config_name)
|
107
116
|
ensure_initialized
|
108
117
|
@shared_instance&.get_config(user, dynamic_config_name, GetConfigOptions.new(disable_log_exposure: true))
|
109
118
|
end
|
110
119
|
|
111
|
-
sig { params(user: StatsigUser, dynamic_config: String).void }
|
112
120
|
##
|
113
121
|
# Logs an exposure event for the dynamic config
|
114
122
|
#
|
@@ -119,35 +127,38 @@ module Statsig
|
|
119
127
|
@shared_instance&.manually_log_config_exposure(user, dynamic_config)
|
120
128
|
end
|
121
129
|
|
122
|
-
class GetExperimentOptions
|
123
|
-
|
124
|
-
|
130
|
+
class GetExperimentOptions
|
131
|
+
attr_accessor :disable_log_exposure, :user_persisted_values, :disable_evaluation_details
|
132
|
+
|
133
|
+
def initialize(disable_log_exposure: false, user_persisted_values: nil, disable_evaluation_details: false)
|
134
|
+
@disable_log_exposure = disable_log_exposure
|
135
|
+
@user_persisted_values = user_persisted_values
|
136
|
+
@disable_evaluation_details = disable_evaluation_details
|
137
|
+
end
|
125
138
|
end
|
126
139
|
|
127
|
-
sig { params(user: StatsigUser, experiment_name: String, options: GetExperimentOptions).returns(DynamicConfig) }
|
128
140
|
##
|
129
141
|
# Get the values of an experiment, evaluated against the given user. An exposure event will automatically be logged for the experiment.
|
130
142
|
#
|
131
|
-
# @param user A StatsigUser object used for the evaluation
|
132
|
-
# @param experiment_name The name of the experiment
|
133
|
-
# @param options Additional options for evaluating the experiment
|
134
|
-
def self.get_experiment(user, experiment_name, options =
|
143
|
+
# @param [StatsigUser] user A StatsigUser object used for the evaluation
|
144
|
+
# @param [String] experiment_name The name of the experiment
|
145
|
+
# @param [GetExperimentOptions] options Additional options for evaluating the experiment
|
146
|
+
def self.get_experiment(user, experiment_name, options = nil)
|
135
147
|
ensure_initialized
|
136
148
|
@shared_instance&.get_experiment(user, experiment_name, options)
|
137
149
|
end
|
138
150
|
|
139
|
-
sig { params(user: StatsigUser, experiment_name: String).returns(DynamicConfig) }
|
140
151
|
##
|
152
|
+
# @deprecated - use get_experiment(user, experiment, options) and disable_exposure_logging in options
|
141
153
|
# Get the values of an experiment, evaluated against the given user.
|
142
154
|
#
|
143
|
-
# @param user A StatsigUser object used for the evaluation
|
144
|
-
# @param experiment_name The name of the experiment
|
155
|
+
# @param [StatsigUser] user A StatsigUser object used for the evaluation
|
156
|
+
# @param [String] experiment_name The name of the experiment
|
145
157
|
def self.get_experiment_with_exposure_logging_disabled(user, experiment_name)
|
146
158
|
ensure_initialized
|
147
159
|
@shared_instance&.get_experiment(user, experiment_name, GetExperimentOptions.new(disable_log_exposure: true))
|
148
160
|
end
|
149
161
|
|
150
|
-
sig { params(user: StatsigUser, experiment_name: String).void }
|
151
162
|
##
|
152
163
|
# Logs an exposure event for the experiment
|
153
164
|
#
|
@@ -158,30 +169,34 @@ module Statsig
|
|
158
169
|
@shared_instance&.manually_log_config_exposure(user, experiment_name)
|
159
170
|
end
|
160
171
|
|
161
|
-
sig { params(user: StatsigUser, id_type: String).returns(UserPersistedValues) }
|
162
172
|
def self.get_user_persisted_values(user, id_type)
|
163
173
|
ensure_initialized
|
164
174
|
@shared_instance&.get_user_persisted_values(user, id_type)
|
165
175
|
end
|
166
176
|
|
167
|
-
class GetLayerOptions
|
168
|
-
|
177
|
+
class GetLayerOptions
|
178
|
+
attr_accessor :disable_log_exposure, :disable_evaluation_details
|
179
|
+
|
180
|
+
def initialize(disable_log_exposure: false, disable_evaluation_details: false)
|
181
|
+
@disable_log_exposure = disable_log_exposure
|
182
|
+
@disable_evaluation_details = disable_evaluation_details
|
183
|
+
end
|
169
184
|
end
|
170
185
|
|
171
|
-
sig { params(user: StatsigUser, layer_name: String, options: GetLayerOptions).returns(Layer) }
|
172
186
|
##
|
173
187
|
# Get the values of a layer, evaluated against the given user.
|
174
188
|
# Exposure events will be fired when get or get_typed is called on the resulting Layer class.
|
175
189
|
#
|
176
|
-
# @param user A StatsigUser object used for the evaluation
|
177
|
-
# @param layer_name The name of the layer
|
178
|
-
|
190
|
+
# @param [StatsigUser] user A StatsigUser object used for the evaluation
|
191
|
+
# @param [String] layer_name The name of the layer
|
192
|
+
# @param [GetLayerOptions] options Configuration of how this method call should behave
|
193
|
+
def self.get_layer(user, layer_name, options = nil)
|
179
194
|
ensure_initialized
|
180
195
|
@shared_instance&.get_layer(user, layer_name, options)
|
181
196
|
end
|
182
197
|
|
183
|
-
sig { params(user: StatsigUser, layer_name: String).returns(Layer) }
|
184
198
|
##
|
199
|
+
# @deprecated - use get_layer(user, gate, options) and disable_exposure_logging in options
|
185
200
|
# Get the values of a layer, evaluated against the given user.
|
186
201
|
#
|
187
202
|
# @param user A StatsigUser object used for the evaluation
|
@@ -191,7 +206,6 @@ module Statsig
|
|
191
206
|
@shared_instance&.get_layer(user, layer_name, GetLayerOptions.new(disable_log_exposure: true))
|
192
207
|
end
|
193
208
|
|
194
|
-
sig { params(user: StatsigUser, layer_name: String, parameter_name: String).void }
|
195
209
|
##
|
196
210
|
# Logs an exposure event for the parameter in the given layer
|
197
211
|
#
|
@@ -203,10 +217,6 @@ module Statsig
|
|
203
217
|
@shared_instance&.manually_log_layer_parameter_exposure(user, layer_name, parameter_name)
|
204
218
|
end
|
205
219
|
|
206
|
-
sig { params(user: StatsigUser,
|
207
|
-
event_name: String,
|
208
|
-
value: T.any(String, Integer, Float, NilClass),
|
209
|
-
metadata: T.any(T::Hash[String, T.untyped], NilClass)).void }
|
210
220
|
##
|
211
221
|
# Logs an event to Statsig with the provided values.
|
212
222
|
#
|
@@ -229,7 +239,6 @@ module Statsig
|
|
229
239
|
@shared_instance&.manually_sync_idlists
|
230
240
|
end
|
231
241
|
|
232
|
-
sig { returns(T::Array[String]) }
|
233
242
|
##
|
234
243
|
# Returns a list of all gate names
|
235
244
|
#
|
@@ -238,7 +247,6 @@ module Statsig
|
|
238
247
|
@shared_instance&.list_gates
|
239
248
|
end
|
240
249
|
|
241
|
-
sig { returns(T::Array[String]) }
|
242
250
|
##
|
243
251
|
# Returns a list of all config names
|
244
252
|
#
|
@@ -247,7 +255,6 @@ module Statsig
|
|
247
255
|
@shared_instance&.list_configs
|
248
256
|
end
|
249
257
|
|
250
|
-
sig { returns(T::Array[String]) }
|
251
258
|
##
|
252
259
|
# Returns a list of all experiment names
|
253
260
|
#
|
@@ -256,7 +263,6 @@ module Statsig
|
|
256
263
|
@shared_instance&.list_experiments
|
257
264
|
end
|
258
265
|
|
259
|
-
sig { returns(T::Array[String]) }
|
260
266
|
##
|
261
267
|
# Returns a list of all autotune names
|
262
268
|
#
|
@@ -265,7 +271,6 @@ module Statsig
|
|
265
271
|
@shared_instance&.list_autotunes
|
266
272
|
end
|
267
273
|
|
268
|
-
sig { returns(T::Array[String]) }
|
269
274
|
##
|
270
275
|
# Returns a list of all layer names
|
271
276
|
#
|
@@ -274,7 +279,6 @@ module Statsig
|
|
274
279
|
@shared_instance&.list_layers
|
275
280
|
end
|
276
281
|
|
277
|
-
sig { void }
|
278
282
|
##
|
279
283
|
# Stops all Statsig activity and flushes any pending events.
|
280
284
|
def self.shutdown
|
@@ -284,7 +288,6 @@ module Statsig
|
|
284
288
|
@shared_instance = nil
|
285
289
|
end
|
286
290
|
|
287
|
-
sig { params(gate_name: String, gate_value: T::Boolean).void }
|
288
291
|
##
|
289
292
|
# Sets a value to be returned for the given gate instead of the actual evaluated value.
|
290
293
|
#
|
@@ -295,7 +298,6 @@ module Statsig
|
|
295
298
|
@shared_instance&.override_gate(gate_name, gate_value)
|
296
299
|
end
|
297
300
|
|
298
|
-
sig { params(config_name: String, config_value: Hash).void }
|
299
301
|
##
|
300
302
|
# Sets a value to be returned for the given dynamic config/experiment instead of the actual evaluated value.
|
301
303
|
#
|
@@ -306,7 +308,6 @@ module Statsig
|
|
306
308
|
@shared_instance&.override_config(config_name, config_value)
|
307
309
|
end
|
308
310
|
|
309
|
-
sig { params(user: StatsigUser, hash: String, client_sdk_key: T.any(String, NilClass)).returns(T.any(T::Hash[String, T.untyped], NilClass)) }
|
310
311
|
##
|
311
312
|
# Gets all evaluated values for the given user.
|
312
313
|
# These values can then be given to a Statsig Client SDK via bootstrapping.
|
@@ -321,13 +322,12 @@ module Statsig
|
|
321
322
|
@shared_instance&.get_client_initialize_response(user, hash, client_sdk_key)
|
322
323
|
end
|
323
324
|
|
324
|
-
sig { returns(T::Hash[String, String]) }
|
325
325
|
##
|
326
326
|
# Internal Statsig metadata for this SDK
|
327
327
|
def self.get_statsig_metadata
|
328
328
|
{
|
329
329
|
'sdkType' => 'ruby-server',
|
330
|
-
'sdkVersion' => '1.
|
330
|
+
'sdkVersion' => '1.32.0',
|
331
331
|
'languageVersion' => RUBY_VERSION
|
332
332
|
}
|
333
333
|
end
|
@@ -340,29 +340,4 @@ module Statsig
|
|
340
340
|
end
|
341
341
|
end
|
342
342
|
|
343
|
-
|
344
|
-
def self.bind_sorbet_loggers(options)
|
345
|
-
if options&.disable_sorbet_logging_handlers == true
|
346
|
-
return
|
347
|
-
end
|
348
|
-
|
349
|
-
T::Configuration.call_validation_error_handler = lambda do |signature, opts|
|
350
|
-
puts "[Type Error] " + opts[:pretty_message]
|
351
|
-
end
|
352
|
-
|
353
|
-
T::Configuration.inline_type_error_handler = lambda do |error, opts|
|
354
|
-
puts "[Type Error] " + error.message
|
355
|
-
end
|
356
|
-
|
357
|
-
T::Configuration.sig_builder_error_handler = lambda do |error, location|
|
358
|
-
puts "[Type Error] " + error.message
|
359
|
-
end
|
360
|
-
|
361
|
-
T::Configuration.sig_validation_error_handler = lambda do |error, opts|
|
362
|
-
puts "[Type Error] " + error.message
|
363
|
-
end
|
364
|
-
|
365
|
-
return
|
366
|
-
end
|
367
|
-
|
368
|
-
end
|
343
|
+
end
|
data/lib/statsig_driver.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# typed: true
|
2
|
-
|
3
1
|
require 'config_result'
|
4
2
|
require 'evaluator'
|
5
3
|
require 'network'
|
@@ -13,13 +11,11 @@ require 'dynamic_config'
|
|
13
11
|
require 'feature_gate'
|
14
12
|
require 'error_boundary'
|
15
13
|
require 'layer'
|
16
|
-
|
14
|
+
|
17
15
|
require 'diagnostics'
|
18
16
|
|
19
17
|
class StatsigDriver
|
20
|
-
extend T::Sig
|
21
18
|
|
22
|
-
sig { params(secret_key: String, options: T.any(StatsigOptions, NilClass), error_callback: T.any(Method, Proc, NilClass)).void }
|
23
19
|
def initialize(secret_key, options = nil, error_callback = nil)
|
24
20
|
unless secret_key.start_with?('secret-')
|
25
21
|
raise Statsig::ValueError.new('Invalid secret key provided. Provide your project secret key from the Statsig console')
|
@@ -47,26 +43,16 @@ class StatsigDriver
|
|
47
43
|
}, caller: __method__.to_s)
|
48
44
|
end
|
49
45
|
|
50
|
-
|
51
|
-
params(
|
52
|
-
user: StatsigUser,
|
53
|
-
gate_name: String,
|
54
|
-
disable_log_exposure: T::Boolean,
|
55
|
-
skip_evaluation: T::Boolean
|
56
|
-
).returns(FeatureGate)
|
57
|
-
end
|
58
|
-
def get_gate_impl(user, gate_name, disable_log_exposure: false, skip_evaluation: false)
|
46
|
+
def get_gate_impl(user, gate_name, disable_log_exposure: false, skip_evaluation: false, disable_evaluation_details: false)
|
59
47
|
if skip_evaluation
|
60
48
|
gate = @store.get_gate(gate_name)
|
61
49
|
return FeatureGate.new(gate_name) if gate.nil?
|
62
|
-
return FeatureGate.new(gate
|
50
|
+
return FeatureGate.new(gate.name, target_app_ids: gate.target_app_ids)
|
63
51
|
end
|
64
52
|
user = verify_inputs(user, gate_name, 'gate_name')
|
65
53
|
|
66
|
-
res =
|
67
|
-
|
68
|
-
res = Statsig::ConfigResult.new(gate_name)
|
69
|
-
end
|
54
|
+
res = Statsig::ConfigResult.new(name: gate_name, disable_exposures: disable_log_exposure, disable_evaluation_details: disable_evaluation_details)
|
55
|
+
@evaluator.check_gate(user, gate_name, res)
|
70
56
|
|
71
57
|
unless disable_log_exposure
|
72
58
|
@logger.log_gate_exposure(
|
@@ -76,63 +62,79 @@ class StatsigDriver
|
|
76
62
|
FeatureGate.from_config_result(res)
|
77
63
|
end
|
78
64
|
|
79
|
-
|
80
|
-
def get_gate(user, gate_name, options = Statsig::GetGateOptions.new)
|
65
|
+
def get_gate(user, gate_name, options = nil)
|
81
66
|
@err_boundary.capture(task: lambda {
|
82
67
|
run_with_diagnostics(task: lambda {
|
83
|
-
get_gate_impl(user, gate_name,
|
68
|
+
get_gate_impl(user, gate_name,
|
69
|
+
disable_log_exposure: options&.disable_log_exposure == true,
|
70
|
+
skip_evaluation: options&.skip_evaluation == true,
|
71
|
+
disable_evaluation_details: options&.disable_evaluation_details == true
|
72
|
+
)
|
84
73
|
}, caller: __method__.to_s)
|
85
74
|
}, recover: -> { false }, caller: __method__.to_s)
|
86
75
|
end
|
87
76
|
|
88
|
-
|
89
|
-
def check_gate(user, gate_name, options = Statsig::CheckGateOptions.new)
|
77
|
+
def check_gate(user, gate_name, options = nil)
|
90
78
|
@err_boundary.capture(task: lambda {
|
91
79
|
run_with_diagnostics(task: lambda {
|
92
|
-
get_gate_impl(
|
80
|
+
get_gate_impl(
|
81
|
+
user,
|
82
|
+
gate_name,
|
83
|
+
disable_log_exposure: options&.disable_log_exposure == true,
|
84
|
+
disable_evaluation_details: options&.disable_evaluation_details == true
|
85
|
+
).value
|
93
86
|
}, caller: __method__.to_s)
|
94
87
|
}, recover: -> { false }, caller: __method__.to_s)
|
95
88
|
end
|
96
89
|
|
97
|
-
sig { params(user: StatsigUser, gate_name: String).void }
|
98
90
|
def manually_log_gate_exposure(user, gate_name)
|
99
91
|
@err_boundary.capture(task: lambda {
|
100
|
-
res =
|
101
|
-
|
92
|
+
res = Statsig::ConfigResult.new(name: gate_name)
|
93
|
+
@evaluator.check_gate(user, gate_name, res)
|
94
|
+
context = { :is_manual_exposure => true }
|
102
95
|
@logger.log_gate_exposure(user, gate_name, res.gate_value, res.rule_id, res.secondary_exposures, res.evaluation_details, context)
|
103
96
|
})
|
104
97
|
end
|
105
98
|
|
106
|
-
|
107
|
-
def get_config(user, dynamic_config_name, options = Statsig::GetConfigOptions.new)
|
99
|
+
def get_config(user, dynamic_config_name, options = nil)
|
108
100
|
@err_boundary.capture(task: lambda {
|
109
101
|
run_with_diagnostics(task: lambda {
|
110
102
|
user = verify_inputs(user, dynamic_config_name, "dynamic_config_name")
|
111
|
-
get_config_impl(
|
103
|
+
get_config_impl(
|
104
|
+
user,
|
105
|
+
dynamic_config_name,
|
106
|
+
options&.disable_log_exposure == true,
|
107
|
+
disable_evaluation_details: options&.disable_evaluation_details == true
|
108
|
+
)
|
112
109
|
}, caller: __method__.to_s)
|
113
110
|
}, recover: -> { DynamicConfig.new(dynamic_config_name) }, caller: __method__.to_s)
|
114
111
|
end
|
115
112
|
|
116
|
-
|
117
|
-
def get_experiment(user, experiment_name, options = Statsig::GetExperimentOptions.new)
|
113
|
+
def get_experiment(user, experiment_name, options = nil)
|
118
114
|
@err_boundary.capture(task: lambda {
|
119
115
|
run_with_diagnostics(task: lambda {
|
120
116
|
user = verify_inputs(user, experiment_name, "experiment_name")
|
121
|
-
get_config_impl(
|
117
|
+
get_config_impl(
|
118
|
+
user,
|
119
|
+
experiment_name,
|
120
|
+
options&.disable_log_exposure == true,
|
121
|
+
user_persisted_values: options&.user_persisted_values,
|
122
|
+
disable_evaluation_details: options&.disable_evaluation_details == true
|
123
|
+
)
|
122
124
|
}, caller: __method__.to_s)
|
123
125
|
}, recover: -> { DynamicConfig.new(experiment_name) }, caller: __method__.to_s)
|
124
126
|
end
|
125
127
|
|
126
|
-
sig { params(user: StatsigUser, config_name: String).void }
|
127
128
|
def manually_log_config_exposure(user, config_name)
|
128
129
|
@err_boundary.capture(task: lambda {
|
129
|
-
res =
|
130
|
-
|
130
|
+
res = Statsig::ConfigResult.new(name: config_name)
|
131
|
+
@evaluator.get_config(user, config_name, res)
|
132
|
+
|
133
|
+
context = { :is_manual_exposure => true }
|
131
134
|
@logger.log_config_exposure(user, res.name, res.rule_id, res.secondary_exposures, res.evaluation_details, context)
|
132
135
|
}, caller: __method__.to_s)
|
133
136
|
end
|
134
137
|
|
135
|
-
sig { params(user: StatsigUser, id_type: String).returns(Statsig::UserPersistedValues) }
|
136
138
|
def get_user_persisted_values(user, id_type)
|
137
139
|
@err_boundary.capture(task: lambda {
|
138
140
|
persisted_values = @persistent_storage_utils.get_user_persisted_values(user, id_type)
|
@@ -142,31 +144,34 @@ class StatsigDriver
|
|
142
144
|
}, caller: __method__.to_s)
|
143
145
|
end
|
144
146
|
|
145
|
-
|
146
|
-
def get_layer(user, layer_name, options = Statsig::GetLayerOptions.new)
|
147
|
+
def get_layer(user, layer_name, options = nil)
|
147
148
|
@err_boundary.capture(task: lambda {
|
148
149
|
run_with_diagnostics(task: lambda {
|
149
150
|
user = verify_inputs(user, layer_name, "layer_name")
|
150
|
-
|
151
|
-
res =
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
151
|
+
exposures_disabled = options&.disable_log_exposure == true
|
152
|
+
res = Statsig::ConfigResult.new(
|
153
|
+
name: layer_name,
|
154
|
+
disable_exposures: exposures_disabled,
|
155
|
+
disable_evaluation_details: options&.disable_evaluation_details == true
|
156
|
+
)
|
157
|
+
@evaluator.get_layer(user, layer_name, res)
|
158
|
+
|
159
|
+
exposure_log_func = !exposures_disabled ? lambda { |layer, parameter_name|
|
157
160
|
@logger.log_layer_exposure(user, layer, parameter_name, res)
|
158
161
|
} : nil
|
162
|
+
|
159
163
|
Layer.new(res.name, res.json_value, res.rule_id, res.group_name, res.config_delegate, exposure_log_func)
|
160
164
|
}, caller: __method__.to_s)
|
161
165
|
}, recover: lambda { Layer.new(layer_name) }, caller: __method__.to_s)
|
162
166
|
end
|
163
167
|
|
164
|
-
sig { params(user: StatsigUser, layer_name: String, parameter_name: String).void }
|
165
168
|
def manually_log_layer_parameter_exposure(user, layer_name, parameter_name)
|
166
169
|
@err_boundary.capture(task: lambda {
|
167
|
-
res =
|
170
|
+
res = Statsig::ConfigResult.new(name: layer_name)
|
171
|
+
@evaluator.get_layer(user, layer_name, res)
|
172
|
+
|
168
173
|
layer = Layer.new(layer_name, res.json_value, res.rule_id, res.group_name, res.config_delegate)
|
169
|
-
context = {
|
174
|
+
context = { :is_manual_exposure => true }
|
170
175
|
@logger.log_layer_exposure(user, layer, parameter_name, res, context)
|
171
176
|
}, caller: __method__.to_s)
|
172
177
|
end
|
@@ -200,35 +205,30 @@ class StatsigDriver
|
|
200
205
|
}, caller: __method__.to_s)
|
201
206
|
end
|
202
207
|
|
203
|
-
sig { returns(T::Array[String]) }
|
204
208
|
def list_gates
|
205
209
|
@err_boundary.capture(task: lambda {
|
206
210
|
@evaluator.list_gates
|
207
211
|
}, caller: __method__.to_s)
|
208
212
|
end
|
209
213
|
|
210
|
-
sig { returns(T::Array[String]) }
|
211
214
|
def list_configs
|
212
215
|
@err_boundary.capture(task: lambda {
|
213
216
|
@evaluator.list_configs
|
214
217
|
}, caller: __method__.to_s)
|
215
218
|
end
|
216
219
|
|
217
|
-
sig { returns(T::Array[String]) }
|
218
220
|
def list_experiments
|
219
221
|
@err_boundary.capture(task: lambda {
|
220
222
|
@evaluator.list_experiments
|
221
223
|
}, caller: __method__.to_s)
|
222
224
|
end
|
223
225
|
|
224
|
-
sig { returns(T::Array[String]) }
|
225
226
|
def list_autotunes
|
226
227
|
@err_boundary.capture(task: lambda {
|
227
228
|
@evaluator.list_autotunes
|
228
229
|
}, caller: __method__.to_s)
|
229
230
|
end
|
230
231
|
|
231
|
-
sig { returns(T::Array[String]) }
|
232
232
|
def list_layers
|
233
233
|
@err_boundary.capture(task: lambda {
|
234
234
|
@evaluator.list_layers
|
@@ -297,7 +297,6 @@ class StatsigDriver
|
|
297
297
|
return res
|
298
298
|
end
|
299
299
|
|
300
|
-
sig { params(user: StatsigUser, config_name: String, variable_name: String).returns(StatsigUser) }
|
301
300
|
def verify_inputs(user, config_name, variable_name)
|
302
301
|
validate_user(user)
|
303
302
|
if !config_name.is_a?(String) || config_name.empty?
|
@@ -309,19 +308,13 @@ class StatsigDriver
|
|
309
308
|
normalize_user(user)
|
310
309
|
end
|
311
310
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
end
|
320
|
-
def get_config_impl(user, config_name, disable_log_exposure, user_persisted_values: nil)
|
321
|
-
res = @evaluator.get_config(user, config_name, user_persisted_values: user_persisted_values)
|
322
|
-
if res.nil?
|
323
|
-
res = Statsig::ConfigResult.new(config_name)
|
324
|
-
end
|
311
|
+
def get_config_impl(user, config_name, disable_log_exposure, user_persisted_values: nil, disable_evaluation_details: false)
|
312
|
+
res = Statsig::ConfigResult.new(
|
313
|
+
name: config_name,
|
314
|
+
disable_exposures: disable_log_exposure,
|
315
|
+
disable_evaluation_details: disable_evaluation_details
|
316
|
+
)
|
317
|
+
@evaluator.get_config(user, config_name, res, user_persisted_values: user_persisted_values)
|
325
318
|
|
326
319
|
unless disable_log_exposure
|
327
320
|
@logger.log_config_exposure(user, res.name, res.rule_id, res.secondary_exposures, res.evaluation_details)
|
@@ -343,7 +336,7 @@ class StatsigDriver
|
|
343
336
|
end
|
344
337
|
|
345
338
|
def normalize_user(user)
|
346
|
-
if
|
339
|
+
if !@options&.environment.nil?
|
347
340
|
user.statsig_environment = @options.environment
|
348
341
|
end
|
349
342
|
user
|
data/lib/statsig_errors.rb
CHANGED
data/lib/statsig_event.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
|
2
2
|
class StatsigEvent
|
3
3
|
attr_accessor :value, :metadata, :statsig_metadata, :secondary_exposures
|
4
4
|
attr_reader :user
|
@@ -21,13 +21,13 @@ class StatsigEvent
|
|
21
21
|
|
22
22
|
def serialize
|
23
23
|
{
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
:eventName => @event_name,
|
25
|
+
:metadata => @metadata,
|
26
|
+
:value => @value,
|
27
|
+
:user => @user,
|
28
|
+
:time => @time,
|
29
|
+
:statsigMetadata => @statsig_metadata,
|
30
|
+
:secondaryExposures => @secondary_exposures
|
31
31
|
}
|
32
32
|
end
|
33
33
|
end
|