Class: Timber::LogEntry

Inherits:
Object
  • Object
show all
Defined in:
lib/timber/log_entry.rb

Overview

Represents a new log entry into the log. This is an intermediary class between ‘Logger` and the log device that you set it up with.

Constant Summary collapse

BINARY_LIMIT_THRESHOLD =

:nodoc:

1_000.freeze
DT_PRECISION =
6.freeze
MESSAGE_MAX_BYTES =
8192.freeze
SCHEMA =
"https://raw.githubusercontent.com/timberio/log-event-json-schema/v3.2.0/schema.json".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(level, time, progname, message, context_snapshot, event, options = {}) ⇒ LogEntry

Creates a log entry suitable to be sent to the Timber API.

Parameters:

  • level (Integer)

    the log level / severity

  • time (Time)

    the exact time the log message was written

  • progname (String)

    the progname scope for the log message

  • message (String)

    Human readable log message.

  • context_snapshot (Hash)

    structured data representing a snapshot of the context at the given point in time.

  • event (Timber.Event)

    structured data representing the log line event. This should be an instance of Event.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/timber/log_entry.rb', line 28

def initialize(level, time, progname, message, context_snapshot, event, options = {})
  @level = level
  @time = time.utc
  @progname = progname

  # If the message is not a string we call inspect to ensure it is a string.
  # This follows the default behavior set by ::Logger
  # See: https://github.com/ruby/ruby/blob/trunk/lib/logger.rb#L615
  @message = message.is_a?(String) ? message : message.inspect
  @message = @message.byteslice(0, MESSAGE_MAX_BYTES)
  @tags = options[:tags]
  @time_ms = options[:time_ms]
  @context_snapshot = context_snapshot
  @event = event
end

Instance Attribute Details

#context_snapshotObject (readonly)

Returns the value of attribute context_snapshot.



16
17
18
# File 'lib/timber/log_entry.rb', line 16

def context_snapshot
  @context_snapshot
end

#eventObject (readonly)

Returns the value of attribute event.



16
17
18
# File 'lib/timber/log_entry.rb', line 16

def event
  @event
end

#levelObject (readonly)

Returns the value of attribute level.



16
17
18
# File 'lib/timber/log_entry.rb', line 16

def level
  @level
end

#messageObject (readonly)

Returns the value of attribute message.



16
17
18
# File 'lib/timber/log_entry.rb', line 16

def message
  @message
end

#prognameObject (readonly)

Returns the value of attribute progname.



16
17
18
# File 'lib/timber/log_entry.rb', line 16

def progname
  @progname
end

#tagsObject (readonly)

Returns the value of attribute tags.



16
17
18
# File 'lib/timber/log_entry.rb', line 16

def tags
  @tags
end

#timeObject (readonly)

Returns the value of attribute time.



16
17
18
# File 'lib/timber/log_entry.rb', line 16

def time
  @time
end

#time_msObject (readonly)

Returns the value of attribute time_ms.



16
17
18
# File 'lib/timber/log_entry.rb', line 16

def time_ms
  @time_ms
end

Instance Method Details

#as_json(options = {}) ⇒ Object

Builds a hash representation containing simple objects, suitable for serialization (JSON).



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/timber/log_entry.rb', line 45

def as_json(options = {})
  options ||= {}
  hash = {
    :level => level,
    :dt => formatted_dt,
    :message => message,
    :tags => tags,
    :time_ms => time_ms
  }

  if !event.nil?
    hash[:event] = event.as_json
  end

  if !context_snapshot.nil? && context_snapshot.length > 0
    hash[:context] = context_snapshot
  end

  hash[:"$schema"] = SCHEMA

  hash = if options[:only]
    hash.select do |key, _value|
      options[:only].include?(key)
    end
  elsif options[:except]
    hash.select do |key, _value|
      !options[:except].include?(key)
    end
  else
    hash
  end

  # Preparing a log event for JSON should remove any blank values. Timber strictly
  # validates incoming data, including message size. Blank values will fail validation.
  # Moreover, binary data (ASCII-8BIT) generally cannot be encoded into JSON because it
  # contains characters outside of the valid UTF-8 space.
  Util::Hash.deep_reduce(hash) do |k, v, h|
    # Discard blank values
    if !v.nil? && (!v.respond_to?(:length) || v.length > 0)
      # If the value is a binary string, give it special treatment
      if v.respond_to?(:encoding) && v.encoding == ::Encoding::ASCII_8BIT
        # Only keep binary values less than a certain size. Sizes larger than this
        # are almost always file uploads and data we do not want to log.
        if v.length < BINARY_LIMIT_THRESHOLD
          # Attempt to safely encode the data to UTF-8
          encoded_value = encode_string(v)
          if !encoded_value.nil?
            h[k] = encoded_value
          end
        end
      else
        # Keep all other values
        h[k] = v
      end
    end
  end
end

#inspectObject



103
104
105
# File 'lib/timber/log_entry.rb', line 103

def inspect
  to_s
end

#to_json(options = {}) ⇒ Object



107
108
109
# File 'lib/timber/log_entry.rb', line 107

def to_json(options = {})
  as_json(options).to_json
end

#to_msgpack(*args) ⇒ Object



111
112
113
# File 'lib/timber/log_entry.rb', line 111

def to_msgpack(*args)
  as_json.to_msgpack(*args)
end

#to_sObject

This is used when LogEntry objects make it to a non-Timber logger.



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/timber/log_entry.rb', line 116

def to_s
  log_message = message

  if !event.nil?
    event_hash = event.as_json
    event_type = event_hash.keys.first

    event_type = if event.is_a?(Events::Custom)
      "#{event_type}.#{event.type}"
    else
      "#{event_type}"
    end

    log_message = "#{message} [#{event_type}]"
  end

  log_message + "\n"
end