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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 475c2e56b1f53dbc642adff47dd6a1de3a3c324ce9a0145fcaf7c6ebb2b412c1
4
- data.tar.gz: a37bbef25c2ce1b818fafe25252bcf076964b16acdb484d41ebe2c705b6042b1
3
+ metadata.gz: 354a77a658a3232a8695d82136d3e84e5bf0ce2199d06af9fee216eaae7d5dcd
4
+ data.tar.gz: 3be67ca270e61eedd92fb3aaa96b4f28ff1b79feee3ec4b1a33bdc2d000f8c2e
5
5
  SHA512:
6
- metadata.gz: 32ba1629776babb0f4d437e551a251e5bea38b42b916c067c0009705ef59b71db5989a6942e009994ab5956e10ca61cf7ee4a14f9302312094e2b2cc479568c5
7
- data.tar.gz: d8d6f082a647a6b6ba7d6adf8954c17d845b44b55dfd7b17ce4fff0aa858cbce96d6308e2ec0e0f15209275d5e8520f0b5697d1caf64cdac7e40e0d7dc46b4da
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.18.0',
228
+ 'sdkVersion' => '1.19.0',
140
229
  }
141
230
  end
142
231
 
@@ -45,9 +45,13 @@ class StatsigDriver
45
45
  })
46
46
  end
47
47
 
48
- sig { params(user: StatsigUser, gate_name: String).returns(T::Boolean) }
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
- @logger.log_gate_exposure(user, res.name, res.gate_value, res.rule_id, res.secondary_exposures, res.evaluation_details)
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, dynamic_config_name: String).returns(DynamicConfig) }
77
+ sig { params(user: StatsigUser, gate_name: String).void }
72
78
 
73
- def get_config(user, dynamic_config_name)
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
- sig { params(user: StatsigUser, experiment_name: String).returns(DynamicConfig) }
98
+ class GetExperimentOptions < T::Struct
99
+ prop :log_exposure, T::Boolean, default: true
100
+ end
81
101
 
82
- def get_experiment(user, experiment_name)
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, layer_name: String).returns(Layer) }
111
+ sig { params(user: StatsigUser, config_name: String).void }
90
112
 
91
- def get_layer(user, layer_name)
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
- Layer.new(res.name, res.json_value, res.rule_id, lambda { |layer, parameter_name|
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
- @logger.log_config_exposure(user, res.name, res.rule_id, res.secondary_exposures, res.evaluation_details)
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)
@@ -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.18.0
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-28 00:00:00.000000000 Z
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.11
218
+ rubygems_version: 3.3.7
219
219
  signing_key:
220
220
  specification_version: 4
221
221
  summary: Statsig server SDK for Ruby