statsig 1.18.0 → 1.19.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/statsig.rb +90 -1
- data/lib/statsig_driver.rb +62 -16
- data/lib/statsig_logger.rb +16 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 354a77a658a3232a8695d82136d3e84e5bf0ce2199d06af9fee216eaae7d5dcd
|
4
|
+
data.tar.gz: 3be67ca270e61eedd92fb3aaa96b4f28ff1b79feee3ec4b1a33bdc2d000f8c2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f2461d11144a2e822178d69dad1ff50ebb2a4cd14f7b5dc46704b9c285a56d494f512b8058361f0a3ba3c71d899a6b9afc2fe51618abbe73784c6a937c39125
|
7
|
+
data.tar.gz: 45ac2d3a06f60c1cb0a81b109df9d06e1f479d384023e2009343b6d6f74b5d806fdf86e85b5d09ad8f1e55b07ca8c1b010cb23f7c8de2e9594b1092b323c8708
|
data/lib/statsig.rb
CHANGED
@@ -35,6 +35,28 @@ module Statsig
|
|
35
35
|
@shared_instance&.check_gate(user, gate_name)
|
36
36
|
end
|
37
37
|
|
38
|
+
sig { params(user: StatsigUser, gate_name: String).returns(T::Boolean) }
|
39
|
+
##
|
40
|
+
# Gets the boolean result of a gate, evaluated against the given user.
|
41
|
+
#
|
42
|
+
# @param user A StatsigUser object used for the evaluation
|
43
|
+
# @param gate_name The name of the gate being checked
|
44
|
+
def self.check_gate_with_exposure_logging_disabled(user, gate_name)
|
45
|
+
ensure_initialized
|
46
|
+
@shared_instance&.check_gate(user, gate_name, StatsigDriver::CheckGateOptions.new(log_exposure: false))
|
47
|
+
end
|
48
|
+
|
49
|
+
sig { params(user: StatsigUser, gate_name: String).void }
|
50
|
+
##
|
51
|
+
# Logs an exposure event for the gate
|
52
|
+
#
|
53
|
+
# @param user A StatsigUser object used for the evaluation
|
54
|
+
# @param gate_name The name of the gate being checked
|
55
|
+
def self.manually_log_gate_exposure(user, gate_name)
|
56
|
+
ensure_initialized
|
57
|
+
@shared_instance&.manually_log_gate_exposure(user, gate_name)
|
58
|
+
end
|
59
|
+
|
38
60
|
sig { params(user: StatsigUser, dynamic_config_name: String).returns(DynamicConfig) }
|
39
61
|
##
|
40
62
|
# Get the values of a dynamic config, evaluated against the given user. An exposure event will automatically be logged for the dynamic config.
|
@@ -46,6 +68,28 @@ module Statsig
|
|
46
68
|
@shared_instance&.get_config(user, dynamic_config_name)
|
47
69
|
end
|
48
70
|
|
71
|
+
sig { params(user: StatsigUser, dynamic_config_name: String).returns(DynamicConfig) }
|
72
|
+
##
|
73
|
+
# Get the values of a dynamic config, evaluated against the given user.
|
74
|
+
#
|
75
|
+
# @param user A StatsigUser object used for the evaluation
|
76
|
+
# @param dynamic_config_name The name of the dynamic config
|
77
|
+
def self.get_config_with_exposure_logging_disabled(user, dynamic_config_name)
|
78
|
+
ensure_initialized
|
79
|
+
@shared_instance&.get_config(user, dynamic_config_name, StatsigDriver::GetConfigOptions.new(log_exposure: false))
|
80
|
+
end
|
81
|
+
|
82
|
+
sig { params(user: StatsigUser, dynamic_config: String).void }
|
83
|
+
##
|
84
|
+
# Logs an exposure event for the dynamic config
|
85
|
+
#
|
86
|
+
# @param user A StatsigUser object used for the evaluation
|
87
|
+
# @param dynamic_config_name The name of the dynamic config
|
88
|
+
def self.manually_log_config_exposure(user, dynamic_config)
|
89
|
+
ensure_initialized
|
90
|
+
@shared_instance&.manually_log_config_exposure(user, dynamic_config)
|
91
|
+
end
|
92
|
+
|
49
93
|
sig { params(user: StatsigUser, experiment_name: String).returns(DynamicConfig) }
|
50
94
|
##
|
51
95
|
# Get the values of an experiment, evaluated against the given user. An exposure event will automatically be logged for the experiment.
|
@@ -57,6 +101,28 @@ module Statsig
|
|
57
101
|
@shared_instance&.get_experiment(user, experiment_name)
|
58
102
|
end
|
59
103
|
|
104
|
+
sig { params(user: StatsigUser, experiment_name: String).returns(DynamicConfig) }
|
105
|
+
##
|
106
|
+
# Get the values of an experiment, evaluated against the given user.
|
107
|
+
#
|
108
|
+
# @param user A StatsigUser object used for the evaluation
|
109
|
+
# @param experiment_name The name of the experiment
|
110
|
+
def self.get_experiment_with_exposure_logging_disabled(user, experiment_name)
|
111
|
+
ensure_initialized
|
112
|
+
@shared_instance&.get_experiment(user, experiment_name, StatsigDriver::GetExperimentOptions.new(log_exposure: false))
|
113
|
+
end
|
114
|
+
|
115
|
+
sig { params(user: StatsigUser, experiment_name: String).void }
|
116
|
+
##
|
117
|
+
# Logs an exposure event for the experiment
|
118
|
+
#
|
119
|
+
# @param user A StatsigUser object used for the evaluation
|
120
|
+
# @param experiment_name The name of the experiment
|
121
|
+
def self.manually_log_experiment_exposure(user, experiment_name)
|
122
|
+
ensure_initialized
|
123
|
+
@shared_instance&.manually_log_config_exposure(user, experiment_name)
|
124
|
+
end
|
125
|
+
|
60
126
|
sig { params(user: StatsigUser, layer_name: String).returns(Layer) }
|
61
127
|
##
|
62
128
|
# Get the values of a layer, evaluated against the given user.
|
@@ -69,6 +135,29 @@ module Statsig
|
|
69
135
|
@shared_instance&.get_layer(user, layer_name)
|
70
136
|
end
|
71
137
|
|
138
|
+
sig { params(user: StatsigUser, layer_name: String).returns(Layer) }
|
139
|
+
##
|
140
|
+
# Get the values of a layer, evaluated against the given user.
|
141
|
+
#
|
142
|
+
# @param user A StatsigUser object used for the evaluation
|
143
|
+
# @param layer_name The name of the layer
|
144
|
+
def self.get_layer_with_exposure_logging_disabled(user, layer_name)
|
145
|
+
ensure_initialized
|
146
|
+
@shared_instance&.get_layer(user, layer_name, StatsigDriver::GetLayerOptions.new(log_exposure: false))
|
147
|
+
end
|
148
|
+
|
149
|
+
sig { params(user: StatsigUser, layer_name: String, parameter_name: String).returns(Layer) }
|
150
|
+
##
|
151
|
+
# Logs an exposure event for the parameter in the given layer
|
152
|
+
#
|
153
|
+
# @param user A StatsigUser object used for the evaluation
|
154
|
+
# @param layer_name The name of the layer
|
155
|
+
# @param parameter_name The name of the parameter in the layer
|
156
|
+
def self.manually_log_layer_parameter_exposure(user, layer_name, parameter_name)
|
157
|
+
ensure_initialized
|
158
|
+
@shared_instance&.manually_log_layer_parameter_exposure(user, layer_name, parameter_name)
|
159
|
+
end
|
160
|
+
|
72
161
|
sig { params(user: StatsigUser,
|
73
162
|
event_name: String,
|
74
163
|
value: T.any(String, Integer, Float, NilClass),
|
@@ -136,7 +225,7 @@ module Statsig
|
|
136
225
|
def self.get_statsig_metadata
|
137
226
|
{
|
138
227
|
'sdkType' => 'ruby-server',
|
139
|
-
'sdkVersion' => '1.
|
228
|
+
'sdkVersion' => '1.19.0',
|
140
229
|
}
|
141
230
|
end
|
142
231
|
|
data/lib/statsig_driver.rb
CHANGED
@@ -45,9 +45,13 @@ class StatsigDriver
|
|
45
45
|
})
|
46
46
|
end
|
47
47
|
|
48
|
-
|
48
|
+
class CheckGateOptions < T::Struct
|
49
|
+
prop :log_exposure, T::Boolean, default: true
|
50
|
+
end
|
51
|
+
|
52
|
+
sig { params(user: StatsigUser, gate_name: String, options: CheckGateOptions).returns(T::Boolean) }
|
49
53
|
|
50
|
-
def check_gate(user, gate_name)
|
54
|
+
def check_gate(user, gate_name, options = CheckGateOptions.new)
|
51
55
|
@err_boundary.capture(-> {
|
52
56
|
user = verify_inputs(user, gate_name, "gate_name")
|
53
57
|
|
@@ -60,7 +64,9 @@ class StatsigDriver
|
|
60
64
|
res = check_gate_fallback(user, gate_name)
|
61
65
|
# exposure logged by the server
|
62
66
|
else
|
63
|
-
|
67
|
+
if options.log_exposure
|
68
|
+
@logger.log_gate_exposure(user, res.name, res.gate_value, res.rule_id, res.secondary_exposures, res.evaluation_details)
|
69
|
+
end
|
64
70
|
end
|
65
71
|
|
66
72
|
res.gate_value
|
@@ -68,27 +74,55 @@ class StatsigDriver
|
|
68
74
|
|
69
75
|
end
|
70
76
|
|
71
|
-
sig { params(user: StatsigUser,
|
77
|
+
sig { params(user: StatsigUser, gate_name: String).void }
|
72
78
|
|
73
|
-
def
|
79
|
+
def manually_log_gate_exposure(user, gate_name)
|
80
|
+
res = @evaluator.check_gate(user, gate_name)
|
81
|
+
context = {'is_manual_exposure' => true}
|
82
|
+
@logger.log_gate_exposure(user, gate_name, res.gate_value, res.rule_id, res.secondary_exposures, res.evaluation_details, context)
|
83
|
+
end
|
84
|
+
|
85
|
+
class GetConfigOptions < T::Struct
|
86
|
+
prop :log_exposure, T::Boolean, default: true
|
87
|
+
end
|
88
|
+
|
89
|
+
sig { params(user: StatsigUser, dynamic_config_name: String, options: GetConfigOptions).returns(DynamicConfig) }
|
90
|
+
|
91
|
+
def get_config(user, dynamic_config_name, options = GetConfigOptions.new)
|
74
92
|
@err_boundary.capture(-> {
|
75
93
|
user = verify_inputs(user, dynamic_config_name, "dynamic_config_name")
|
76
|
-
get_config_impl(user, dynamic_config_name)
|
94
|
+
get_config_impl(user, dynamic_config_name, options)
|
77
95
|
}, -> { DynamicConfig.new(dynamic_config_name) })
|
78
96
|
end
|
79
97
|
|
80
|
-
|
98
|
+
class GetExperimentOptions < T::Struct
|
99
|
+
prop :log_exposure, T::Boolean, default: true
|
100
|
+
end
|
81
101
|
|
82
|
-
|
102
|
+
sig { params(user: StatsigUser, experiment_name: String, options: GetExperimentOptions).returns(DynamicConfig) }
|
103
|
+
|
104
|
+
def get_experiment(user, experiment_name, options = GetExperimentOptions.new)
|
83
105
|
@err_boundary.capture(-> {
|
84
106
|
user = verify_inputs(user, experiment_name, "experiment_name")
|
85
|
-
get_config_impl(user, experiment_name)
|
107
|
+
get_config_impl(user, experiment_name, options)
|
86
108
|
}, -> { DynamicConfig.new(experiment_name) })
|
87
109
|
end
|
88
110
|
|
89
|
-
sig { params(user: StatsigUser,
|
111
|
+
sig { params(user: StatsigUser, config_name: String).void }
|
90
112
|
|
91
|
-
def
|
113
|
+
def manually_log_config_exposure(user, config_name)
|
114
|
+
res = @evaluator.get_config(user, config_name)
|
115
|
+
context = {'is_manual_exposure' => true}
|
116
|
+
@logger.log_config_exposure(user, res.name, res.rule_id, res.secondary_exposures, res.evaluation_details, context)
|
117
|
+
end
|
118
|
+
|
119
|
+
class GetLayerOptions < T::Struct
|
120
|
+
prop :log_exposure, T::Boolean, default: true
|
121
|
+
end
|
122
|
+
|
123
|
+
sig { params(user: StatsigUser, layer_name: String, options: GetLayerOptions).returns(Layer) }
|
124
|
+
|
125
|
+
def get_layer(user, layer_name, options = GetLayerOptions.new)
|
92
126
|
@err_boundary.capture(-> {
|
93
127
|
user = verify_inputs(user, layer_name, "layer_name")
|
94
128
|
|
@@ -104,15 +138,25 @@ class StatsigDriver
|
|
104
138
|
res = get_config_fallback(user, res.config_delegate)
|
105
139
|
# exposure logged by the server
|
106
140
|
end
|
107
|
-
|
108
|
-
|
141
|
+
|
142
|
+
exposure_log_func = options.log_exposure ? lambda { |layer, parameter_name|
|
109
143
|
@logger.log_layer_exposure(user, layer, parameter_name, res)
|
110
|
-
}
|
144
|
+
} : nil
|
145
|
+
Layer.new(res.name, res.json_value, res.rule_id, exposure_log_func)
|
111
146
|
}, -> {
|
112
147
|
Layer.new(layer_name)
|
113
148
|
})
|
114
149
|
end
|
115
150
|
|
151
|
+
sig { params(user: StatsigUser, layer_name: String, parameter_name: String).void }
|
152
|
+
|
153
|
+
def manually_log_layer_parameter_exposure(user, layer_name, parameter_name)
|
154
|
+
res = @evaluator.get_layer(user, layer_name)
|
155
|
+
layer = Layer.new(layer_name, res.json_value, res.rule_id)
|
156
|
+
context = {'is_manual_exposure' => true}
|
157
|
+
@logger.log_layer_exposure(user, layer, parameter_name, res, context)
|
158
|
+
end
|
159
|
+
|
116
160
|
def log_event(user, event_name, value = nil, metadata = nil)
|
117
161
|
@err_boundary.capture(-> {
|
118
162
|
if !user.nil? && !user.instance_of?(StatsigUser)
|
@@ -186,7 +230,7 @@ class StatsigDriver
|
|
186
230
|
normalize_user(user)
|
187
231
|
end
|
188
232
|
|
189
|
-
def get_config_impl(user, config_name)
|
233
|
+
def get_config_impl(user, config_name, options)
|
190
234
|
res = @evaluator.get_config(user, config_name)
|
191
235
|
if res.nil?
|
192
236
|
res = Statsig::ConfigResult.new(config_name)
|
@@ -196,7 +240,9 @@ class StatsigDriver
|
|
196
240
|
res = get_config_fallback(user, config_name)
|
197
241
|
# exposure logged by the server
|
198
242
|
else
|
199
|
-
|
243
|
+
if options.log_exposure
|
244
|
+
@logger.log_config_exposure(user, res.name, res.rule_id, res.secondary_exposures, res.evaluation_details)
|
245
|
+
end
|
200
246
|
end
|
201
247
|
|
202
248
|
DynamicConfig.new(res.name, res.json_value, res.rule_id)
|
data/lib/statsig_logger.rb
CHANGED
@@ -32,7 +32,7 @@ module Statsig
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
def log_gate_exposure(user, gate_name, value, rule_id, secondary_exposures, eval_details)
|
35
|
+
def log_gate_exposure(user, gate_name, value, rule_id, secondary_exposures, eval_details, context = nil)
|
36
36
|
event = StatsigEvent.new($gate_exposure_event)
|
37
37
|
event.user = user
|
38
38
|
event.metadata = {
|
@@ -44,10 +44,11 @@ module Statsig
|
|
44
44
|
event.secondary_exposures = secondary_exposures.is_a?(Array) ? secondary_exposures : []
|
45
45
|
|
46
46
|
safe_add_eval_details(eval_details, event)
|
47
|
+
safe_add_exposure_context(context, event)
|
47
48
|
log_event(event)
|
48
49
|
end
|
49
50
|
|
50
|
-
def log_config_exposure(user, config_name, rule_id, secondary_exposures, eval_details)
|
51
|
+
def log_config_exposure(user, config_name, rule_id, secondary_exposures, eval_details, context = nil)
|
51
52
|
event = StatsigEvent.new($config_exposure_event)
|
52
53
|
event.user = user
|
53
54
|
event.metadata = {
|
@@ -58,10 +59,11 @@ module Statsig
|
|
58
59
|
event.secondary_exposures = secondary_exposures.is_a?(Array) ? secondary_exposures : []
|
59
60
|
|
60
61
|
safe_add_eval_details(eval_details, event)
|
62
|
+
safe_add_exposure_context(context, event)
|
61
63
|
log_event(event)
|
62
64
|
end
|
63
65
|
|
64
|
-
def log_layer_exposure(user, layer, parameter_name, config_evaluation)
|
66
|
+
def log_layer_exposure(user, layer, parameter_name, config_evaluation, context = nil)
|
65
67
|
exposures = config_evaluation.undelegated_sec_exps
|
66
68
|
allocated_experiment = ''
|
67
69
|
is_explicit = (config_evaluation.explicit_parameters&.include? parameter_name) || false
|
@@ -83,6 +85,7 @@ module Statsig
|
|
83
85
|
event.secondary_exposures = exposures.is_a?(Array) ? exposures : []
|
84
86
|
|
85
87
|
safe_add_eval_details(config_evaluation.evaluation_details, event)
|
88
|
+
safe_add_exposure_context(context, event)
|
86
89
|
log_event(event)
|
87
90
|
end
|
88
91
|
|
@@ -144,5 +147,15 @@ module Statsig
|
|
144
147
|
event.metadata['initTime'] = eval_details.init_time
|
145
148
|
event.metadata['serverTime'] = eval_details.server_time
|
146
149
|
end
|
150
|
+
|
151
|
+
def safe_add_exposure_context(context, event)
|
152
|
+
if context.nil?
|
153
|
+
return
|
154
|
+
end
|
155
|
+
|
156
|
+
if context['is_manual_exposure']
|
157
|
+
event.metadata['isManualExposure'] = 'true'
|
158
|
+
end
|
159
|
+
end
|
147
160
|
end
|
148
161
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statsig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.19.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Statsig, Inc
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -215,7 +215,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
215
215
|
- !ruby/object:Gem::Version
|
216
216
|
version: '0'
|
217
217
|
requirements: []
|
218
|
-
rubygems_version: 3.3.
|
218
|
+
rubygems_version: 3.3.7
|
219
219
|
signing_key:
|
220
220
|
specification_version: 4
|
221
221
|
summary: Statsig server SDK for Ruby
|