Class: OneApm::Configuration::Manager

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

Constant Summary collapse

MALFORMED_LABELS_WARNING =
"Skipping malformed labels configuration"
PARSING_LABELS_FAILURE =
"Failure during parsing labels. Ignoring and carrying on with connect."
MAX_LABEL_COUNT =
64
MAX_LABEL_LENGTH =
255

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeManager

Returns a new instance of Manager.



24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/one_apm/configuration.rb', line 24

def initialize
  reset_to_defaults
  @callbacks = Hash.new {|hash,key| hash[key] = [] }

  register_callback(:'strip_exception_messages.whitelist') do |whitelist|
    if whitelist
      @stripped_exceptions_whitelist = parse_constant_list(whitelist).compact
    else
      @stripped_exceptions_whitelist = []
    end
  end
end

Instance Attribute Details

#stripped_exceptions_whitelistObject (readonly)

Returns the value of attribute stripped_exceptions_whitelist.



22
23
24
# File 'lib/one_apm/configuration.rb', line 22

def stripped_exceptions_whitelist
  @stripped_exceptions_whitelist
end

Instance Method Details

#[](key) ⇒ Object

Defining these explicitly saves object allocations that we incur if we use Forwardable and def_delegators.



39
40
41
# File 'lib/one_apm/configuration.rb', line 39

def [](key)
  @cache[key]
end

#_callbacks_(direction, source, key) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
# File 'lib/one_apm/configuration.rb', line 194

def _callbacks_ direction, source, key
  if @cache[key] != source[key]
    @callbacks[key].each do |proc|
      case direction
      when :add    then proc.call(source[key])
      when :append then proc.call(@cache[key], source[key])
      else proc.call(@cache[key])
      end
    end
  end
end

#_invoke_callbacks_(source) ⇒ Object



179
180
181
182
183
184
185
# File 'lib/one_apm/configuration.rb', line 179

def _invoke_callbacks_ source
  return unless source
  @directions = directions(source)
  source.keys.each do |key|
    _callbacks_(@directions[key], source, key) 
  end
end

#add_config_for_testing(source, level = 0) ⇒ Object



51
52
53
54
55
56
57
# File 'lib/one_apm/configuration.rb', line 51

def add_config_for_testing(source, level=0)
  raise 'Invalid config type for testing' unless [Hash, OneApm::Support::DottedHash].include?(source.class)
  invoke_callbacks(:add, source)
  @configs_for_testing << [source.freeze, level]
  reset_cache
  log_config(:add, source)
end

#app_nameObject



269
270
271
# File 'lib/one_apm/configuration.rb', line 269

def app_name
  OneApm::Manager.config[:app_name]
end

#apply_mask(hash) ⇒ Object



238
239
240
241
242
243
# File 'lib/one_apm/configuration.rb', line 238

def apply_mask(hash)
  OA_MASK_DEFAULTS. \
    select {|_, proc| proc.call}. \
    each {|key, _| hash.delete(key) }
  hash
end

#apply_transformations(key, value) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/one_apm/configuration.rb', line 157

def apply_transformations(key, value)
  if transform = transform_from_default(key)
    begin
      transform.call(value)
    rescue => e
      OneApm::Manager.logger.error("Error applying transformation for #{key}, falling back to #{value}.", e)
      raise e
    end
  else
    value
  end
end

#break_label_string_into_pairs(labels) ⇒ Object



305
306
307
308
309
310
# File 'lib/one_apm/configuration.rb', line 305

def break_label_string_into_pairs(labels)
  stripped_labels = labels.strip
  stripped_labels.split(';').map do |pair|
    pair.split(':').map(&:strip)
  end
end

#config_classes_for_testingObject



426
427
428
# File 'lib/one_apm/configuration.rb', line 426

def config_classes_for_testing
  config_stack.map(&:class)
end

#configure(source) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/one_apm/configuration.rb', line 103

