class L2meter::Emitter

Constants

BARE_VALUE_SENTINEL
NL
SPACE

Attributes

configuration[R]

Public Class Methods

new(configuration: Configuration.new) click to toggle source
# File lib/l2meter/emitter.rb, line 9
def initialize(configuration: Configuration.new)
  @configuration = configuration
end

Public Instance Methods

batch() { || ... } click to toggle source
# File lib/l2meter/emitter.rb, line 57
def batch
  old_state = in_batch?
  in_batch!
  yield
ensure
  reset_in_batch(old_state)
  write
end
clone() click to toggle source
# File lib/l2meter/emitter.rb, line 82
def clone
  original_contexts = dynamic_contexts
  original_output = output
  self.class.new(configuration: configuration).tap do |clone|
    clone.instance_eval do
      dynamic_contexts.concat(original_contexts)
      set_output original_output
    end
  end
end
context(*context_data, &block) click to toggle source
# File lib/l2meter/emitter.rb, line 23
def context(*context_data, &block)
  if block
    wrap_context(context_data, &block)
  else
    contexted(context_data)
  end
end
count(metric, value = 1) click to toggle source
# File lib/l2meter/emitter.rb, line 74
def count(metric, value = 1)
  log_with_prefix(:count, metric, value)
end
log(*args, &block) click to toggle source
# File lib/l2meter/emitter.rb, line 13
def log(*args, &block)
  merge!(current_context, *args)

  if block
    wrap(&block)
  else
    write
  end
end
measure(metric, value, **args) click to toggle source
# File lib/l2meter/emitter.rb, line 66
def measure(metric, value, **args)
  log_with_prefix(:measure, metric, value, **args)
end
sample(metric, value, **args) click to toggle source
# File lib/l2meter/emitter.rb, line 70
def sample(metric, value, **args)
  log_with_prefix(:sample, metric, value, **args)
end
silence(&block) click to toggle source
# File lib/l2meter/emitter.rb, line 37
def silence(&block)
  with_output(NullOutput.new, &block)
end
silence!() click to toggle source
# File lib/l2meter/emitter.rb, line 41
def silence!
  set_output(NullOutput.new)
end
unique(metric, value) click to toggle source
# File lib/l2meter/emitter.rb, line 78
def unique(metric, value)
  log_with_prefix(:unique, metric, value)
end
unsilence!() click to toggle source
# File lib/l2meter/emitter.rb, line 45
def unsilence!
  set_output(nil)
end
with_elapsed() { || ... } click to toggle source
# File lib/l2meter/emitter.rb, line 31
def with_elapsed
  context elapsed: elapse do
    yield
  end
end
with_output(new_output) { || ... } click to toggle source
# File lib/l2meter/emitter.rb, line 49
def with_output(new_output)
  old_output = output
  set_output(new_output)
  yield
ensure
  set_output(old_output)
end

Private Instance Methods

buffer() click to toggle source
# File lib/l2meter/emitter.rb, line 282
def buffer
  thread_state[:buffer] ||= {}
end
build_token(key, value) click to toggle source
# File lib/l2meter/emitter.rb, line 191
def build_token(key, value)
  case value
  when Proc
    build_token(key, value.call)
  else
    value = scrub_value(key, value)
    format_token(key, value)
  end
end
capture() { || ... } click to toggle source
# File lib/l2meter/emitter.rb, line 124
def capture
  [yield, nil]
rescue Object => exception
  [nil, exception]
end
contexted(context_data) click to toggle source
# File lib/l2meter/emitter.rb, line 137
def contexted(context_data)
  clone.instance_eval do
    dynamic_contexts.concat(context_data)
    self
  end
end
current_context() click to toggle source
# File lib/l2meter/emitter.rb, line 152
def current_context
  unwrap(resolved_contexts)
end
current_contexts() click to toggle source
# File lib/l2meter/emitter.rb, line 156
def current_contexts
  [
    source_context,
    configuration.context,
    *dynamic_contexts
  ].compact
end
dynamic_contexts() click to toggle source
# File lib/l2meter/emitter.rb, line 286
def dynamic_contexts
  thread_state[:dynamic_contexts] ||= []
end
elapse(since = Time.now) click to toggle source
# File lib/l2meter/emitter.rb, line 100
def elapse(since = Time.now)
  -> { Time.now - since }
end
fire!() click to toggle source
# File lib/l2meter/emitter.rb, line 172
def fire!
  tokens = buffer.map { |k, v| build_token(k, v) }.compact
  tokens.sort! if configuration.sort?
  return if tokens.empty?
  output.print(tokens.join(SPACE) << NL)
ensure
  buffer.clear
end
format_float_value(value) click to toggle source
# File lib/l2meter/emitter.rb, line 236
def format_float_value(value)
  format = "%.#{configuration.float_precision}f"
  sprintf(format, value)
