Class: Statsig::StatsigLogger

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

Instance Method Summary collapse

Constructor Details

#initialize(network, options, error_boundary) ⇒ 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
30
31
32
# File 'lib/statsig_logger.rb', line 12

def initialize(network, options, error_boundary)
  @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
  )

  @error_boundary = error_boundary
  @background_flush = periodic_flush
  @deduper = Concurrent::Set.new()
  @interval = 0
  @flush_mutex = Mutex.new
  @debug_info = nil
end

Instance Method Details

#flushObject



164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/statsig_logger.rb', line 164

def flush
  @flush_mutex.synchronize do
    if @events.length.zero?
      return
    end

    events_clone = @events
    @events = []
    flush_events = events_clone.map { |e| e.serialize }
    @network.post_logs(flush_events, @error_boundary)
  end
end

#flush_asyncObject



158
159
160
161
162
# File 'lib/statsig_logger.rb', line 158

def flush_async
  @logging_pool.post do
    flush
  end
end

#log_config_exposure(user, result, context = nil) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/statsig_logger.rb', line 65

def log_config_exposure(user, result, context = nil)
  event = StatsigEvent.new($config_exposure_event)
  event.user = user
   = {
    config: result.name,
    ruleID: result.rule_id || Statsig::Const::EMPTY_STR,
    rulePassed: result.gate_value.to_s,
  }
  if result.config_version != nil
    [:configVersion] = result.config_version.to_s
  end
  if @debug_info != nil
    [:debugInfo] = @debug_info
  end
  return false if not is_unique_exposure(user, $config_exposure_event, )
  event. = 
  event.secondary_exposures = result.secondary_exposures.is_a?(Array) ? result.secondary_exposures : []

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

#log_diagnostics_event(diagnostics, context, user = nil) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/statsig_logger.rb', line 121

def log_diagnostics_event(diagnostics, context, user = nil)
  return if diagnostics.nil?
  if @options.disable_diagnostics_logging
    diagnostics.clear_markers(context)
    return
  end

  event = StatsigEvent.new($diagnostics_event)
  event.user = user
  serialized = diagnostics.serialize_with_sampling(context)
  diagnostics.clear_markers(context)
  return if serialized[:markers].empty?

  event. = serialized
  log_event(event)
end

#log_event(event) ⇒ Object



34
35
36
37
38
39
# File 'lib/statsig_logger.rb', line 34

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

#log_gate_exposure(user, result, context = nil) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/statsig_logger.rb', line 41

def log_gate_exposure(user, result, context = nil)
  event = StatsigEvent.new($gate_exposure_event)
  event.user = user
   = {
    gate: result.name,
    gateValue: result.gate_value.to_s,
    ruleID: result.rule_id || Statsig::Const::EMPTY_STR,
  }
  if result.config_version != nil
    [:configVersion] = result.config_version.to_s
  end
  if @debug_info != nil
    [:debugInfo] = @debug_info
  end
  return false if not is_unique_exposure(user, $gate_exposure_event, )
  event. = 

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

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

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



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/statsig_logger.rb', line 88

def log_layer_exposure(user, layer, parameter_name, config_evaluation, context = nil)
  exposures = config_evaluation.undelegated_sec_exps || []
  allocated_experiment = Statsig::Const::EMPTY_STR
  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 || Statsig::Const::EMPTY_STR,
    allocatedExperiment: allocated_experiment,
    parameterName: parameter_name,
    isExplicitParameter: String(is_explicit)
  }
  if config_evaluation.config_version != nil
    [:configVersion] = config_evaluation.config_version.to_s
  end
  if @debug_info != nil
    [:debugInfo] = @debug_info
  end
  return false unless 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



177
178
179
180
181
# File 'lib/statsig_logger.rb', line 177

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

#periodic_flushObject



138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/statsig_logger.rb', line 138

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

#set_debug_info(debug_info) ⇒ Object



183
184
185
# File 'lib/statsig_logger.rb', line 183

def set_debug_info(debug_info)
  @debug_info = debug_info
end

#shutdownObject



151
152
153
154
155
156
# File 'lib/statsig_logger.rb', line 151

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