def configure source
  source.freeze
  was_finished = finished_configuring?
  operation = yield
  case source
  when HighSecuritySource then @high_security_source = source
  when EnvironmentSource  then @environment_source   = source
  when ServerSource       then @server_source        = source
  when ManualSource       then @manual_source        = source
  when YamlSource         then @yaml_source          = source
  when DefaultSource      then @default_source       = source
  else
    OneApm::Manager.logger.warn("Invalid config format; config will be ignored: #{source}")
  end
  reset_cache
  log_config(operation, source)
  notify_finished_configuring if !was_finished && finished_configuring?
end

#delete_all_configs_for_testingObject



412
413
414
415
416
417
418
419
420
# File 'lib/one_apm/configuration.rb', line 412

def delete_all_configs_for_testing
  @high_security_source = nil
  @environment_source   = nil
  @server_source        = nil
  @manual_source        = nil
  @yaml_source          = nil
  @default_source       = nil
  @configs_for_testing  = []
end

#directions(source) ⇒ Object



206
207
208
209
210
211
212
# File 'lib/one_apm/configuration.rb', line 206

def directions source
  h = Hash.new{|h, k| h[k] = :add}
  source.each do |key, value|
    h[key] = source[:"#{key}.direction"].to_sym if source[:"#{key}.direction"]
  end 
  h
end

#evaluate_procs(value) ⇒ Object



149
150
151
152
153
154
155
# File 'lib/one_apm/configuration.rb', line 149

def evaluate_procs(value)
  if value.respond_to?(:call)
    instance_eval(&value)
  else
    value
  end
end

#fetch(key) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/one_apm/configuration.rb', line 130

def fetch(key)
  config_stack.each do |config|
    next unless config
    accessor = key.to_sym

    if config.has_key?(accessor)
      evaluated = evaluate_procs(config[accessor])

      begin
        return apply_transformations(accessor, evaluated)
      rescue
        next
      end
    end
  end

  nil
end

#finished_configuring?Boolean

Returns:



218
219
220
# File 'lib/one_apm/configuration.rb', line 218

def finished_configuring?
  !@server_source.nil?
end

#flattenedObject



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/one_apm/configuration.rb', line 222

def flattened
  config_stack.reverse.inject({}) do |flat,layer|
    thawed_layer = layer.to_hash.dup
    thawed_layer.each do |k,v|
      begin
        thawed_layer[k] = instance_eval(&v) if v.respond_to?(:call)
      rescue => e
        OneApm::Manager.logger.debug("#{e.class.name} : #{e.message} - when accessing config key #{k}")
        thawed_layer[k] = nil
      end
      thawed_layer.delete(:config)
    end
    flat.merge(thawed_layer.to_hash)
  end
end

#has_key?(key) ⇒ Boolean

Returns:



43
44
45
# File 'lib/one_apm/configuration.rb', line 43

def has_key?(key)
  @cache.has_key?[key]
end

#invoke_callbacks(direction, source) ⇒ Object



187
188
189
190
191
192
# File 'lib/one_apm/configuration.rb', line 187

def invoke_callbacks direction, source
  return unless source
  source.keys.each do |key|
   _callbacks_(direction, source, key)
  end
end

#keysObject



47
48
49
# File 'lib/one_apm/configuration.rb', line 47

def keys
  @cache.keys
end

#limit_number_of_labels(pairs) ⇒ Object



361
362
363
364
365
366
367
368
# File 'lib/one_apm/configuration.rb', line 361

def limit_number_of_labels(pairs)
  if pairs.length > MAX_LABEL_COUNT
    OneApm::Manager.logger.warn("Too many labels defined. Only taking first #{MAX_LABEL_COUNT}")
    pairs[0...64]
  else
    pairs
  end
end

#log_config(direction, source) ⇒ Object



402
403
404
405
406
407
408
409
410
# File 'lib/one_apm/configuration.rb', line 402

def log_config(direction, source)
  # Just generating this log message (specifically calling
  # flattened.inspect) is expensive enough that we don't want to do it
  # unless we're actually going to be logging the message based on our
  # current log level.
  OneApm::Manager.logger.debug do
    "Updating config (#{direction}) from #{source.class}. Results: #{flattened.inspect}"
  end
