class Lumberjack::JsonDevice

This Lumberjack device logs output to another device as JSON formatted text with one document per line.

The mapping parameter can be used to define the JSON data structure. To define the structure pass in a hash with key indicating the log entry field and the value indicating the JSON document key.

The standard entry fields are mapped with the following keys:

Any additional keys will be pulled from the tags. If any of the standard keys are missing or have a nil mapping, the entry field will not be included in the JSON output.

You can create a nested JSON structure by specifying an array as the JSON key.

Constants

DEFAULT_MAPPING
DEFAULT_TIME_FORMAT

Attributes

formatter[RW]
mapping[R]

Public Class Methods

new(stream_or_device, mapping: DEFAULT_MAPPING, formatter: nil, datetime_format: nil) click to toggle source
# File lib/lumberjack_json_device.rb, line 42
def initialize(stream_or_device, mapping: DEFAULT_MAPPING, formatter: nil, datetime_format: nil)
  @mutex = Mutex.new

  if stream_or_device.is_a?(Device)
    @device = stream_or_device
  else
    @device = Writer.new(stream_or_device)
  end

  self.mapping = mapping

  if formatter
    @formatter = formatter
  else
    @formatter = default_formatter
    datetime_format = DEFAULT_TIME_FORMAT if datetime_format.nil?
  end
  add_datetime_formatter!(datetime_format) unless datetime_format.nil?
end

Public Instance Methods

datetime_format() click to toggle source
# File lib/lumberjack_json_device.rb, line 73
def datetime_format
  @datetime_format
end
datetime_format=(format) click to toggle source

Set the datetime format for the log timestamp.

# File lib/lumberjack_json_device.rb, line 78
def datetime_format=(format)
  add_datetime_formatter!(format)
end
entry_as_json(entry) click to toggle source

Convert a Lumberjack::LogEntry to a Hash using the specified field mapping.

# File lib/lumberjack_json_device.rb, line 115
def entry_as_json(entry)
  data = {}
  set_attribute(data, @time_key, entry.time) unless @time_key.nil?
  set_attribute(data, @severity_key, entry.severity_label) unless @severity_key.nil?
  set_attribute(data, @progname_key, entry.progname) unless @progname_key.nil?
  set_attribute(data, @pid_key, entry.pid) unless @pid_key.nil?
  set_attribute(data, @message_key, entry.message) unless @message_key.nil?

  tags = entry.tags
  if @custom_keys.size > 0
    tags = (tags.nil? ? {} : tags.dup)
    @custom_keys.each do |name, key|
      set_attribute(data, key, tags.delete(name.to_s))
    end
  end

  unless @tags_key.nil?
    tags ||= {}
    set_attribute(data, @tags_key, tags)
  end

  data = @formatter.format(data) if @formatter
  data
end
flush() click to toggle source
# File lib/lumberjack_json_device.rb, line 69
def flush
  @device.flush
end
map(field_mapping) click to toggle source
# File lib/lumberjack_json_device.rb, line 106
def map(field_mapping)
  new_mapping = {}
  field_mapping.each do |key, value|
    new_mapping[key.to_sym] = value
  end
  self.mapping = mapping.merge(new_mapping)
end
mapping=(mapping) click to toggle source

Set the mapping for how to map an entry to a JSON object.

# File lib/lumberjack_json_device.rb, line 83
def mapping=(mapping)
  @mutex.synchronize do
    keys = {}
    mapping.each do |key, value|
      if value == true
        value = key.to_s.split(".")
        value = value.first if value.size == 1
      end
      keys[key.to_sym] = value if value
    end

    @time_key = keys.delete(:time)
    @severity_key = keys.delete(:severity)
    @progname_key = keys.delete(:progname)
    @pid_key = keys.delete(:pid)
    @message_key = keys.delete(:message)
    @tags_key = keys.delete(:tags)
    @custom_keys = keys
    @mapping = mapping
  end
  nil
end
write(entry) click to toggle source
# File lib/lumberjack_json_device.rb, line 62
def write(entry)
  return if entry.message.nil? || entry.message == ""
  data = entry_as_json(entry)
  json = MultiJson.dump(data)
  @device.write(json)
end

Private Instance Methods

add_datetime_formatter!(datetime_format) click to toggle source
# File lib/lumberjack_json_device.rb, line 177
def add_datetime_formatter!(datetime_format)
  if datetime_format
    @datetime_format = datetime_format
    time_formatter = Lumberjack::Formatter::DateTimeFormatter.new(datetime_format)
    formatter.add(Time, time_formatter)
    formatter.add(Date, time_formatter)
  else
    @datetime_format = nil
    formatter.remove(Time)
    formatter.remove(Date)
  end
end
deep_merge!(hash, other_hash, &block) click to toggle source
# File lib/lumberjack_json_device.rb, line 190
def deep_merge!(hash, other_hash, &block)
  hash.merge!(other_hash) do |key, this_val, other_val|
    if this_val.is_a?(Hash) && other_val.is_a?(Hash)
      deep_merge!(this_val, other_val, &block)
    elsif block_given?
      block.call(key, this_val, other_val)
    else
      other_val
    end
  end
end
default_formatter() click to toggle source
# File lib/lumberjack_json_device.rb, line 168
def default_formatter
  formatter = Formatter.new.clear
  object_formatter = Lumberjack::Formatter::ObjectFormatter.new
  formatter.add(String, object_formatter)
  formatter.add(Object, object_formatter)
  formatter.add(Enumerable, Formatter::StructuredFormatter.new(formatter))
  formatter
end
set_attribute(data, key, value) click to toggle source
# File lib/lumberjack_json_device.rb, line 142
def set_attribute(data, key, value)
  return if value.nil?

  if (value.is_a?(Time) || value.is_a?(DateTime)) && @time_formatter
    value = @time_formatter.call(value)
  end

  if key.is_a?(Array)
    unless key.empty?
      if key.size == 1
        data[key.first] = value
      else
        data[key.first] ||= {}
        set_attribute(data[key.first], key[1, key.size], value)
      end
    end
  elsif key.respond_to?(:call)
    hash = key.call(value)
    if hash.is_a?(Hash)
      deep_merge!(data, Lumberjack::Tags.stringify_keys(hash))
    end
  else
    data[key] = value unless key.nil?
  end
end