Class: SemanticLogger::Log

Inherits:
Struct
  • Object
show all
Defined in:
lib/semantic_logger/log.rb

Overview

Log Struct

Structure for holding all log entries

level

Log level of the supplied log call
:trace, :debug, :info, :warn, :error, :fatal

thread_name

Name of the thread in which the logging call was called

name

Class name supplied to the logging instance

message

Text message to be logged

payload

Optional Hash or Ruby Exception object to be logged

time

The time at which the log entry was created

duration

The time taken to complete a measure call

tags

Any tags active on the thread when the log call was made

level_index

Internal index of the log level

exception

Ruby Exception object to log

metric [Object]

Object supplied when measure_x was called

backtrace [Array<String>]

The backtrace captured at source when the log level >= SemanticLogger.backtrace_level

metric_amount [Numeric]

Used for numeric or counter metrics.
For example, the number of inquiries or, the amount purchased etc.

Constant Summary collapse

MAX_EXCEPTIONS_TO_UNWRAP =
5
CALLER_REGEXP =
/^(.*):(\d+).*/

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#backtraceObject

Returns the value of attribute backtrace

Returns:

  • (Object)

    the current value of backtrace



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def backtrace
  @backtrace
end

#durationObject

Returns the value of attribute duration

Returns:

  • (Object)

    the current value of duration



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def duration
  @duration
end

#exceptionObject

Returns the value of attribute exception

Returns:

  • (Object)

    the current value of exception



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def exception
  @exception
end

#levelObject

Returns the value of attribute level

Returns:

  • (Object)

    the current value of level



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def level
  @level
end

#level_indexObject

Returns the value of attribute level_index

Returns:

  • (Object)

    the current value of level_index



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def level_index
  @level_index
end

#messageObject

Returns the value of attribute message

Returns:

  • (Object)

    the current value of message



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def message
  @message
end

#metricObject

Returns the value of attribute metric

Returns:

  • (Object)

    the current value of metric



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def metric
  @metric
end

#metric_amountObject

Returns the value of attribute metric_amount

Returns:

  • (Object)

    the current value of metric_amount



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def metric_amount
  @metric_amount
end

#nameObject

Returns the value of attribute name

Returns:

  • (Object)

    the current value of name



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def name
  @name
end

#payloadObject

Returns the value of attribute payload

Returns:

  • (Object)

    the current value of payload



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def payload
  @payload
end

#tagsObject

Returns the value of attribute tags

Returns:

  • (Object)

    the current value of tags



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def tags
  @tags
end

#thread_nameObject

Returns the value of attribute thread_name

Returns:

  • (Object)

    the current value of thread_name



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def thread_name
  @thread_name
end

#timeObject

Returns the value of attribute time

Returns:

  • (Object)

    the current value of time



46
47
48
# File 'lib/semantic_logger/log.rb', line 46

def time
  @time
end

Instance Method Details

#backtrace_to_sObject

Returns [String] the exception backtrace including all of the child / caused by exceptions



72
73
74
75
76
77
78
79
80
81
82
# File 'lib/semantic_logger/log.rb', line 72

def backtrace_to_s
  trace = ''
  each_exception do |exception, i|
    if i == 0
      trace = (exception.backtrace || []).join("\n")
    else
      trace << "\nCause: #{exception.class.name}: #{exception.message}\n#{(exception.backtrace || []).join("\n")}"
    end
  end
  trace
end

#cleansed_messageObject

Strip the standard Rails colorizing from the logged message



148
149
150
# File 'lib/semantic_logger/log.rb', line 148