end

#make_label_hash(pairs, labels = nil) ⇒ Object



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/one_apm/configuration.rb', line 328

def make_label_hash(pairs, labels = nil)
  # This can accept a hash, so force it down to an array of pairs first
  pairs = Array(pairs)

  unless valid_label_pairs?(pairs)
    OneApm::Manager.logger.warn("#{MALFORMED_LABELS_WARNING}: #{labels||pairs}")
    return []
  end

  pairs = limit_number_of_labels(pairs)
  pairs = remove_duplicates(pairs)
  pairs.map do |key, value|
    {
      'label_type'  => truncate(key),
      'label_value' => truncate(value.to_s, key)
    }
  end
end

#notify_finished_configuringObject



214
215
216
# File 'lib/one_apm/configuration.rb', line 214

def notify_finished_configuring
  OneApm::Manager.agent.events.notify(:finished_configuring)
end

#num_configs_for_testingObject



422
423
424
# File 'lib/one_apm/configuration.rb', line 422

def num_configs_for_testing
  config_stack.size
end

#parse_labels_from_dictionaryObject

parse hash of labels delete key eql ‘labels.xxx.notified’



378
379
380
381
382
# File 'lib/one_apm/configuration.rb', line 378

def parse_labels_from_dictionary
  labels = OneApm::Manager.config[:labels]
  labels.delete_if{|k, v| k.include?(".notified")}
  make_label_hash(labels)
end

#parse_labels_from_stringObject



299
300
301
302
303
# File 'lib/one_apm/configuration.rb', line 299

def parse_labels_from_string
  labels = OneApm::Manager.config[:labels]
  label_pairs = break_label_string_into_pairs(labels)
  make_label_hash(label_pairs, labels)
end

#parsed_labelsObject



287
288
289
290
291
292
293
294
295
296
297
# File 'lib/one_apm/configuration.rb', line 287

def parsed_labels
  case OneApm::Manager.config[:labels]
  when String
    parse_labels_from_string
  else
    parse_labels_from_dictionary
  end
rescue => e
  OneApm::Manager.logger.error(PARSING_LABELS_FAILURE, e)
  []
end

#register_callback(key, &proc) ⇒ Object



174
175
176
177
# File 'lib/one_apm/configuration.rb', line 174

def register_callback(key, &proc)
  @callbacks[key] << proc
  proc.call(@cache[key])
end

#remove_config(source) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/one_apm/configuration.rb', line 72

def remove_config(source)
  case source
  when HighSecuritySource then @high_security_source = nil
  when EnvironmentSource  then @environment_source   = nil
  when ServerSource       then @server_source        = nil
  when ManualSource       then @manual_source        = nil
  when YamlSource         then @yaml_source          = nil
  when DefaultSource      then @default_source       = nil
  else
    @configs_for_testing.delete_if {|src,lvl| src == source}
  end

  reset_cache
  invoke_callbacks(:remove, source)
  log_config(:remove, source)
end

#remove_config_type(sym) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/one_apm/configuration.rb', line 59

def remove_config_type(sym)
  source = case sym
  when :high_security then @high_security_source
  when :environment   then @environment_source
  when :server        then @server_source
  when :manual        then @manual_source
  when :yaml          then @yaml_source
  when :default       then @default_source
  end

  remove_config(source)
end

#remove_duplicates(pairs) ⇒ Object

We only take the last value provided for a given label type key



371
372
373
374
# File 'lib/one_apm/configuration.rb', line 371

def remove_duplicates(pairs)
  grouped_by_type = pairs.group_by(&:first)
  grouped_by_type.values.map(&:last)
end

#replace_or_add_config(source) ⇒ Object



89
90
91
92
93
94
# File 'lib/one_apm/configuration.rb', line 89

def replace_or_add_config source
  configure(source) do 
    invoke_callbacks(:add, source)
    :add
  end
