Class: Statsig::StatsigLogger

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

Instance Method Summary collapse

Constructor Details

#initialize(network, options) ⇒ StatsigLogger

Returns a new instance of StatsigLogger.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/statsig_logger.rb', line 12

def initialize(network, options)
  @network = network
  @events = []
  @options = options

  @logging_pool = Concurrent::ThreadPoolExecutor.new(
    name: 'statsig-logger',
    min_threads: @options.logger_threadpool_size,
    max_threads: @options.logger_threadpool_size,
    # max jobs pending before we start dropping
    max_queue: 100,
    fallback_policy: :discard
  )

  @background_flush = periodic_flush
  @deduper = Concurrent::Set.new()
  @interval = 0
end

Instance Method Details

#flushObject



130
131
132
133
134
135
136
137
138
139
# File 'lib/statsig_logger.rb', line 130

def flush
  if @events.length == 0
    return
  end
  events_clone = @events
  @events = []
  flush_events = events_clone.map { |e| e.serialize }

  @network.post_logs(flush_events)
end

#flush_asyncObject



124
125
126
127
128
# File 'lib/statsig_logger.rb', line 124

def flush_async
  @logging_pool.post do
    flush
  end
end

#log_config_exposure(user, config_name, rule_id, secondary_exposures, eval_details, context = nil) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/statsig_logger.rb', line 56

def log_config_exposure(user, config_name, rule_id, secondary_exposures, eval_details, context = nil)
  event = StatsigEvent.new($config_exposure_event)
  event.user = user
   = {
    'config' => config_name,
    'ruleID' => rule_id,
  }
  return false if not is_unique_exposure(user, $config_exposure_event, )
  event. = 
  event.secondary_exposures = secondary_exposures.is_a?(Array) ? secondary_exposures : []

  safe_add_eval_details(eval_details, event)
  safe_add_exposure_context(context, event)
  log_event(event)
end

#log_diagnostics_event(diagnostics, user = nil) ⇒ Object



99
100
101
102
103
104
# File 'lib/statsig_logger.rb', line 99

def log_diagnostics_event(diagnostics, user = nil)
  event = StatsigEvent.new($diagnostics_event)
  event.user = user
  event. = diagnostics.serialize
  log_event(event)
end

#log_event(event) ⇒ Object



31
32
33
34
35
36
# File 'lib/statsig_logger.rb', line 31

def log_event(event)
  @events.push(event)
  if @events.length >= @options.logging_max_buffer_size
    flush_async
  end
end

#log_gate_exposure(user, gate_name, value, rule_id, secondary_exposures, eval_details, context = nil) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/statsig_logger.rb', line 38

def log_gate_exposure(user, gate_name, value, rule_id, secondary_exposures, eval_details, context = nil)
  event = StatsigEvent.new($gate_exposure_event)
  event.user = user
   = {
    'gate' => gate_name,
    'gateValue' => value.to_s,
    'ruleID' => rule_id,
  }
  return false if not is_unique_exposure(user, $gate_exposure_event, )
  event. = 

  event.secondary_exposures = secondary_exposures.is_a?(Array) ? secondary_exposures : []

  safe_add_eval_details(eval_details, event)
  safe_add_exposure_context(context, event)
  log_event(event)
end

#log_layer_exposure(user, layer, parameter_name, config_evaluation, context = nil) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/statsig_logger.rb', line 72

def log_layer_exposure(user, layer, parameter_name, config_evaluation, context = nil)
  exposures = config_evaluation.undelegated_sec_exps
  allocated_experiment = ''
  is_explicit = (config_evaluation.explicit_parameters&.include? parameter_name) || false
  if is_explicit
    allocated_experiment = config_evaluation.config_delegate
    exposures = config_evaluation.secondary_exposures
  end

  event = StatsigEvent.new($layer_exposure_event)
  event.user = user
   = {
    'config' => layer.name,
    'ruleID' => layer.rule_id,
    'allocatedExperiment' => allocated_experiment,
    'parameterName' => parameter_name,
    'isExplicitParameter' => String(is_explicit),
  }
  return false if not is_unique_exposure(user, $layer_exposure_event, )
  event. = 
  event.secondary_exposures = exposures.is_a?(Array) ? exposures : []

  safe_add_eval_details(config_evaluation.evaluation_details, event)
  safe_add_exposure_context(context, event)
  log_event(event)
end

#maybe_restart_background_threadsObject



141
142
143
144
145
# File 'lib/statsig_logger.rb', line 141

def maybe_restart_background_threads
  if @background_flush.nil? or !@background_flush.alive?
    @background_flush = periodic_flush
  end
end

#periodic_flushObject



106
107
108
109
110
111
112
113
114
115
# File 'lib/statsig_logger.rb', line 106

def periodic_flush
  Thread.new do
    loop do
      sleep @options.logging_interval_seconds
      flush_async
      @interval += 1
      @deduper.clear if @interval % 2 == 0
    end
  end
end

#shutdownObject



117
118
119
120
121
122
# File 'lib/statsig_logger.rb', line 117

def shutdown
  @background_flush&.exit
  @logging_pool.shutdown
  @logging_pool.wait_for_termination(timeout = 3)
  flush
end