statsig 1.31.1 → 1.33.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 +99 -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 +386 -330
- 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 +103 -99
- data/lib/statsig_driver.rb +99 -71
- 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 -34
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,23 @@ class StatsigDriver
|
|
47
43
|
}, caller: __method__.to_s)
|
48
44
|
end
|
49
45
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
def get_gate_impl(user, gate_name, disable_log_exposure: false, skip_evaluation: false)
|
46
|
+
def get_gate_impl(
|
47
|
+
user,
|
48
|
+
gate_name,
|
49
|
+
disable_log_exposure: false,
|
50
|
+
skip_evaluation: false,
|
51
|
+
disable_evaluation_details: false,
|
52
|
+
ignore_local_overrides: false
|
53
|
+
)
|
59
54
|
if skip_evaluation
|
60
55
|
gate = @store.get_gate(gate_name)
|
61
56
|
return FeatureGate.new(gate_name) if gate.nil?
|
62
|
-
return FeatureGate.new(gate
|
57
|
+
return FeatureGate.new(gate.name, target_app_ids: gate.target_app_ids)
|
63
58
|
end
|
64
59
|
user = verify_inputs(user, gate_name, 'gate_name')
|
65
60
|
|
66
|
-
res =
|
67
|
-
|
68
|
-
res = Statsig::ConfigResult.new(gate_name)
|
69
|
-
end
|
61
|
+
res = Statsig::ConfigResult.new(name: gate_name, disable_exposures: disable_log_exposure, disable_evaluation_details: disable_evaluation_details)
|
62
|
+
@evaluator.check_gate(user, gate_name, res, ignore_local_overrides: ignore_local_overrides)
|
70
63
|
|
71
64
|
unless disable_log_exposure
|
72
65
|
@logger.log_gate_exposure(
|
@@ -76,63 +69,82 @@ class StatsigDriver
|
|
76
69
|
FeatureGate.from_config_result(res)
|
77
70
|
end
|
78
71
|
|
79
|
-
|
80
|
-
def get_gate(user, gate_name, options = Statsig::GetGateOptions.new)
|
72
|
+
def get_gate(user, gate_name, options = nil)
|
81
73
|
@err_boundary.capture(task: lambda {
|
82
74
|
run_with_diagnostics(task: lambda {
|
83
|
-
get_gate_impl(user, gate_name,
|
75
|
+
get_gate_impl(user, gate_name,
|
76
|
+
disable_log_exposure: options&.disable_log_exposure == true,
|
77
|
+
skip_evaluation: options&.skip_evaluation == true,
|
78
|
+
disable_evaluation_details: options&.disable_evaluation_details == true
|
79
|
+
)
|
84
80
|
}, caller: __method__.to_s)
|
85
81
|
}, recover: -> { false }, caller: __method__.to_s)
|
86
82
|
end
|
87
83
|
|
88
|
-
|
89
|
-
def check_gate(user, gate_name, options = Statsig::CheckGateOptions.new)
|
84
|
+
def check_gate(user, gate_name, options = nil)
|
90
85
|
@err_boundary.capture(task: lambda {
|
91
86
|
run_with_diagnostics(task: lambda {
|
92
|
-
get_gate_impl(
|
87
|
+
get_gate_impl(
|
88
|
+
user,
|
89
|
+
gate_name,
|
90
|
+
disable_log_exposure: options&.disable_log_exposure == true,
|
91
|
+
disable_evaluation_details: options&.disable_evaluation_details == true,
|
92
|
+
ignore_local_overrides: options&.ignore_local_overrides == true
|
93
|
+
).value
|
93
94
|
}, caller: __method__.to_s)
|
94
95
|
}, recover: -> { false }, caller: __method__.to_s)
|
95
96
|
end
|
96
97
|
|
97
|
-
sig { params(user: StatsigUser, gate_name: String).void }
|
98
98
|
def manually_log_gate_exposure(user, gate_name)
|
99
99
|
@err_boundary.capture(task: lambda {
|
100
|
-
res =
|
101
|
-
|
100
|
+
res = Statsig::ConfigResult.new(name: gate_name)
|
101
|
+
@evaluator.check_gate(user, gate_name, res)
|
102
|
+
context = { :is_manual_exposure => true }
|
102
103
|
@logger.log_gate_exposure(user, gate_name, res.gate_value, res.rule_id, res.secondary_exposures, res.evaluation_details, context)
|
103
104
|
})
|
104
105
|
end
|
105
106
|
|
106
|
-
|
107
|
-
def get_config(user, dynamic_config_name, options = Statsig::GetConfigOptions.new)
|
107
|
+
def get_config(user, dynamic_config_name, options = nil)
|
108
108
|
@err_boundary.capture(task: lambda {
|
109
109
|
run_with_diagnostics(task: lambda {
|
110
110
|
user = verify_inputs(user, dynamic_config_name, "dynamic_config_name")
|
111
|
-
get_config_impl(
|
111
|
+
get_config_impl(
|
112
|
+
user,
|
113
|
+
dynamic_config_name,
|
114
|
+
options&.disable_log_exposure == true,
|
115
|
+
disable_evaluation_details: options&.disable_evaluation_details == true,
|
116
|
+
ignore_local_overrides: options&.ignore_local_overrides == true
|
117
|
+
)
|
112
118
|
}, caller: __method__.to_s)
|
113
119
|
}, recover: -> { DynamicConfig.new(dynamic_config_name) }, caller: __method__.to_s)
|
114
120
|
end
|
115
121
|
|
116
|
-
|
117
|
-
def get_experiment(user, experiment_name, options = Statsig::GetExperimentOptions.new)
|
122
|
+
def get_experiment(user, experiment_name, options = nil)
|
118
123
|
@err_boundary.capture(task: lambda {
|
119
124
|
run_with_diagnostics(task: lambda {
|
120
125
|
user = verify_inputs(user, experiment_name, "experiment_name")
|
121
|
-
get_config_impl(
|
126
|
+
get_config_impl(
|
127
|
+
user,
|
128
|
+
experiment_name,
|
129
|
+
options&.disable_log_exposure == true,
|
130
|
+
user_persisted_values: options&.user_persisted_values,
|
131
|
+
disable_evaluation_details: options&.disable_evaluation_details == true,
|
132
|
+
ignore_local_overrides: options&.ignore_local_overrides == true
|
133
|
+
)
|
122
134
|
}, caller: __method__.to_s)
|
123
135
|
}, recover: -> { DynamicConfig.new(experiment_name) }, caller: __method__.to_s)
|
124
136
|
end
|
125
137
|
|
126
|
-
sig { params(user: StatsigUser, config_name: String).void }
|
127
138
|
def manually_log_config_exposure(user, config_name)
|
128
139
|
@err_boundary.capture(task: lambda {
|
129
|
-
res =
|
130
|
-
|
140
|
+
res = Statsig::ConfigResult.new(name: config_name)
|
141
|
+
@evaluator.get_config(user, config_name, res)
|
142
|
+
|
143
|
+
context = { :is_manual_exposure => true }
|
131
144
|
@logger.log_config_exposure(user, res.name, res.rule_id, res.secondary_exposures, res.evaluation_details, context)
|
132
145
|
}, caller: __method__.to_s)
|
133
146
|
end
|
134
147
|
|
135
|
-
sig { params(user: StatsigUser, id_type: String).returns(Statsig::UserPersistedValues) }
|
136
148
|
def get_user_persisted_values(user, id_type)
|
137
149
|
@err_boundary.capture(task: lambda {
|
138
150
|
persisted_values = @persistent_storage_utils.get_user_persisted_values(user, id_type)
|
@@ -142,31 +154,34 @@ class StatsigDriver
|
|
142
154
|
}, caller: __method__.to_s)
|
143
155
|
end
|
144
156
|
|
145
|
-
|
146
|
-
def get_layer(user, layer_name, options = Statsig::GetLayerOptions.new)
|
157
|
+
def get_layer(user, layer_name, options = nil)
|
147
158
|
@err_boundary.capture(task: lambda {
|
148
159
|
run_with_diagnostics(task: lambda {
|
149
160
|
user = verify_inputs(user, layer_name, "layer_name")
|
150
|
-
|
151
|
-
res =
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
161
|
+
exposures_disabled = options&.disable_log_exposure == true
|
162
|
+
res = Statsig::ConfigResult.new(
|
163
|
+
name: layer_name,
|
164
|
+
disable_exposures: exposures_disabled,
|
165
|
+
disable_evaluation_details: options&.disable_evaluation_details == true
|
166
|
+
)
|
167
|
+
@evaluator.get_layer(user, layer_name, res)
|
168
|
+
|
169
|
+
exposure_log_func = !exposures_disabled ? lambda { |layer, parameter_name|
|
157
170
|
@logger.log_layer_exposure(user, layer, parameter_name, res)
|
158
171
|
} : nil
|
172
|
+
|
159
173
|
Layer.new(res.name, res.json_value, res.rule_id, res.group_name, res.config_delegate, exposure_log_func)
|
160
174
|
}, caller: __method__.to_s)
|
161
175
|
}, recover: lambda { Layer.new(layer_name) }, caller: __method__.to_s)
|
162
176
|
end
|
163
177
|
|
164
|
-
sig { params(user: StatsigUser, layer_name: String, parameter_name: String).void }
|
165
178
|
def manually_log_layer_parameter_exposure(user, layer_name, parameter_name)
|
166
179
|
@err_boundary.capture(task: lambda {
|
167
|
-
res =
|
180
|
+
res = Statsig::ConfigResult.new(name: layer_name)
|
181
|
+
@evaluator.get_layer(user, layer_name, res)
|
182
|
+
|
168
183
|
layer = Layer.new(layer_name, res.json_value, res.rule_id, res.group_name, res.config_delegate)
|
169
|
-
context = {
|
184
|
+
context = { :is_manual_exposure => true }
|
170
185
|
@logger.log_layer_exposure(user, layer, parameter_name, res, context)
|
171
186
|
}, caller: __method__.to_s)
|
172
187
|
end
|
@@ -200,35 +215,30 @@ class StatsigDriver
|
|
200
215
|
}, caller: __method__.to_s)
|
201
216
|
end
|
202
217
|
|
203
|
-
sig { returns(T::Array[String]) }
|
204
218
|
def list_gates
|
205
219
|
@err_boundary.capture(task: lambda {
|
206
220
|
@evaluator.list_gates
|
207
221
|
}, caller: __method__.to_s)
|
208
222
|
end
|
209
223
|
|
210
|
-
sig { returns(T::Array[String]) }
|
211
224
|
def list_configs
|
212
225
|
@err_boundary.capture(task: lambda {
|
213
226
|
@evaluator.list_configs
|
214
227
|
}, caller: __method__.to_s)
|
215
228
|
end
|
216
229
|
|
217
|
-
sig { returns(T::Array[String]) }
|
218
230
|
def list_experiments
|
219
231
|
@err_boundary.capture(task: lambda {
|
220
232
|
@evaluator.list_experiments
|
221
233
|
}, caller: __method__.to_s)
|
222
234
|
end
|
223
235
|
|
224
|
-
sig { returns(T::Array[String]) }
|
225
236
|
def list_autotunes
|
226
237
|
@err_boundary.capture(task: lambda {
|
227
238
|
@evaluator.list_autotunes
|
228
239
|
}, caller: __method__.to_s)
|
229
240
|
end
|
230
241
|
|
231
|
-
sig { returns(T::Array[String]) }
|
232
242
|
def list_layers
|
233
243
|
@err_boundary.capture(task: lambda {
|
234
244
|
@evaluator.list_layers
|
@@ -249,20 +259,45 @@ class StatsigDriver
|
|
249
259
|
}, caller: __method__.to_s)
|
250
260
|
end
|
251
261
|
|
262
|
+
def remove_gate_override(gate_name)
|
263
|
+
@err_boundary.capture(task: lambda {
|
264
|
+
@evaluator.remove_gate_override(gate_name)
|
265
|
+
}, caller: __method__.to_s)
|
266
|
+
end
|
267
|
+
|
268
|
+
def clear_gate_overrides
|
269
|
+
@err_boundary.capture(task: lambda {
|
270
|
+
@evaluator.clear_gate_overrides
|
271
|
+
}, caller: __method__.to_s)
|
272
|
+
end
|
273
|
+
|
252
274
|
def override_config(config_name, config_value)
|
253
275
|
@err_boundary.capture(task: lambda {
|
254
276
|
@evaluator.override_config(config_name, config_value)
|
255
277
|
}, caller: __method__.to_s)
|
256
278
|
end
|
257
279
|
|
280
|
+
def remove_config_override(config_name)
|
281
|
+
@err_boundary.capture(task: lambda {
|
282
|
+
@evaluator.remove_config_override(config_name)
|
283
|
+
}, caller: __method__.to_s)
|
284
|
+
end
|
285
|
+
|
286
|
+
def clear_config_overrides
|
287
|
+
@err_boundary.capture(task: lambda {
|
288
|
+
@evaluator.clear_config_overrides
|
289
|
+
}, caller: __method__.to_s)
|
290
|
+
end
|
291
|
+
|
258
292
|
# @param [StatsigUser] user
|
259
293
|
# @param [String | nil] client_sdk_key
|
294
|
+
# @param [Boolean] include_local_overrides
|
260
295
|
# @return [Hash]
|
261
|
-
def get_client_initialize_response(user, hash, client_sdk_key)
|
296
|
+
def get_client_initialize_response(user, hash, client_sdk_key, include_local_overrides)
|
262
297
|
@err_boundary.capture(task: lambda {
|
263
298
|
validate_user(user)
|
264
299
|
normalize_user(user)
|
265
|
-
@evaluator.get_client_initialize_response(user, hash, client_sdk_key)
|
300
|
+
@evaluator.get_client_initialize_response(user, hash, client_sdk_key, include_local_overrides)
|
266
301
|
}, recover: -> { nil }, caller: __method__.to_s)
|
267
302
|
end
|
268
303
|
|
@@ -297,7 +332,6 @@ class StatsigDriver
|
|
297
332
|
return res
|
298
333
|
end
|
299
334
|
|
300
|
-
sig { params(user: StatsigUser, config_name: String, variable_name: String).returns(StatsigUser) }
|
301
335
|
def verify_inputs(user, config_name, variable_name)
|
302
336
|
validate_user(user)
|
303
337
|
if !config_name.is_a?(String) || config_name.empty?
|
@@ -309,19 +343,13 @@ class StatsigDriver
|
|
309
343
|
normalize_user(user)
|
310
344
|
end
|
311
345
|
|
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
|
346
|
+
def get_config_impl(user, config_name, disable_log_exposure, user_persisted_values: nil, disable_evaluation_details: false, ignore_local_overrides: false)
|
347
|
+
res = Statsig::ConfigResult.new(
|
348
|
+
name: config_name,
|
349
|
+
disable_exposures: disable_log_exposure,
|
350
|
+
disable_evaluation_details: disable_evaluation_details
|
351
|
+
)
|
352
|
+
@evaluator.get_config(user, config_name, res, user_persisted_values: user_persisted_values, ignore_local_overrides: ignore_local_overrides)
|
325
353
|
|
326
354
|
unless disable_log_exposure
|
327
355
|
@logger.log_config_exposure(user, res.name, res.rule_id, res.secondary_exposures, res.evaluation_details)
|
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
|
data/lib/statsig_logger.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'constants'
|
2
2
|
require 'statsig_event'
|
3
3
|
require 'concurrent-ruby'
|
4
4
|
|
@@ -6,7 +6,7 @@ $gate_exposure_event = 'statsig::gate_exposure'
|
|
6
6
|
$config_exposure_event = 'statsig::config_exposure'
|
7
7
|
$layer_exposure_event = 'statsig::layer_exposure'
|
8
8
|
$diagnostics_event = 'statsig::diagnostics'
|
9
|
-
$ignored_metadata_keys = [
|
9
|
+
$ignored_metadata_keys = [:serverTime, :configSyncTime, :initTime, :reason]
|
10
10
|
module Statsig
|
11
11
|
class StatsigLogger
|
12
12
|
def initialize(network, options, error_boundary)
|
@@ -41,9 +41,9 @@ module Statsig
|
|
41
41
|
event = StatsigEvent.new($gate_exposure_event)
|
42
42
|
event.user = user
|
43
43
|
metadata = {
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
gate: gate_name,
|
45
|
+
gateValue: value.to_s,
|
46
|
+
ruleID: rule_id || Statsig::Const::EMPTY_STR,
|
47
47
|
}
|
48
48
|
return false if not is_unique_exposure(user, $gate_exposure_event, metadata)
|
49
49
|
event.metadata = metadata
|
@@ -59,8 +59,8 @@ module Statsig
|
|
59
59
|
event = StatsigEvent.new($config_exposure_event)
|
60
60
|
event.user = user
|
61
61
|
metadata = {
|
62
|
-
|
63
|
-
|
62
|
+
config: config_name,
|
63
|
+
ruleID: rule_id || Statsig::Const::EMPTY_STR,
|
64
64
|
}
|
65
65
|
return false if not is_unique_exposure(user, $config_exposure_event, metadata)
|
66
66
|
event.metadata = metadata
|
@@ -72,8 +72,8 @@ module Statsig
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def log_layer_exposure(user, layer, parameter_name, config_evaluation, context = nil)
|
75
|
-
exposures = config_evaluation.undelegated_sec_exps
|
76
|
-
allocated_experiment =
|
75
|
+
exposures = config_evaluation.undelegated_sec_exps || []
|
76
|
+
allocated_experiment = Statsig::Const::EMPTY_STR
|
77
77
|
is_explicit = (config_evaluation.explicit_parameters&.include? parameter_name) || false
|
78
78
|
if is_explicit
|
79
79
|
allocated_experiment = config_evaluation.config_delegate
|
@@ -83,13 +83,13 @@ module Statsig
|
|
83
83
|
event = StatsigEvent.new($layer_exposure_event)
|
84
84
|
event.user = user
|
85
85
|
metadata = {
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
86
|
+
config: layer.name,
|
87
|
+
ruleID: layer.rule_id || Statsig::Const::EMPTY_STR,
|
88
|
+
allocatedExperiment: allocated_experiment,
|
89
|
+
parameterName: parameter_name,
|
90
|
+
isExplicitParameter: String(is_explicit)
|
91
91
|
}
|
92
|
-
return false
|
92
|
+
return false unless is_unique_exposure(user, $layer_exposure_event, metadata)
|
93
93
|
event.metadata = metadata
|
94
94
|
event.secondary_exposures = exposures.is_a?(Array) ? exposures : []
|
95
95
|
|
@@ -167,10 +167,10 @@ module Statsig
|
|
167
167
|
return
|
168
168
|
end
|
169
169
|
|
170
|
-
event.metadata[
|
171
|
-
event.metadata[
|
172
|
-
event.metadata[
|
173
|
-
event.metadata[
|
170
|
+
event.metadata[:reason] = eval_details.reason
|
171
|
+
event.metadata[:configSyncTime] = eval_details.config_sync_time
|
172
|
+
event.metadata[:initTime] = eval_details.init_time
|
173
|
+
event.metadata[:serverTime] = eval_details.server_time
|
174
174
|
end
|
175
175
|
|
176
176
|
def safe_add_exposure_context(context, event)
|
@@ -178,8 +178,8 @@ module Statsig
|
|
178
178
|
return
|
179
179
|
end
|
180
180
|
|
181
|
-
if context[
|
182
|
-
event.metadata[
|
181
|
+
if context[:is_manual_exposure]
|
182
|
+
event.metadata[:isManualExposure] = 'true'
|
183
183
|
end
|
184
184
|
end
|
185
185
|
|
data/lib/statsig_options.rb
CHANGED
@@ -1,142 +1,92 @@
|
|
1
|
-
# typed: true
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
1
|
require_relative 'interfaces/data_store'
|
5
2
|
require_relative 'interfaces/user_persistent_storage'
|
6
3
|
|
7
4
|
##
|
8
5
|
# Configuration options for the Statsig SDK.
|
9
6
|
class StatsigOptions
|
10
|
-
extend T::Sig
|
11
7
|
|
12
|
-
sig { returns(T.any(T::Hash[String, String], NilClass)) }
|
13
8
|
# Hash you can use to set environment variables that apply to all of your users in
|
14
9
|
# the same session and will be used for targeting purposes.
|
15
10
|
# eg. { "tier" => "development" }
|
16
11
|
attr_accessor :environment
|
17
12
|
|
18
|
-
sig { returns(String) }
|
19
13
|
# The base url used to make network calls to Statsig.
|
20
14
|
# default: https://statsigapi.net/v1
|
21
15
|
attr_accessor :api_url_base
|
22
16
|
|
23
17
|
# The base url used specifically to call download_config_specs.
|
24
18
|
# Takes precedence over api_url_base
|
25
|
-
sig { returns(String) }
|
26
19
|
attr_accessor :api_url_download_config_specs
|
27
20
|
|
28
|
-
sig { returns(T.any(Float, Integer)) }
|
29
21
|
# The interval (in seconds) to poll for changes to your Statsig configuration
|
30
22
|
# default: 10s
|
31
23
|
attr_accessor :rulesets_sync_interval
|
32
24
|
|
33
|
-
sig { returns(T.any(Float, Integer)) }
|
34
25
|
# The interval (in seconds) to poll for changes to your id lists
|
35
26
|
# default: 60s
|
36
27
|
attr_accessor :idlists_sync_interval
|
37
28
|
|
38
29
|
# Disable background syncing for rulesets
|
39
|
-
sig { returns(T::Boolean) }
|
40
30
|
attr_accessor :disable_rulesets_sync
|
41
31
|
|
42
32
|
# Disable background syncing for id lists
|
43
|
-
sig { returns(T::Boolean) }
|
44
33
|
attr_accessor :disable_idlists_sync
|
45
34
|
|
46
|
-
sig { returns(T.any(Float, Integer)) }
|
47
35
|
# How often to flush logs to Statsig
|
48
36
|
# default: 60s
|
49
37
|
attr_accessor :logging_interval_seconds
|
50
38
|
|
51
|
-
sig { returns(Integer) }
|
52
39
|
# The maximum number of events to batch before flushing logs to the server
|
53
40
|
# default: 1000
|
54
41
|
attr_accessor :logging_max_buffer_size
|
55
42
|
|
56
|
-
sig { returns(T::Boolean) }
|
57
43
|
# Restricts the SDK to not issue any network requests and only respond with default values (or local overrides)
|
58
44
|
# default: false
|
59
45
|
attr_accessor :local_mode
|
60
46
|
|
61
|
-
sig { returns(T.any(String, NilClass)) }
|
62
47
|
# A string that represents all rules for all feature gates, dynamic configs and experiments.
|
63
48
|
# It can be provided to bootstrap the Statsig server SDK at initialization in case your server runs
|
64
49
|
# into network issue or Statsig is down temporarily.
|
65
50
|
attr_accessor :bootstrap_values
|
66
51
|
|
67
|
-
sig { returns(T.any(Method, Proc, NilClass)) }
|
68
52
|
# A callback function that will be called anytime the rulesets are updated.
|
69
53
|
attr_accessor :rules_updated_callback
|
70
54
|
|
71
|
-
sig { returns(T.any(Statsig::Interfaces::IDataStore, NilClass)) }
|
72
55
|
# A class that extends IDataStore. Can be used to provide values from a
|
73
56
|
# common data store (like Redis) to initialize the Statsig SDK.
|
74
57
|
attr_accessor :data_store
|
75
58
|
|
76
|
-
sig { returns(Integer) }
|
77
59
|
# The number of threads allocated to syncing IDLists.
|
78
60
|
# default: 3
|
79
61
|
attr_accessor :idlist_threadpool_size
|
80
62
|
|
81
|
-
sig { returns(Integer) }
|
82
63
|
# The number of threads allocated to posting event logs.
|
83
64
|
# default: 3
|
84
65
|
attr_accessor :logger_threadpool_size
|
85
66
|
|
86
|
-
sig { returns(T::Boolean) }
|
87
67
|
# Should diagnostics be logged. These include performance metrics for initialize.
|
88
68
|
# default: false
|
89
69
|
attr_accessor :disable_diagnostics_logging
|
90
70
|
|
91
|
-
sig { returns(T::Boolean) }
|
92
71
|
# Statsig utilizes Sorbet (https://sorbet.org) to ensure type safety of the SDK. This includes logging
|
93
72
|
# to console when errors are detected. You can disable this logging by setting this flag to true.
|
94
73
|
# default: false
|
95
74
|
attr_accessor :disable_sorbet_logging_handlers
|
96
75
|
|
97
|
-
sig { returns(T.any(Integer, NilClass)) }
|
98
76
|
# Number of seconds before a network call is timed out
|
99
77
|
attr_accessor :network_timeout
|
100
78
|
|
101
|
-
sig { returns(Integer) }
|
102
79
|
# Number of times to retry sending a batch of failed log events
|
103
80
|
attr_accessor :post_logs_retry_limit
|
104
81
|
|
105
|
-
sig { returns(T.any(Method, Proc, Integer, NilClass)) }
|
106
82
|
# The number of seconds, or a function that returns the number of seconds based on the number of retries remaining
|
107
83
|
# which overrides the default backoff time between retries
|
108
84
|
attr_accessor :post_logs_retry_backoff
|
109
85
|
|
110
|
-
sig { returns(T.any(Statsig::Interfaces::IUserPersistentStorage, NilClass)) }
|
111
86
|
# A storage adapter for persisted values. Can be used for sticky bucketing users in experiments.
|
112
87
|
# Implements Statsig::Interfaces::IUserPersistentStorage.
|
113
88
|
attr_accessor :user_persistent_storage
|
114
89
|
|
115
|
-
sig do
|
116
|
-
params(
|
117
|
-
environment: T.any(T::Hash[String, String], NilClass),
|
118
|
-
api_url_base: T.nilable(String),
|
119
|
-
api_url_download_config_specs: T.any(String, NilClass),
|
120
|
-
rulesets_sync_interval: T.any(Float, Integer),
|
121
|
-
idlists_sync_interval: T.any(Float, Integer),
|
122
|
-
disable_rulesets_sync: T::Boolean,
|
123
|
-
disable_idlists_sync: T::Boolean,
|
124
|
-
logging_interval_seconds: T.any(Float, Integer),
|
125
|
-
logging_max_buffer_size: Integer,
|
126
|
-
local_mode: T::Boolean,
|
127
|
-
bootstrap_values: T.any(String, NilClass),
|
128
|
-
rules_updated_callback: T.any(Method, Proc, NilClass),
|
129
|
-
data_store: T.any(Statsig::Interfaces::IDataStore, NilClass),
|
130
|
-
idlist_threadpool_size: Integer,
|
131
|
-
logger_threadpool_size: Integer,
|
132
|
-
disable_diagnostics_logging: T::Boolean,
|
133
|
-
disable_sorbet_logging_handlers: T::Boolean,
|
134
|
-
network_timeout: T.any(Integer, NilClass),
|
135
|
-
post_logs_retry_limit: Integer,
|
136
|
-
post_logs_retry_backoff: T.any(Method, Proc, Integer, NilClass),
|
137
|
-
user_persistent_storage: T.any(Statsig::Interfaces::IUserPersistentStorage, NilClass)
|
138
|
-
).void
|
139
|
-
end
|
140
90
|
def initialize(
|
141
91
|
environment = nil,
|
142
92
|
api_url_base = nil,
|