end
format_key(key) click to toggle source
# File lib/l2meter/emitter.rb, line 254
def format_key(key)
  configuration.key_formatter.call(key)
end
format_string_value(value) click to toggle source
# File lib/l2meter/emitter.rb, line 241
def format_string_value(value)
  /[^\w,.:@\-\]\[]/.match?(value) ?
    value.strip.gsub(/\s+/, " ").inspect :
    value.to_s
end
format_time_value(value) click to toggle source
# File lib/l2meter/emitter.rb, line 232
def format_time_value(value)
  value.iso8601
end
format_token(key, value) click to toggle source
# File lib/l2meter/emitter.rb, line 201
def format_token(key, value)
  case
  when value == true && configuration.compact_values?
    key
  when !value && configuration.compact_values?
    nil
  when value == BARE_VALUE_SENTINEL
    key
  else
    value = format_value(value)
    "#{key}=#{value}"
  end
end
format_value(value) click to toggle source
# File lib/l2meter/emitter.rb, line 215
def format_value(value)
  case value
  when Float
    format_float_value(value)
  when String
    format_string_value(value)
  when Time
    format_time_value(value)
  when Array
    value.map(&method(:format_value)).join(",")
  when nil
    "null"
  else
    format_value(value.to_s)
  end
end
in_batch!() click to toggle source
# File lib/l2meter/emitter.rb, line 302
def in_batch!
  reset_in_batch(true)
end
in_batch?() click to toggle source
# File lib/l2meter/emitter.rb, line 298
def in_batch?
  !!thread_state[:in_batch]
end
log_with_prefix(method, key, value, unit: nil) click to toggle source
# File lib/l2meter/emitter.rb, line 95
def log_with_prefix(method, key, value, unit: nil)
  key = [configuration.prefix, key, unit].compact.join(".")
  log(Hash["#{method}##{key}", value])
end
merge!(*args) click to toggle source
# File lib/l2meter/emitter.rb, line 247
def merge!(*args)
  unwrap(args.compact).each do |key, value|
    key = format_key(key)
    buffer[key] = value
  end
end
output() click to toggle source
# File lib/l2meter/emitter.rb, line 290
def output
  thread_state[:output] ||= configuration.output
end
reset_in_batch(new_value) click to toggle source
# File lib/l2meter/emitter.rb, line 306
def reset_in_batch(new_value)
  thread_state[:in_batch] = new_value
end
resolved_contexts() click to toggle source
# File lib/l2meter/emitter.rb, line 168
def resolved_contexts
  current_contexts.map { |c| Proc === c ? c.call : c }
end
scrub_value(key, value) click to toggle source
# File lib/l2meter/emitter.rb, line 186
def scrub_value(key, value)
  scrubber = configuration.scrubber
  scrubber ? scrubber.call(key, value) : value
end
set_output(new_output) click to toggle source
# File lib/l2meter/emitter.rb, line 294
def set_output(new_output)
  thread_state[:output] = new_output
end
source_context() click to toggle source
# File lib/l2meter/emitter.rb, line 164
def source_context
  configuration.source ? {source: configuration.source} : {}
end
thread_state() click to toggle source
# File lib/l2meter/emitter.rb, line 270
def thread_state
  @mutex ||= Mutex.new
  @mutex.synchronize do
    @threads ||= {}

    # cleaning up state from dead threads
    @threads.delete_if { |t, _| !t.alive? }

    @threads[Thread.current] ||= {}
  end
end
unwrap(args) click to toggle source
# File lib/l2meter/emitter.rb, line 258
def unwrap(args)
  {}.tap do |result|
    args.each do |arg|
      next if arg.nil?
      arg = Hash[arg, BARE_VALUE_SENTINEL] unless Hash === arg
      arg.each do |key, value|
        result[key] = value
      end
    end
  end
end
unwrap_exception(exception) click to toggle source
# File lib/l2meter/emitter.rb, line 144
def unwrap_exception(exception)
  {
    at: :exception,
    exception: exception.class,
    message: exception.message
  }
end
wrap(&block) click to toggle source
# File lib/l2meter/emitter.rb, line 109
def wrap(&block)
  elapsed = elapse
  cloned_buffer = buffer.clone
  write(at: :start)
  result, exception = capture(&block)
  merge!(cloned_buffer)
  if exception
    write(unwrap_exception(exception), elapsed: elapsed)
    raise(exception)
  else
    write(at: :finish, elapsed: elapsed)
    result
  end
end
wrap_context(context_data) { || ... } click to toggle source
# File lib/l2meter/emitter.rb, line 130
def wrap_context(context_data)
  dynamic_contexts.concat(context_data)
  yield
ensure
  context_data.each { dynamic_contexts.pop }
end
write(*args) click to toggle source
# File lib/l2meter/emitter.rb, line 104
def write(*args)
  merge!(*args)
  fire! unless in_batch?
end