def cleansed_message
  message.to_s.gsub(/(\e(\[([\d;]*[mz]?))?)?/, '').strip
end

#duration_humanObject

Returns [String] the duration in human readable form



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/semantic_logger/log.rb', line 99

def duration_human
  return nil unless duration
  seconds = duration / 1000
  if seconds >= 86400.0 # 1 day
    "#{(seconds / 86400).to_i}d #{Time.at(seconds).strftime('%-Hh %-Mm')}"
  elsif seconds >= 3600.0 # 1 hour
    Time.at(seconds).strftime('%-Hh %-Mm')
  elsif seconds >= 60.0 # 1 minute
    Time.at(seconds).strftime('%-Mm %-Ss')
  elsif seconds >= 1.0 # 1 second
    "#{'%.3f' % seconds}s"
  else
    duration_to_s
  end
end

#duration_to_sObject



88
89
90
# File 'lib/semantic_logger/log.rb', line 88

def duration_to_s
  "#{duration.to_i}ms" if duration
end

#each_exceptionObject

Call the block for exception and any nested exception



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/semantic_logger/log.rb', line 50

def each_exception
  # With thanks to https://github.com/bugsnag/bugsnag-ruby/blob/6348306e44323eee347896843d16c690cd7c4362/lib/bugsnag/notification.rb#L81
  depth      = 0
  exceptions = []
  ex         = exception
  while ex != nil && !exceptions.include?(ex) && exceptions.length < MAX_EXCEPTIONS_TO_UNWRAP
    exceptions << ex
    yield(ex, depth)

    depth += 1
    ex    =
      if ex.respond_to?(:cause) && ex.cause
        ex.cause
      elsif ex.respond_to?(:continued_exception) && ex.continued_exception
        ex.continued_exception
      elsif ex.respond_to?(:original_exception) && ex.original_exception
        ex.original_exception
      end
  end
end

#extract_file_and_line(stack, short_name = false) ⇒ Object

Extract the filename and line number from the last entry in the supplied backtrace



133
134
135
136
# File 'lib/semantic_logger/log.rb', line 133

def extract_file_and_line(stack, short_name = false)
  match = CALLER_REGEXP.match(stack.first)
  [short_name ? File.basename(match[1]) : match[1], match[2].to_i]
end

#file_name_and_line(short_name = false) ⇒ Object

Returns [String, String] the file_name and line_number from the backtrace supplied in either the backtrace or exception



140
141
142
143
144
145
# File 'lib/semantic_logger/log.rb', line 140

def file_name_and_line(short_name = false)
  if backtrace || (exception && exception.backtrace)
    stack = backtrace || exception.backtrace
    extract_file_and_line(stack, short_name) if stack && stack.size > 0
  end
end

#formatted_timeObject

Return the Time as a formatted string JRuby only supports time in ms DEPRECATED



167
168
169
# File 'lib/semantic_logger/log.rb', line 167

def formatted_time
  "#{time.strftime('%Y-%m-%d %H:%M:%S')}.#{'%03d' % (time.usec/1000)}"
end

#has_payload?Boolean

Returns [true|false] whether the log entry has a payload

Returns:

  • (Boolean)


159
160
161
# File 'lib/semantic_logger/log.rb', line 159

def has_payload?
  !(payload.nil? || (payload.respond_to?(:empty?) && payload.empty?))
end

#level_to_sObject

Returns [String] single character upper case log level



116
117
118
# File 'lib/semantic_logger/log.rb', line 116

def level_to_s
  level.to_s[0..0].upcase
end

#payload_to_sObject

Return the payload in text form Returns nil if payload is missing or empty



154
155
156
# File 'lib/semantic_logger/log.rb', line 154

def payload_to_s
  payload.inspect if has_payload?
end

#process_info(thread_name_length = 30) ⇒ Object

Returns [String] the available process info Example:

18934:thread 23 test_logging.rb:51


123
124
125
126
127
128
# File 'lib/semantic_logger/log.rb', line 123

def process_info(thread_name_length = 30)
  file, line = file_name_and_line(true)
  file_name  = " #{file}:#{line}" if file

  "#{$$}:#{"%.#{thread_name_length}s" % thread_name}#{file_name}"
end

#to_h(host = SemanticLogger.host, application = SemanticLogger.application) ⇒ Object

Returns [Hash] representation of this log entry



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/semantic_logger/log.rb', line 180

def to_h(host = SemanticLogger.host, application = SemanticLogger.application)
  # Header
  h               = {
    name:        name,
    pid:         $$,
    thread:      thread_name,
    time:        time,
    level:       level,
    level_index: level_index,
  }
  h[:host]        = host if host
  h[:application] = application if application
  file, line      = file_name_and_line
  if file
    h[:file] = file
    h[:line] = line.to_i
  end

  # Tags
  h[:tags] = tags if tags && (tags.size > 0)

  # Duration
  if duration
    h[:duration_ms] = duration
    h[:duration]    = duration_human
  end

  # Log message
  h[:message] = cleansed_message if message

  # Payload
  if payload
    if payload.is_a?(Hash)
      h.merge!(payload)
    else
      h[:payload] = payload
    end
  end

  # Exceptions
  if exception
    root = h
    each_exception do |exception, i|
      name       = i == 0 ? :exception : :cause
      root[name] = {
        name:        exception.class.name,
        message:     exception.message,
        stack_trace: exception.backtrace
      }
      root       = root[name]
    end
  end

  # Metric
  h[:metric] = metric if metric
  h
end