statsig 2.5.5 → 2.8.3
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/api_config.rb +1 -1
- data/lib/client_initialize_helpers.rb +1 -2
- data/lib/config_result.rb +6 -2
- data/lib/error_boundary.rb +1 -1
- data/lib/evaluator.rb +92 -14
- data/lib/hash_utils.rb +1 -1
- data/lib/network.rb +10 -3
- data/lib/spec_store.rb +11 -5
- data/lib/statsig.rb +28 -4
- data/lib/statsig_driver.rb +50 -16
- data/lib/statsig_logger.rb +11 -5
- data/lib/statsig_user.rb +1 -1
- data/lib/user_persistent_storage_utils.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a17857d17823d2f8d7f6a13d01c4f3d117e4187233d377441c4e7be7a6499ef1
|
|
4
|
+
data.tar.gz: 34bb6a509d1fca2ab2973edf7ce0f76814440c5197649a68af8c573130ef13d5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: eef23c96fefa5aff93eec2ce8562a45ccb59434bfb68d264f39b50df987689c402286895103295b701ba6f71db970f43bd8832f608a2da0622a5bde1717d9521
|
|
7
|
+
data.tar.gz: 7df3f01db686cf387e30b7d45be967be4d9376340d64506359c0df6a0a9b169f45ef310a7b727b34f87cb9c4ddb97f7ba0a80daf7e79d8102f256f83f32369cd
|
data/lib/api_config.rb
CHANGED
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/error_boundary.rb
CHANGED
data/lib/evaluator.rb
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
require 'config_result'
|
|
2
1
|
require 'country_lookup'
|
|
3
2
|
require 'digest'
|
|
4
|
-
require 'evaluation_helpers'
|
|
5
|
-
require 'client_initialize_helpers'
|
|
6
|
-
require 'spec_store'
|
|
7
3
|
require 'time'
|
|
8
|
-
require 'ua_parser'
|
|
9
|
-
require 'evaluation_details'
|
|
10
4
|
require 'user_agent_parser/operating_system'
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
require_relative 'client_initialize_helpers'
|
|
6
|
+
require_relative 'config_result'
|
|
7
|
+
require_relative 'constants'
|
|
8
|
+
require_relative 'evaluation_details'
|
|
9
|
+
require_relative 'evaluation_helpers'
|
|
10
|
+
require_relative 'spec_store'
|
|
11
|
+
require_relative 'ua_parser'
|
|
12
|
+
require_relative 'user_persistent_storage_utils'
|
|
13
13
|
|
|
14
14
|
module Statsig
|
|
15
15
|
class Evaluator
|
|
@@ -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]
|
|
@@ -317,7 +378,7 @@ module Statsig
|
|
|
317
378
|
unless config.nil?
|
|
318
379
|
cur_count += config[:records]
|
|
319
380
|
end
|
|
320
|
-
sum += 1.0 /
|
|
381
|
+
sum += 1.0 / cur_count / total_records
|
|
321
382
|
next unless value < sum
|
|
322
383
|
|
|
323
384
|
end_result.json_value = group[:parameterValues]
|
|
@@ -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
|
|
@@ -479,7 +549,7 @@ module Statsig
|
|
|
479
549
|
value: rule[:returnValue],
|
|
480
550
|
group_name: rule[:groupName],
|
|
481
551
|
rule_id: rule[:id],
|
|
482
|
-
evaluation_details: EvaluationDetails.local_override(@
|
|
552
|
+
evaluation_details: EvaluationDetails.local_override(@spec_store.last_config_sync_time, @spec_store.initial_config_sync_time)
|
|
483
553
|
}
|
|
484
554
|
return
|
|
485
555
|
end
|
|
@@ -490,7 +560,7 @@ module Statsig
|
|
|
490
560
|
value: {},
|
|
491
561
|
group_name: group_name,
|
|
492
562
|
rule_id: "#{experiment_name}:override",
|
|
493
|
-
evaluation_details: EvaluationDetails.local_override(@
|
|
563
|
+
evaluation_details: EvaluationDetails.local_override(@spec_store.last_config_sync_time, @spec_store.initial_config_sync_time)
|
|
494
564
|
}
|
|
495
565
|
end
|
|
496
566
|
|
|
@@ -498,6 +568,10 @@ module Statsig
|
|
|
498
568
|
@experiment_overrides.clear
|
|
499
569
|
end
|
|
500
570
|
|
|
571
|
+
def remove_experiment_override(experiment_name)
|
|
572
|
+
@experiment_overrides.delete(experiment_name.to_sym)
|
|
573
|
+
end
|
|
574
|
+
|
|
501
575
|
def eval_spec(config_name, user, config, end_result, is_nested: false)
|
|
502
576
|
config[:rules].each do |rule|
|
|
503
577
|
end_result.sampling_rate = rule[:samplingRate]
|
|
@@ -525,7 +599,7 @@ module Statsig
|
|
|
525
599
|
end_result.target_app_ids = config[:targetAppIDs]
|
|
526
600
|
end_result.gate_value = did_pass
|
|
527
601
|
end_result.forward_all_exposures = config[:forwardAllExposures]
|
|
528
|
-
if config[:entity] == Const::TYPE_FEATURE_GATE
|
|
602
|
+
if config[:entity] == Const::TYPE_FEATURE_GATE || config[:entity] == Const::TYPE_HOLDOUT
|
|
529
603
|
end_result.gate_value = did_pass ? rule[:returnValue] == true : config[:defaultValue] == true
|
|
530
604
|
end
|
|
531
605
|
end_result.config_version = config[:version]
|
|
@@ -657,6 +731,10 @@ module Statsig
|
|
|
657
731
|
when Const::CND_PUBLIC
|
|
658
732
|
return true
|
|
659
733
|
when Const::CND_PASS_GATE, Const::CND_FAIL_GATE
|
|
734
|
+
if !target.is_a?(String) || target.empty?
|
|
735
|
+
return type == Const::CND_FAIL_GATE
|
|
736
|
+
end
|
|
737
|
+
|
|
660
738
|
result = eval_nested_gate(target, user, end_result)
|
|
661
739
|
if end_result.sampling_rate == nil && !target.start_with?("segment")
|
|
662
740
|
end_result.has_seen_analytical_gates = true
|
data/lib/hash_utils.rb
CHANGED
data/lib/network.rb
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
require 'connection_pool'
|
|
1
2
|
require 'http'
|
|
2
3
|
require 'json'
|
|
3
4
|
require 'securerandom'
|
|
4
5
|
require 'zlib'
|
|
5
6
|
|
|
6
|
-
require 'connection_pool'
|
|
7
|
-
|
|
8
7
|
RETRY_CODES = [408, 500, 502, 503, 504, 522, 524, 599].freeze
|
|
9
8
|
|
|
10
9
|
module Statsig
|
|
@@ -53,7 +52,11 @@ module Statsig
|
|
|
53
52
|
|
|
54
53
|
def download_config_specs(since_time)
|
|
55
54
|
url = @options.download_config_specs_url
|
|
56
|
-
|
|
55
|
+
dcs_url = "#{url}#{@server_secret}.json"
|
|
56
|
+
if since_time.positive?
|
|
57
|
+
dcs_url += "?sinceTime=#{since_time}"
|
|
58
|
+
end
|
|
59
|
+
get(dcs_url)
|
|
57
60
|
end
|
|
58
61
|
|
|
59
62
|
def post_logs(events, error_boundary)
|
|
@@ -64,6 +67,10 @@ module Statsig
|
|
|
64
67
|
gzip << json_body
|
|
65
68
|
|
|
66
69
|
response, e = post(url, gzip.close.string, @post_logs_retry_limit, 1, true, event_count)
|
|
70
|
+
|
|
71
|
+
# Consume response body to ensure connection can be closed.
|
|
72
|
+
response&.flush
|
|
73
|
+
|
|
67
74
|
unless e == nil
|
|
68
75
|
message = "Failed to log #{event_count} events after #{@post_logs_retry_limit} retries"
|
|
69
76
|
puts "[Statsig]: #{message}"
|
data/lib/spec_store.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
require 'concurrent-ruby'
|
|
1
2
|
require 'net/http'
|
|
2
3
|
require 'uri'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
require 'api_config'
|
|
4
|
+
require_relative 'api_config'
|
|
5
|
+
require_relative 'evaluation_details'
|
|
6
|
+
require_relative 'hash_utils'
|
|
7
|
+
require_relative 'id_list'
|
|
8
8
|
|
|
9
9
|
module Statsig
|
|
10
10
|
class SpecStore
|
|
@@ -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
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require 'statsig_errors'
|
|
1
|
+
require_relative 'statsig_driver'
|
|
2
|
+
require_relative 'statsig_errors'
|
|
4
3
|
|
|
5
4
|
module Statsig
|
|
6
5
|
|
|
@@ -92,6 +91,11 @@ module Statsig
|
|
|
92
91
|
@shared_instance&.manually_log_gate_exposure(user, gate_name)
|
|
93
92
|
end
|
|
94
93
|
|
|
94
|
+
def self.get_fields_used_for_gate(gate_name)
|
|
95
|
+
ensure_initialized
|
|
96
|
+
@shared_instance&.get_fields_used_for_gate(gate_name)
|
|
97
|
+
end
|
|
98
|
+
|
|
95
99
|
class GetConfigOptions
|
|
96
100
|
attr_accessor :disable_log_exposure, :disable_evaluation_details, :ignore_local_overrides
|
|
97
101
|
|
|
@@ -136,6 +140,11 @@ module Statsig
|
|
|
136
140
|
@shared_instance&.manually_log_config_exposure(user, dynamic_config)
|
|
137
141
|
end
|
|
138
142
|
|
|
143
|
+
def self.get_fields_used_for_config(config_name)
|
|
144
|
+
ensure_initialized
|
|
145
|
+
@shared_instance&.get_fields_used_for_config(config_name)
|
|
146
|
+
end
|
|
147
|
+
|
|
139
148
|
class GetExperimentOptions
|
|
140
149
|
attr_accessor :disable_log_exposure, :user_persisted_values, :disable_evaluation_details, :ignore_local_overrides
|
|
141
150
|
|
|
@@ -184,6 +193,11 @@ module Statsig
|
|
|
184
193
|
@shared_instance&.get_user_persisted_values(user, id_type)
|
|
185
194
|
end
|
|
186
195
|
|
|
196
|
+
def self.get_fields_used_for_experiment(experiment_name)
|
|
197
|
+
ensure_initialized
|
|
198
|
+
@shared_instance&.get_fields_used_for_config(experiment_name)
|
|
199
|
+
end
|
|
200
|
+
|
|
187
201
|
class GetLayerOptions
|
|
188
202
|
attr_accessor :disable_log_exposure, :disable_evaluation_details
|
|
189
203
|
|
|
@@ -227,6 +241,11 @@ module Statsig
|
|
|
227
241
|
@shared_instance&.manually_log_layer_parameter_exposure(user, layer_name, parameter_name)
|
|
228
242
|
end
|
|
229
243
|
|
|
244
|
+
def self.get_fields_used_for_layer(layer_name)
|
|
245
|
+
ensure_initialized
|
|
246
|
+
@shared_instance&.get_fields_used_for_layer(layer_name)
|
|
247
|
+
end
|
|
248
|
+
|
|
230
249
|
##
|
|
231
250
|
# Logs an event to Statsig with the provided values.
|
|
232
251
|
#
|
|
@@ -354,6 +373,11 @@ module Statsig
|
|
|
354
373
|
@shared_instance&.clear_experiment_overrides
|
|
355
374
|
end
|
|
356
375
|
|
|
376
|
+
def self.remove_experiment_override(experiment_name)
|
|
377
|
+
ensure_initialized
|
|
378
|
+
@shared_instance&.remove_experiment_override(experiment_name)
|
|
379
|
+
end
|
|
380
|
+
|
|
357
381
|
##
|
|
358
382
|
# @param [HashTable] debug information log with exposure events
|
|
359
383
|
def self.set_debug_info(debug_info)
|
|
@@ -386,7 +410,7 @@ module Statsig
|
|
|
386
410
|
def self.get_statsig_metadata
|
|
387
411
|
{
|
|
388
412
|
'sdkType' => 'ruby-server',
|
|
389
|
-
'sdkVersion' => '2.
|
|
413
|
+
'sdkVersion' => '2.8.3',
|
|
390
414
|
'languageVersion' => RUBY_VERSION
|
|
391
415
|
}
|
|
392
416
|
end
|
data/lib/statsig_driver.rb
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
require_relative 'api_config'
|
|
2
|
+
require_relative 'config_result'
|
|
3
|
+
require_relative 'diagnostics'
|
|
4
|
+
require_relative 'dynamic_config'
|
|
5
|
+
require_relative 'error_boundary'
|
|
6
|
+
require_relative 'evaluator'
|
|
7
|
+
require_relative 'feature_gate'
|
|
8
|
+
require_relative 'layer'
|
|
9
|
+
require_relative 'memo'
|
|
10
|
+
require_relative 'network'
|
|
11
|
+
require_relative 'sdk_configs'
|
|
12
|
+
require_relative 'spec_store'
|
|
13
|
+
require_relative 'statsig_errors'
|
|
14
|
+
require_relative 'statsig_event'
|
|
15
|
+
require_relative 'statsig_logger'
|
|
16
|
+
require_relative 'statsig_options'
|
|
17
|
+
require_relative 'statsig_user'
|
|
17
18
|
|
|
18
19
|
class StatsigDriver
|
|
19
20
|
|
|
@@ -117,6 +118,15 @@ class StatsigDriver
|
|
|
117
118
|
end
|
|
118
119
|
end
|
|
119
120
|
|
|
121
|
+
def get_fields_used_for_gate(gate_name)
|
|
122
|
+
@err_boundary.capture(caller: __method__, recover: -> { [] }) do
|
|
123
|
+
gate = @store.get_gate(gate_name)
|
|
124
|
+
return [] if gate.nil?
|
|
125
|
+
|
|
126
|
+
gate[:fieldsUsed] || []
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
120
130
|
def get_config(user, dynamic_config_name, options = nil)
|
|
121
131
|
@err_boundary.capture(caller: __method__, recover: -> { DynamicConfig.new(dynamic_config_name) }) do
|
|
122
132
|
run_with_diagnostics(caller: :get_config) do
|
|
@@ -132,6 +142,15 @@ class StatsigDriver
|
|
|
132
142
|
end
|
|
133
143
|
end
|
|
134
144
|
|
|
145
|
+
def get_fields_used_for_config(config_name)
|
|
146
|
+
@err_boundary.capture(caller: __method__, recover: -> { [] }) do
|
|
147
|
+
config = @store.get_config(config_name)
|
|
148
|
+
return [] if config.nil?
|
|
149
|
+
|
|
150
|
+
config[:fieldsUsed] || []
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
135
154
|
def get_experiment(user, experiment_name, options = nil)
|
|
136
155
|
@err_boundary.capture(caller: __method__, recover: -> { DynamicConfig.new(experiment_name) }) do
|
|
137
156
|
run_with_diagnostics(caller: :get_experiment) do
|
|
@@ -201,6 +220,15 @@ class StatsigDriver
|
|
|
201
220
|
end
|
|
202
221
|
end
|
|
203
222
|
|
|
223
|
+
def get_fields_used_for_layer(layer_name)
|
|
224
|
+
@err_boundary.capture(caller: __method__, recover: -> { [] }) do
|
|
225
|
+
layer = @store.get_layer(layer_name)
|
|
226
|
+
return [] if layer.nil?
|
|
227
|
+
|
|
228
|
+
layer[:fieldsUsed] || []
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
204
232
|
def log_event(user, event_name, value = nil, metadata = nil)
|
|
205
233
|
@err_boundary.capture(caller: __method__) do
|
|
206
234
|
if !user.nil? && !user.instance_of?(StatsigUser)
|
|
@@ -310,6 +338,12 @@ class StatsigDriver
|
|
|
310
338
|
end
|
|
311
339
|
end
|
|
312
340
|
|
|
341
|
+
def remove_experiment_override(experiment_name)
|
|
342
|
+
@err_boundary.capture(caller: __method__) do
|
|
343
|
+
@evaluator.remove_experiment_override(experiment_name)
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
313
347
|
def set_debug_info(debug_info)
|
|
314
348
|
@err_boundary.capture(caller: __method__) do
|
|
315
349
|
@logger.set_debug_info(debug_info)
|
data/lib/statsig_logger.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
require 'constants'
|
|
2
|
-
require 'statsig_event'
|
|
3
|
-
require 'ttl_set'
|
|
4
1
|
require 'concurrent-ruby'
|
|
5
|
-
|
|
2
|
+
require_relative 'constants'
|
|
3
|
+
require_relative 'hash_utils'
|
|
4
|
+
require_relative 'statsig_event'
|
|
5
|
+
require_relative 'ttl_set'
|
|
6
6
|
|
|
7
7
|
$gate_exposure_event = 'statsig::gate_exposure'
|
|
8
8
|
$config_exposure_event = 'statsig::config_exposure'
|
|
@@ -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
|
data/lib/statsig_user.rb
CHANGED
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.8.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Statsig, Inc
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|