Class: StatsigDriver

Inherits:
Object
  • Object
show all
Defined in:
lib/statsig_driver.rb

Instance Method Summary collapse

Constructor Details

#initialize(secret_key, options = nil, error_callback = nil) ⇒ StatsigDriver

Returns a new instance of StatsigDriver.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/statsig_driver.rb', line 19

def initialize(secret_key, options = nil, error_callback = nil)
  unless secret_key.start_with?('secret-')
    raise Statsig::ValueError.new('Invalid secret key provided. Provide your project secret key from the Statsig console')
  end

  if !options.nil? && !options.instance_of?(StatsigOptions)
    raise Statsig::ValueError.new('Invalid options provided. Either provide a valid StatsigOptions object or nil')
  end

  @err_boundary = Statsig::ErrorBoundary.new(secret_key)
  @err_boundary.capture(caller: __method__) do
    @diagnostics = Statsig::Diagnostics.new()
    tracker = @diagnostics.track('initialize', 'overall')
    @options = options || StatsigOptions.new
    @shutdown = false
    @secret_key = secret_key
    @net = Statsig::Network.new(secret_key, @options)
    @logger = Statsig::StatsigLogger.new(@net, @options, @err_boundary)
    @persistent_storage_utils = Statsig::UserPersistentStorageUtils.new(@options)
    @store = Statsig::SpecStore.new(@net, @options, error_callback, @diagnostics, @err_boundary, @logger, secret_key)
    @evaluator = Statsig::Evaluator.new(@store, @options, @persistent_storage_utils)
    tracker.end(success: true)

    @logger.log_diagnostics_event(@diagnostics, 'initialize')
  end
end

Instance Method Details

#check_gate(user, gate_name, options = nil) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/statsig_driver.rb', line 88

def check_gate(user, gate_name, options = nil)
  @err_boundary.capture(caller: __method__, recover: -> {false}) do
    run_with_diagnostics(caller: :check_gate) do 
      get_gate_impl(
        user,
        gate_name,
        disable_log_exposure: options&.disable_log_exposure == true,
        disable_evaluation_details: options&.disable_evaluation_details == true,
        ignore_local_overrides: options&.ignore_local_overrides == true
      ).value
    end
  end
end

#clear_config_overridesObject



292
293
294
295
296
# File 'lib/statsig_driver.rb', line 292

def clear_config_overrides
  @err_boundary.capture(caller: __method__) do
    @evaluator.clear_config_overrides
  end
end

#clear_gate_overridesObject



274
275
276
277
278
# File 'lib/statsig_driver.rb', line 274

def clear_gate_overrides
  @err_boundary.capture(caller: __method__) do
    @evaluator.clear_gate_overrides
  end
end

#get_client_initialize_response(user, hash, client_sdk_key, include_local_overrides) ⇒ Hash

Parameters:

  • user (StatsigUser)
  • client_sdk_key (String | nil)
  • include_local_overrides (Boolean)

Returns:

  • (Hash)


308
309
310
311
312
313
314
# File 'lib/statsig_driver.rb', line 308

def get_client_initialize_response(user, hash, client_sdk_key, include_local_overrides)
  @err_boundary.capture(caller: __method__, recover: -> { nil }) do
    validate_user(user)
    normalize_user(user)
    @evaluator.get_client_initialize_response(user, hash, client_sdk_key, include_local_overrides)
  end
end

#get_config(user, dynamic_config_name, options = nil) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/statsig_driver.rb', line 111

def get_config(user, dynamic_config_name, options = nil)
  @err_boundary.capture(caller: __method__, recover: -> { DynamicConfig.new(dynamic_config_name) }) do
    run_with_diagnostics(caller: :get_config) do
      user = verify_inputs(user, dynamic_config_name, "dynamic_config_name")
      get_config_impl(
        user,
        dynamic_config_name,
        options&.disable_log_exposure == true,
        disable_evaluation_details: options&.disable_evaluation_details == true,
        ignore_local_overrides: options&.ignore_local_overrides == true
      )
    end
  end
end

#get_experiment(user, experiment_name, options = nil) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/statsig_driver.rb', line 126

def get_experiment(user, experiment_name, options = nil)
  @err_boundary.capture(caller: __method__, recover: -> { DynamicConfig.new(experiment_name) }) do
    run_with_diagnostics(caller: :get_experiment) do
      user = verify_inputs(user, experiment_name, "experiment_name")
      get_config_impl(
        user,
        experiment_name,
        options&.disable_log_exposure == true,
        user_persisted_values: options&.user_persisted_values,
        disable_evaluation_details: options&.disable_evaluation_details == true,
        ignore_local_overrides: options&.ignore_local_overrides == true
      )
    end
  end
