statsig 1.18.0 → 1.19.0

Sign up to get free protection for your applications and to get access to all the features.
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