Class: Lumberjack::JsonDevice

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

Overview

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:

  • :time

  • :severity

  • :progname

  • :pid

  • :message

  • :tags

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.

Constant Summary collapse

DEFAULT_MAPPING =
{
  time: true,
  severity: true,
  progname: true,
  pid: true,
  message: true,
  tags: true
}.freeze
DEFAULT_TIME_FORMAT =
"%Y-%m-%dT%H:%M:%S.%6N%z"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(stream_or_device, mapping: DEFAULT_MAPPING, formatter: nil, datetime_format: nil, post_processor: nil, pretty: false) ⇒ JsonDevice

Returns a new instance of JsonDevice.

Parameters:

  • stream_or_device (IO, Lumberjack::Device)

    The output stream or Lumberjack device to write the JSON formatted log entries to.

  • mapping (Hash) (defaults to: DEFAULT_MAPPING)

    A hash where the key is the log entry field name and the value indicates how to map the field if it exists. If the value is ‘true`, the field will be mapped to the same name. If the value is an array, it will be mapped to a nested structure that follows the array elements. If the value is a callable object, it will be called with the value and is expected to return a hash that will be merged into the JSON document. If the value is `false`, the field will not be included in the JSON output.

  • formatter (Lumberjack::Formatter) (defaults to: nil)

    An optional formatter to use for formatting the log entry data.

  • datetime_format (String) (defaults to: nil)

    An optional datetime format string to use for formatting the log timestamp.

  • post_processor (Proc) (defaults to: nil)

    An optional callable object that will be called with the log entry hash before it is written to the output stream. This can be used to modify the log entry data before it is serialized to JSON.

  • pretty (Boolean) (defaults to: false)

    If true, the output will be formatted as pretty JSON with indentation and newlines. The default is false, which writes each log entry as a single line JSON document.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/lumberjack_json_device.rb', line 57

def initialize(stream_or_device, mapping: DEFAULT_MAPPING, formatter: nil, datetime_format: nil, post_processor: nil, pretty: false)
  @mutex = Mutex.new

  @device = if stream_or_device.is_a?(Device)
    stream_or_device
  else
    Lumberjack::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?

  @post_processor = post_processor

  @pretty = !!pretty
end

Instance Attribute Details

#datetime_formatObject

Returns the value of attribute datetime_format.



93
94
95
# File 'lib/lumberjack_json_device.rb', line 93

def datetime_format
  @datetime_format
end

#formatterObject

Returns the value of attribute formatter.



37
38
39
# File 'lib/lumberjack_json_device.rb', line 37

def formatter
  @formatter
end

#mappingObject

Returns the value of attribute mapping.



40
41
42
# File 'lib/lumberjack_json_device.rb', line 40

def mapping
  @mapping
end

#post_processorObject

Returns the value of attribute post_processor.



38
39
40
# File 'lib/lumberjack_json_device.rb', line 38

def post_processor
  @post_processor
end

#pretty=(value) ⇒ Object (writeonly)

Sets the attribute pretty

Parameters:

  • value

    the value to set the attribute pretty to.



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

def pretty=(value)
  @pretty = value
end

Instance Method Details

#entry_as_json(entry) ⇒ Hash

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

Parameters:

  • entry (Lumberjack::LogEntry)

    The log entry to convert.

Returns:

  • (Hash)

    A hash representing the log entry in JSON format.



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/lumberjack_json_device.rb', line 159

def entry_as_json(entry)
  data = {}
  set_attribute(data, @time_key, entry.time) if @time_key
  set_attribute(data, @severity_key, entry.severity_label) if @severity_key
  set_attribute(data, @message_key, entry.message) if @message_key
  set_attribute(data, @progname_key, entry.progname) if @progname_key
  set_attribute(data, @pid_key, entry.pid) if @pid_key

  tags = Lumberjack::Utils.expand_tags(entry.tags) if entry.tags
  extracted_tags = nil
  if @custom_keys.size > 0 && !tags&.empty?
    extracted_tags = []
    @custom_keys.each do |name, key|
      set_attribute(data, key, tag_value(tags, name))
      extracted_tags << name
    end

    extracted_tags.each do |path|
      tags = deep_remove_tag(tags, path, entry.tags)
    end
  end

  if @tags_key
    tags ||= {}
    if @tags_key == "*"
      data = tags.merge(data) unless tags.empty?
    else
      set_attribute(data, @tags_key, tags)
    end
  end

  data = @formatter.format(data) if @formatter
  if @post_processor
    processed_result = @post_processor.call(data)
    data = processed_result if processed_result.is_a?(Hash)
  end

  data
end

#flushObject



89
90
91
# File 'lib/lumberjack_json_device.rb', line 89

def flush
  @device.flush
end

#map(field_mapping) ⇒ void

This method returns an undefined value.

Add a field mapping to the existing mappings.

Parameters:

  • field_mapping (Hash)

    A hash where the key is the log entry field name and the value is the JSON key. If the value is ‘true`, the field will be mapped to the same name If the value is an array, it will be mapped to a nested structure. If the value is a callable object, it will be called with the value and should return a hash that will be merged into the JSON document. If the value is `false`, the field will not be included in the JSON output.



150
151
152
153
# File 'lib/lumberjack_json_device.rb', line 150

def map(field_mapping)
  new_mapping = field_mapping.transform_keys(&:to_sym)
  self.mapping = mapping.merge(new_mapping)
end

#pretty?Boolean

Return true if the output is written in a multi-line pretty format. The default is to write each log entry as a single line JSON document.

Returns:

  • (Boolean)


106
107
108
# File 'lib/lumberjack_json_device.rb', line 106

def pretty?
  !!@pretty
end

#write(entry) ⇒ Object



81
82
83
84
85
86
87
# File 'lib/lumberjack_json_device.rb', line 81

def write(entry)
  return if entry.empty?

  data = entry_as_json(entry)
  json = @pretty ? JSON.pretty_generate(data) : JSON.generate(data)
  @device.write(json)
end