end

#get_gate(user, gate_name, options = nil) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
# File 'lib/statsig_driver.rb', line 76

def get_gate(user, gate_name, options = nil)
  @err_boundary.capture(caller: __method__, recover: -> {false}) do
    run_with_diagnostics(caller: :get_gate) do
      get_gate_impl(user, gate_name,
                    disable_log_exposure: options&.disable_log_exposure == true,
                    skip_evaluation: options&.skip_evaluation == true,
                    disable_evaluation_details: options&.disable_evaluation_details == true
      )
    end
  end
end

#get_gate_impl(user, gate_name, disable_log_exposure: false, skip_evaluation: false, disable_evaluation_details: false, ignore_local_overrides: false) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/statsig_driver.rb', line 46

def get_gate_impl(
  user,
  gate_name,
  disable_log_exposure: false,
  skip_evaluation: false,
  disable_evaluation_details: false,
  ignore_local_overrides: false
)
  if skip_evaluation
    gate = @store.get_gate(gate_name)
    return FeatureGate.new(gate_name) if gate.nil?
    return FeatureGate.new(gate.name, target_app_ids: gate.target_app_ids)
  end
 
  user = verify_inputs(user, gate_name, 'gate_name')
  return Statsig::Memo.for(user.get_memo(), :get_gate_impl, gate_name) do

    res = Statsig::ConfigResult.new(name: gate_name, disable_exposures: disable_log_exposure, disable_evaluation_details: disable_evaluation_details)
    @evaluator.check_gate(user, gate_name, res, ignore_local_overrides: ignore_local_overrides)

    unless disable_log_exposure
    @logger.log_gate_exposure(
        user, res.name, res.gate_value, res.rule_id, res.secondary_exposures, res.evaluation_details
      )
    end
    FeatureGate.from_config_result(res)
  end
end

#get_layer(user, layer_name, options = nil) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/statsig_driver.rb', line 161

def get_layer(user, layer_name, options = nil)
  @err_boundary.capture(caller: __method__, recover: -> { Layer.new(layer_name) }) do
    run_with_diagnostics(caller: :get_layer) do
      user = verify_inputs(user, layer_name, "layer_name")
      Statsig::Memo.for(user.get_memo(), :get_layer, layer_name) do
        exposures_disabled = options&.disable_log_exposure == true
        res = Statsig::ConfigResult.new(
          name: layer_name,
          disable_exposures: exposures_disabled,
          disable_evaluation_details: options&.disable_evaluation_details == true
        )
        @evaluator.get_layer(user, layer_name, res)

        exposure_log_func = !exposures_disabled ? lambda { |layer, parameter_name|
          @logger.log_layer_exposure(user, layer, parameter_name, res)
        } : nil

        Layer.new(res.name, res.json_value, res.rule_id, res.group_name, res.config_delegate, exposure_log_func)
      end
    end
  end
end

#get_user_persisted_values(user, id_type) ⇒ Object



152
153
154
155
156
157
158
159
# File 'lib/statsig_driver.rb', line 152

def get_user_persisted_values(user, id_type)
  @err_boundary.capture(caller: __method__,) do
    persisted_values = @persistent_storage_utils.get_user_persisted_values(user, id_type)
    return {} if persisted_values.nil?

    persisted_values
  end
end

#list_autotunesObject



242
243
244
245
246
# File 'lib/statsig_driver.rb', line 242

def list_autotunes
  @err_boundary.capture(caller: __method__) do
    @evaluator.list_autotunes
  end
end

#list_configsObject



230
231
232
233
234
# File 'lib/statsig_driver.rb', line 230

def list_configs
  @err_boundary.capture(caller: __method__) do
    @evaluator.list_configs
  end
end

#list_experimentsObject



236
237
238
239
240
# File 'lib/statsig_driver.rb', line 236

def list_experiments
  @err_boundary.capture(caller: __method__) do
    @evaluator.list_experiments
  end
end

#list_gatesObject



224
225
226
227
228
# File 'lib/statsig_driver.rb', line 224

def list_gates
  @err_boundary.capture(caller: __method__) do
    @evaluator.list_gates
  end
end

#list_layersObject



248
249
250
251
252
# File 'lib/statsig_driver.rb', line 248

def list_layers
  @err_boundary.capture(caller: __method__) do
    @evaluator.list_layers
  end
end

#log_event(user, event_name, value = nil, metadata = nil) ⇒ Object



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/statsig_driver.rb', line 195

