class PaulBunyan::JSONFormatter

Constants

DATETIME_FORMAT

Public Instance Methods

add_metadata(metadata) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 8
def add_metadata(metadata)
  current_metadata.merge!(metadata)
end
call(severity, time, progname, msg) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 12
def call(severity, time, progname, msg)
  metadata = current_metadata.merge({
    "ts"       => time.utc.strftime(DATETIME_FORMAT),
    "unix_ts"  => time.to_f,
    "severity" => severity,
    "pid"      => $$,
  })
  metadata['program'] = progname if progname
  metadata['tags'] = current_tags unless current_tags.empty?

  message_data = format_message(msg)

  JSON::generate(merge_metadata_and_message(metadata, message_data)) + "\n"
end
clear_metadata!() click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 27
def clear_metadata!
  current_metadata.clear
end
clear_tags!() click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 31
def clear_tags!
  current_tags.clear
end
current_metadata() click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 35
def current_metadata
  metadata_thread_key = @metadata_thread_key ||=
    "paul_bunyan_logging_metadata:#{self.object_id}"
  Thread.current[metadata_thread_key] ||= {}
end
current_tags() click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 41
def current_tags
  tags_thread_key = @tags_thread_key ||=
    "paul_bunyan_logging_tags:#{self.object_id}"
  Thread.current[tags_thread_key] ||= []
end
datetime_format() click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 52
def datetime_format
  DATETIME_FORMAT
end
datetime_format=(value) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 47
def datetime_format=(value)
  # intentional nop because the whole point of this formatter is
  # to have a consistent machine parsable format :-P
end
pop_tags(count = 1) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 56
def pop_tags(count = 1)
  current_tags.pop(count)
end
push_tags(*tags) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 60
def push_tags(*tags)
  tags.flatten.reject{|t| t.nil? || t.to_s.strip == '' }.tap do |clean_tags|
    current_tags.concat(clean_tags)
  end
end
remove_metadata(metadata) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 66
def remove_metadata(metadata)
  metadata.each { |k, _| current_metadata.delete(k) }
end
tagged(*tags) { || ... } click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 70
def tagged(*tags)
  clean_tags = push_tags(tags)
  yield
ensure
  pop_tags(clean_tags.size)
end
with_metadata(consumer_metadata) { || ... } click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 77
def with_metadata(consumer_metadata)
  add_metadata(consumer_metadata)
  yield
ensure
  remove_metadata(consumer_metadata)
end

Private Instance Methods

format_exception(exception) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 98
def format_exception(exception)
  {
    'exception.class' => exception.class.to_s,
    'exception.backtrace' => exception.backtrace,
    'exception.message' => exception.message
  }.tap do |exception_hash|
    exception_hash['exception.cause'] = format_exception_cause(exception.cause) if exception.cause
  end
end
format_exception_cause(cause) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 108
def format_exception_cause(cause)
  return format_exception(cause) if cause.is_a?(Exception)

  if cause.respond_to?(:to_str)
    cause.to_str
  elsif cause.respond_to?(:to_s)
    cause.to_s
  else
    cause.inspect
  end
end
format_generic_object(object) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 124
def format_generic_object(object)
  if object.respond_to?(:to_h)
    object.to_h
  elsif object.respond_to?(:to_hash)
    object.to_hash
  else
    format_string(object.inspect)
  end
end
format_message(message) click to toggle source

TODO: extract all of this formatting/merging out into another class if it grows

# File lib/paul_bunyan/json_formatter.rb, line 87
def format_message(message)
  case message
  when Exception
    format_exception(message)
  when String
    format_string(message)
  else
    format_generic_object(message)
  end
end
format_string(message) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 120
def format_string(message)
  { 'message' => PaulBunyan.strip_ansi(message) }
end
merge_metadata_and_message(metadata, message) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 134
def merge_metadata_and_message(metadata, message)
  clean_message = sanitize_message_keys(message, metadata.keys)
  metadata.merge(clean_message)
end
sanitize_message_keys(message, metadata_keys) click to toggle source
# File lib/paul_bunyan/json_formatter.rb, line 139
def sanitize_message_keys(message, metadata_keys)
  message.inject({}) { |clean, (key, value)|
    key = key.to_s
    if metadata_keys.include?(key)
      clean["user.#{ key }"] = value
    else
      clean[key] = value
    end
    clean
  }
end