end

#reset_cacheObject



398
399
400
# File 'lib/one_apm/configuration.rb', line 398

def reset_cache
  @cache = Hash.new {|hash,key| hash[key] = self.fetch(key) }
end

#reset_to_defaultsObject

Generally only useful during initial construction and tests



385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/one_apm/configuration.rb', line 385

def reset_to_defaults
  @high_security_source = nil
  @environment_source   = EnvironmentSource.new
  @server_source        = nil
  @manual_source        = nil
  @yaml_source          = nil
  @default_source       = DefaultSource.new

  @configs_for_testing  = []

  reset_cache
end

#source(key) ⇒ Object



122
123
124
125
126
127
128
# File 'lib/one_apm/configuration.rb', line 122

def source(key)
  config_stack.each do |config|
    if config.respond_to?(key.to_sym) || config.has_key?(key.to_sym)
      return config
    end
  end
end

#tier_namesObject



273
274
275
276
277
278
279
# File 'lib/one_apm/configuration.rb', line 273

def tier_names
  case OneApm::Manager.config[:tier_name]
  when Array then OneApm::Manager.config[:tier_name]
  when String then OneApm::Manager.config[:tier_name].split(';')
  else []
  end
end

#to_collector_hashObject



245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/one_apm/configuration.rb', line 245

def to_collector_hash
  OneApm::Support::DottedHash.new(apply_mask(flattened)).to_hash.delete_if do |k, v|
    default = DEFAULTS[k]
    if default
      default[:local_only]
    else
      # In our tests, we add totally bogus configs, because testing.
      # In those cases, there will be no default. So we'll just let
      # them through.
      false
    end
  end
end

#to_notified_hashObject



259
260
261
262
263
264
265
266
267
# File 'lib/one_apm/configuration.rb', line 259

def to_notified_hash
  @notified_hash = {}
  to_collector_hash.each{|k, v| @notified_hash[k]= v.to_s}
  return @notified_hash unless OneApm::Manager.config[:'notified.enable']
  @notified_hash.select do |k, v|
    default = DEFAULTS[k]
    OneApm::Manager.config[:"#{k}.notified"] || (default && default.fetch(:notified, false))
  end
end

#transform_from_default(key) ⇒ Object



170
171
172
# File 'lib/one_apm/configuration.rb', line 170

def transform_from_default(key)
  ::OneApm::Configuration::DefaultSource.transform_for(key)
end

#truncate(text, key = nil) ⇒ Object



347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'lib/one_apm/configuration.rb', line 347

def truncate(text, key=nil)
  if text.length > MAX_LABEL_LENGTH
    if key
      msg = "The value for the label '#{key}' is longer than the allowed #{MAX_LABEL_LENGTH} and will be truncated. Value = '#{text}'"
    else
      msg = "Label name longer than the allowed #{MAX_LABEL_LENGTH} will be truncated. Name = '#{text}'"
    end
    OneApm::Manager.logger.warn(msg)
    text[0..MAX_LABEL_LENGTH-1]
  else
    text
  end
end

#update_config(source) ⇒ Object



96
97
98
99
100
101
# File 'lib/one_apm/configuration.rb', line 96

def update_config source
  configure(source) do 
    _invoke_callbacks_(source)
    :update
  end
end

#valid_label_item?(item) ⇒ Boolean

Returns:



318
319
320
321
322
323
324
325
326
# File 'lib/one_apm/configuration.rb', line 318

def valid_label_item?(item)
  case item
  when String  then !item.empty?
  when Numeric then true
  when true    then true
  when false   then true
  else false
  end
end

#valid_label_pairs?(label_pairs) ⇒ Boolean

Returns:



312
313
314
315
316
# File 'lib/one_apm/configuration.rb', line 312

def valid_label_pairs?(label_pairs)
  label_pairs.all? do |pair|
    pair.length == 2 && valid_label_item?(pair.first) && valid_label_item?(pair.last)
  end
end