def log_event(user, event_name, value = nil,  = nil)
  @err_boundary.capture(caller: __method__) do
    if !user.nil? && !user.instance_of?(StatsigUser)
      raise Statsig::ValueError.new('Must provide a valid StatsigUser or nil')
    end
    check_shutdown

    user = normalize_user(user)

    event = StatsigEvent.new(event_name)
    event.user = user
    event.value = value
    event. = 
    @logger.log_event(event)
  end
end

#manually_log_config_exposure(user, config_name) ⇒ Object



142
143
144
145
146
147
148
149
150
# File 'lib/statsig_driver.rb', line 142

def manually_log_config_exposure(user, config_name)
  @err_boundary.capture(caller: __method__) do
    res = Statsig::ConfigResult.new(name: config_name)
    @evaluator.get_config(user, config_name, res)

    context = { :is_manual_exposure => true }
    @logger.log_config_exposure(user, res.name, res.rule_id, res.secondary_exposures, res.evaluation_details, context)
  end
end

#manually_log_gate_exposure(user, gate_name) ⇒ Object



102
103
104
105
106
107
108
109
# File 'lib/statsig_driver.rb', line 102

def manually_log_gate_exposure(user, gate_name)
  @err_boundary.capture(caller: __method__) do
    res = Statsig::ConfigResult.new(name: gate_name)
    @evaluator.check_gate(user, gate_name, res)
    context = { :is_manual_exposure => true }
    @logger.log_gate_exposure(user, gate_name, res.gate_value, res.rule_id, res.secondary_exposures, res.evaluation_details, context)
  end
end

#manually_log_layer_parameter_exposure(user, layer_name, parameter_name) ⇒ Object



184
185
186
187
188
189
190
191
192
193
# File 'lib/statsig_driver.rb', line 184

def manually_log_layer_parameter_exposure(user, layer_name, parameter_name)
  @err_boundary.capture(caller: __method__) do
    res = Statsig::ConfigResult.new(name: layer_name)
    @evaluator.get_layer(user, layer_name, res)

    layer = Layer.new(layer_name, res.json_value, res.rule_id, res.group_name, res.config_delegate)
    context = { :is_manual_exposure => true }
    @logger.log_layer_exposure(user, layer, parameter_name, res, context)
  end
end

#manually_sync_idlistsObject



218
219
220
221
222
# File 'lib/statsig_driver.rb', line 218

def manually_sync_idlists
  @err_boundary.capture(caller: __method__) do
    @evaluator.spec_store.sync_id_lists
  end
end

#manually_sync_rulesetsObject



212
213
214
215
216
# File 'lib/statsig_driver.rb', line 212

def manually_sync_rulesets
  @err_boundary.capture(caller: __method__) do
    @evaluator.spec_store.sync_config_specs
  end
end

#maybe_restart_background_threadsObject



316
317
318
319
320
321
322
323
324
325
# File 'lib/statsig_driver.rb', line 316

def maybe_restart_background_threads
  if @options.local_mode
    return
  end

  @err_boundary.capture(caller: __method__) do
    @evaluator.maybe_restart_background_threads
    @logger.maybe_restart_background_threads
  end
end

#override_config(config_name, config_value) ⇒ Object



280
281
282
283
284
# File 'lib/statsig_driver.rb', line 280

def override_config(config_name, config_value)
  @err_boundary.capture(caller: __method__) do
    @evaluator.override_config(config_name, config_value)
  end
end

#override_gate(gate_name, gate_value) ⇒ Object



262
263
264
265
266
# File 'lib/statsig_driver.rb', line 262

def override_gate(gate_name, gate_value)
  @err_boundary.capture(caller: __method__) do
    @evaluator.override_gate(gate_name, gate_value)
  end
end

#remove_config_override(config_name) ⇒ Object



286
287
288
289
290
# File 'lib/statsig_driver.rb', line 286

def remove_config_override(config_name)
  @err_boundary.capture(caller: __method__) do
    @evaluator.remove_config_override(config_name)
  end
end

#remove_gate_override(gate_name) ⇒ Object



268
269
270
271
272
# File 'lib/statsig_driver.rb', line 268

def remove_gate_override(gate_name)
  @err_boundary.capture(caller: __method__) do
    @evaluator.remove_gate_override(gate_name)
  end
end

#set_debug_info(debug_info) ⇒ Object



298
299
300
301
302
# File 'lib/statsig_driver.rb', line 298

def set_debug_info(debug_info)
  @err_boundary.capture(caller: __method__) do
    @logger.set_debug_info(debug_info)
  end
end

#shutdownObject



254
255
256
257
258
259
260
# File 'lib/statsig_driver.rb', line 254

def shutdown
  @err_boundary.capture(caller: __method__) do
    @shutdown = true
    @logger.shutdown
    @evaluator.shutdown
  end
end