statsig 1.31.1 → 1.32.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 +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
|