statsig 2.5.4 → 2.6.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/config_result.rb +6 -2
- data/lib/evaluator.rb +77 -3
- data/lib/network.rb +5 -1
- data/lib/spec_store.rb +6 -0
- data/lib/statsig.rb +1 -1
- data/lib/statsig_logger.rb +7 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e43e289ee71055ef26a191a9daf4d54eb4f6a5dbacb8eb6a9160d1f66c07470
|
4
|
+
data.tar.gz: 7c457bd018afe66c60c7ba2d1091b6b0c3054487d50cae69c02ebf640d367acf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80cf6fe68efe3a458f2e9c6637ea6433d7f6ed93110da01fb0c771ea5cd409623b0f721ecc651810e9146d3796b19c23931396407aae64357795dab6424e7d1d
|
7
|
+
data.tar.gz: 496ead0234ed956e4d2077cfea9cd95d755a0f7e036c32c7c9504c727f153a511771465c4a0774b94e4243805c6002056fe96f8434257401770622ff7ae5fe4a
|
data/lib/config_result.rb
CHANGED
@@ -21,6 +21,7 @@ module Statsig
|
|
21
21
|
attr_accessor :forward_all_exposures
|
22
22
|
attr_accessor :sampling_rate
|
23
23
|
attr_accessor :has_seen_analytical_gates
|
24
|
+
attr_accessor :override_config_name
|
24
25
|
|
25
26
|
def initialize(
|
26
27
|
name:,
|
@@ -41,7 +42,8 @@ module Statsig
|
|
41
42
|
include_local_overrides: true,
|
42
43
|
forward_all_exposures: false,
|
43
44
|
sampling_rate: nil,
|
44
|
-
has_seen_analytical_gates: false
|
45
|
+
has_seen_analytical_gates: false,
|
46
|
+
override_config_name: nil
|
45
47
|
)
|
46
48
|
@name = name
|
47
49
|
@gate_value = gate_value
|
@@ -63,6 +65,7 @@ module Statsig
|
|
63
65
|
@forward_all_exposures = forward_all_exposures
|
64
66
|
@sampling_rate = sampling_rate
|
65
67
|
@has_seen_analytical_gates = has_seen_analytical_gates
|
68
|
+
@override_config_name = override_config_name
|
66
69
|
end
|
67
70
|
|
68
71
|
def self.from_user_persisted_values(config_name, user_persisted_values)
|
@@ -82,7 +85,8 @@ module Statsig
|
|
82
85
|
init_time: @init_time,
|
83
86
|
group_name: @group_name,
|
84
87
|
id_type: @id_type,
|
85
|
-
target_app_ids: @target_app_ids
|
88
|
+
target_app_ids: @target_app_ids,
|
89
|
+
override_config_name: @override_config_name
|
86
90
|
}
|
87
91
|
end
|
88
92
|
end
|
data/lib/evaluator.rb
CHANGED
@@ -89,6 +89,50 @@ module Statsig
|
|
89
89
|
nil
|
90
90
|
end
|
91
91
|
|
92
|
+
def try_apply_config_mapping(gate_name, user, end_result, type, salt)
|
93
|
+
gate_name_sym = gate_name.to_sym
|
94
|
+
return false unless @spec_store.overrides.key?(gate_name_sym)
|
95
|
+
|
96
|
+
mapping_list = @spec_store.overrides[gate_name_sym]
|
97
|
+
mapping_list.each do |mapping|
|
98
|
+
rules = mapping[:rules]
|
99
|
+
rules.each do |rule|
|
100
|
+
start_time = rule[:start_time]
|
101
|
+
if !start_time.nil? && start_time > (Time.now.to_i * 1000)
|
102
|
+
next
|
103
|
+
end
|
104
|
+
|
105
|
+
rule_name = rule[:rule_name].to_sym
|
106
|
+
next unless @spec_store.override_rules.key?(rule_name)
|
107
|
+
|
108
|
+
override_rule = @spec_store.override_rules[rule_name]
|
109
|
+
eval_rule(user, override_rule, end_result)
|
110
|
+
unless end_result.gate_value
|
111
|
+
next
|
112
|
+
end
|
113
|
+
|
114
|
+
pass = eval_pass_percent(user, override_rule, salt)
|
115
|
+
unless pass
|
116
|
+
next
|
117
|
+
end
|
118
|
+
|
119
|
+
new_config_name = mapping[:new_config_name]
|
120
|
+
end_result.override_config_name = new_config_name
|
121
|
+
if type == Const::TYPE_FEATURE_GATE
|
122
|
+
check_gate(user, new_config_name, end_result)
|
123
|
+
end
|
124
|
+
if [Const::TYPE_EXPERIMENT, Const::TYPE_DYNAMIC_CONFIG, Const::TYPE_AUTOTUNE].include?(type)
|
125
|
+
get_config(user, new_config_name, end_result)
|
126
|
+
end
|
127
|
+
if type == Const::TYPE_LAYER
|
128
|
+
get_layer(user, new_config_name, end_result)
|
129
|
+
end
|
130
|
+
return true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
false
|
134
|
+
end
|
135
|
+
|
92
136
|
def check_gate(user, gate_name, end_result, ignore_local_overrides: false, is_nested: false)
|
93
137
|
unless ignore_local_overrides
|
94
138
|
local_override = lookup_gate_override(gate_name)
|
@@ -111,11 +155,20 @@ module Statsig
|
|
111
155
|
end
|
112
156
|
|
113
157
|
unless @spec_store.has_gate?(gate_name)
|
158
|
+
if try_apply_config_mapping(gate_name, user, end_result, Const::TYPE_FEATURE_GATE, Const::EMPTY_STR)
|
159
|
+
return
|
160
|
+
end
|
161
|
+
|
114
162
|
unsupported_or_unrecognized(gate_name, end_result)
|
115
163
|
return
|
116
164
|
end
|
117
165
|
|
118
|
-
|
166
|
+
spec = @spec_store.get_gate(gate_name)
|
167
|
+
if try_apply_config_mapping(gate_name, user, end_result, spec[:entity], spec[:salt])
|
168
|
+
return
|
169
|
+
end
|
170
|
+
|
171
|
+
eval_spec(gate_name, user, spec, end_result, is_nested: is_nested)
|
119
172
|
end
|
120
173
|
|
121
174
|
def get_config(user, config_name, end_result, user_persisted_values: nil, ignore_local_overrides: false)
|
@@ -146,12 +199,20 @@ module Statsig
|
|
146
199
|
end
|
147
200
|
|
148
201
|
unless @spec_store.has_config?(config_name)
|
202
|
+
if try_apply_config_mapping(config_name, user, end_result, Const::TYPE_DYNAMIC_CONFIG, Const::EMPTY_STR)
|
203
|
+
return
|
204
|
+
end
|
205
|
+
|
149
206
|
unsupported_or_unrecognized(config_name, end_result)
|
150
207
|
return
|
151
208
|
end
|
152
209
|
|
153
210
|
config = @spec_store.get_config(config_name)
|
154
211
|
|
212
|
+
if try_apply_config_mapping(config_name, user, end_result, config[:entity], config[:salt])
|
213
|
+
return
|
214
|
+
end
|
215
|
+
|
155
216
|
# If persisted values is provided and the experiment is active, return sticky values if exists.
|
156
217
|
if !user_persisted_values.nil? && config[:isActive] == true
|
157
218
|
sticky_values = user_persisted_values[config_name]
|
@@ -231,7 +292,7 @@ module Statsig
|
|
231
292
|
group_size = 10_000.0 / cmab[:groups].length
|
232
293
|
group = cmab[:groups][(hash % 10_000) / group_size]
|
233
294
|
end_result.json_value = group[:parameterValues]
|
234
|
-
end_result.rule_id = group[:id]
|
295
|
+
end_result.rule_id = group[:id] + Const::EXPLORE
|
235
296
|
end_result.group_name = group[:name]
|
236
297
|
end_result.is_experiment_group = true
|
237
298
|
finalize_cmab_eval_result(cmab, end_result, did_pass: true)
|
@@ -338,11 +399,20 @@ module Statsig
|
|
338
399
|
end
|
339
400
|
|
340
401
|
unless @spec_store.has_layer?(layer_name)
|
402
|
+
if try_apply_config_mapping(layer_name, user, end_result, Const::LAYER, Const::EMPTY_STR)
|
403
|
+
return
|
404
|
+
end
|
405
|
+
|
341
406
|
unsupported_or_unrecognized(layer_name, end_result)
|
342
407
|
return
|
343
408
|
end
|
344
409
|
|
345
|
-
|
410
|
+
layer = @spec_store.get_layer(layer_name)
|
411
|
+
if try_apply_config_mapping(layer_name, user, end_result, layer[:entity], layer[:salt])
|
412
|
+
return
|
413
|
+
end
|
414
|
+
|
415
|
+
eval_spec(layer_name, user, layer, end_result)
|
346
416
|
end
|
347
417
|
|
348
418
|
def list_gates
|
@@ -657,6 +727,10 @@ module Statsig
|
|
657
727
|
when Const::CND_PUBLIC
|
658
728
|
return true
|
659
729
|
when Const::CND_PASS_GATE, Const::CND_FAIL_GATE
|
730
|
+
if !target.is_a?(String) || target.empty?
|
731
|
+
return type == Const::CND_FAIL_GATE
|
732
|
+
end
|
733
|
+
|
660
734
|
result = eval_nested_gate(target, user, end_result)
|
661
735
|
if end_result.sampling_rate == nil && !target.start_with?("segment")
|
662
736
|
end_result.has_seen_analytical_gates = true
|
data/lib/network.rb
CHANGED
@@ -53,7 +53,11 @@ module Statsig
|
|
53
53
|
|
54
54
|
def download_config_specs(since_time)
|
55
55
|
url = @options.download_config_specs_url
|
56
|
-
|
56
|
+
dcs_url = "#{url}#{@server_secret}.json"
|
57
|
+
if since_time.positive?
|
58
|
+
dcs_url += "?sinceTime=#{since_time}"
|
59
|
+
end
|
60
|
+
get(dcs_url)
|
57
61
|
end
|
58
62
|
|
59
63
|
def post_logs(events, error_boundary)
|
data/lib/spec_store.rb
CHANGED
@@ -20,6 +20,8 @@ module Statsig
|
|
20
20
|
attr_accessor :hashed_sdk_keys_to_app_ids
|
21
21
|
attr_accessor :unsupported_configs
|
22
22
|
attr_accessor :cmab_configs
|
23
|
+
attr_accessor :overrides
|
24
|
+
attr_accessor :override_rules
|
23
25
|
|
24
26
|
def initialize(network, options, error_callback, diagnostics, error_boundary, logger, secret_key, sdk_config)
|
25
27
|
@init_reason = EvaluationReason::UNINITIALIZED
|
@@ -40,6 +42,8 @@ module Statsig
|
|
40
42
|
@experiment_to_layer = {}
|
41
43
|
@sdk_keys_to_app_ids = {}
|
42
44
|
@hashed_sdk_keys_to_app_ids = {}
|
45
|
+
@overrides = {}
|
46
|
+
@override_rules = {}
|
43
47
|
@diagnostics = diagnostics
|
44
48
|
@error_boundary = error_boundary
|
45
49
|
@logger = logger
|
@@ -361,6 +365,8 @@ module Statsig
|
|
361
365
|
@hashed_sdk_keys_to_app_ids = specs_json[:hashed_sdk_keys_to_app_ids] || {}
|
362
366
|
@sdk_configs.set_flags(specs_json[:sdk_flags])
|
363
367
|
@sdk_configs.set_configs(specs_json[:sdk_configs])
|
368
|
+
@overrides = specs_json[:overrides] || {}
|
369
|
+
@override_rules = specs_json[:override_rules] || {}
|
364
370
|
|
365
371
|
unless from_adapter
|
366
372
|
save_rulesets_to_storage_adapter(specs_string)
|
data/lib/statsig.rb
CHANGED
data/lib/statsig_logger.rb
CHANGED
@@ -65,6 +65,9 @@ module Statsig
|
|
65
65
|
if @debug_info != nil
|
66
66
|
metadata[:debugInfo] = @debug_info
|
67
67
|
end
|
68
|
+
unless result.override_config_name.nil?
|
69
|
+
metadata[:overrideConfigName] = result.override_config_name
|
70
|
+
end
|
68
71
|
return false if not is_unique_exposure(user, $gate_exposure_event, metadata)
|
69
72
|
event.metadata = metadata
|
70
73
|
event.statsig_metadata = {}
|
@@ -93,6 +96,9 @@ module Statsig
|
|
93
96
|
if @debug_info != nil
|
94
97
|
metadata[:debugInfo] = @debug_info
|
95
98
|
end
|
99
|
+
unless result.override_config_name.nil?
|
100
|
+
metadata[:overrideConfigName] = result.override_config_name
|
101
|
+
end
|
96
102
|
return false if not is_unique_exposure(user, $config_exposure_event, metadata)
|
97
103
|
event.metadata = metadata
|
98
104
|
event.secondary_exposures = result.secondary_exposures.is_a?(Array) ? result.secondary_exposures : []
|
@@ -195,7 +201,7 @@ module Statsig
|
|
195
201
|
events_clone = @events
|
196
202
|
@events = []
|
197
203
|
serialized_events = events_clone.map { |e| e.serialize }
|
198
|
-
|
204
|
+
|
199
205
|
serialized_events.each_slice(@options.logging_max_buffer_size) do |batch|
|
200
206
|
@network.post_logs(batch, @error_boundary)
|
201
207
|
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: 2.
|
4
|
+
version: 2.6.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: 2025-
|
11
|
+
date: 2025-10-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -226,14 +226,14 @@ dependencies:
|
|
226
226
|
requirements:
|
227
227
|
- - "~>"
|
228
228
|
- !ruby/object:Gem::Version
|
229
|
-
version: 2.
|
229
|
+
version: 2.18.0
|
230
230
|
type: :runtime
|
231
231
|
prerelease: false
|
232
232
|
version_requirements: !ruby/object:Gem::Requirement
|
233
233
|
requirements:
|
234
234
|
- - "~>"
|
235
235
|
- !ruby/object:Gem::Version
|
236
|
-
version: 2.
|
236
|
+
version: 2.18.0
|
237
237
|
- !ruby/object:Gem::Dependency
|
238
238
|
name: http
|
239
239
|
requirement: !ruby/object:Gem::Requirement
|