Class: Logging::Layout

Inherits:
Object
  • Object
show all
Defined in:
lib/logging/layout.rb

Overview

The Layout class provides methods for formatting log events into a string representation. Layouts are used by Appenders to format log events before writing them to the logging destination.

All other Layouts inherit from this class which provides stub methods. Each subclass should provide a format method. A layout can be used by more than one Appender so all the methods need to be thread safe.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Layout

call-seq:

Layout.new( :format_as => :string )

Creates a new layout that will format objects as strings using the given :format_as style. This can be one of :string, :inspect, or :yaml. These formatting commands map to the following object methods:

  • :string => to_s

  • :inspect => inspect

  • :yaml => to_yaml

  • :json => MultiJson.encode(obj)

If the format is not specified then the global object format is used (see Logging#format_as). If the global object format is not specified then :string is used.


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/logging/layout.rb', line 31

def initialize( opts = {} )
  ::Logging.init unless ::Logging.initialized?

  default = ::Logging.const_defined?('OBJ_FORMAT') ?
            ::Logging::OBJ_FORMAT : nil

  f = opts.fetch(:format_as, default)
  f = f.intern if f.instance_of? String

  @obj_format = case f
                when :inspect, :yaml, :json; f
                else :string end

  self.backtrace   = opts.fetch(:backtrace,   ::Logging.backtrace)
  self.utc_offset  = opts.fetch(:utc_offset,  ::Logging.utc_offset)
  self.cause_depth = opts.fetch(:cause_depth, ::Logging.cause_depth)
end

Instance Attribute Details

#backtraceObject Also known as: backtrace?

Returns the backtrace setting.


65
66
67
# File 'lib/logging/layout.rb', line 65

def backtrace
  @backtrace
end

#cause_depthObject

Returns the exception cause depth formatting limit.


105
106
107
# File 'lib/logging/layout.rb', line 105

def cause_depth
  @cause_depth
end

#utc_offsetObject

Returns the UTC offset.


91
92
93
# File 'lib/logging/layout.rb', line 91

def utc_offset
  @utc_offset
end

Instance Method Details

#apply_utc_offset(time) ⇒ Object

Internal: Helper method that applies the UTC offset to the given `time` instance. A new Time is returned that is equivalent to the original `time` but pinned to the timezone given by the UTC offset.

If a UTC offset has not been set, then the original `time` instance is returned unchanged.


114
115
116
117
118
119
120
121
122
123
124
# File 'lib/logging/layout.rb', line 114

def apply_utc_offset( time )
  return time if utc_offset.nil?

  time = time.dup
  if utc_offset == 0
    time.utc
  else
    time.localtime(utc_offset)
  end
  time
end

call-seq:

footer

Returns a footer string to be used at the end of a logging appender.


147
# File 'lib/logging/layout.rb', line 147

def footer( ) '' end

#format(event) ⇒ Object

call-seq:

format( event )

Returns a string representation of the given logging event. It is up to subclasses to implement this method.


132
# File 'lib/logging/layout.rb', line 132

def format( event ) nil end

#format_cause(e, lines) ⇒ Object

Internal: Format any nested exceptions found in the given exception `e` while respecting the maximum `cause_depth`. The lines array is used to capture all the output lines form the nested exceptions; the array is later joined by the `format_obj` method.

e - Exception to format lines - Array of output lines

Returns the input `lines` Array


185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/logging/layout.rb', line 185

def format_cause(e, lines)
  return lines if cause_depth == 0

  cause_depth.times do
    break unless e.respond_to?(:cause) && e.cause

    cause = e.cause
    lines << "--- Caused by ---"
    lines << "<#{cause.class.name}> #{cause.message}"
    lines.concat(format_cause_backtrace(e, cause)) if backtrace? && cause.backtrace

    e = cause
  end

  if e.respond_to?(:cause) && e.cause
    lines << "--- Further #cause backtraces were omitted ---"
  end

  lines
end

#format_cause_backtrace(e, cause) ⇒ Object

Internal: Format the backtrace of the nested `cause` but remove the common exception lines from the parent exception. This helps keep the backtraces a wee bit shorter and more comprehensible.

e - parent exception cause - the nested exception generating the returned backtrace

Returns an Array of backtracke lines.


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/logging/layout.rb', line 214

def format_cause_backtrace(e, cause)
  # Find where the cause's backtrace differs from the parent exception's.
  backtrace       = Array(e.backtrace)
  cause_backtrace = Array(cause.backtrace)
  index = -1
  min_index = [backtrace.size, cause_backtrace.size].min * -1
  just_in_case = -5000

  while index > min_index && backtrace[index] == cause_backtrace[index] && index >= just_in_case
    index -= 1
  end

  # Add on a few common frames to make it clear where the backtraces line up.
  index += 3
  index = -1 if index >= 0

  cause_backtrace[0..index]
end

#format_obj(obj) ⇒ Object

call-seq:

format_obj( obj )

Return a string representation of the given object. Depending upon the configuration of the logger system the format will be an inspect based representation or a yaml based representation.


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/logging/layout.rb', line 156

def format_obj( obj )
  case obj
  when String; obj
  when Exception
    lines = ["<#{obj.class.name}> #{obj.message}"]
    lines.concat(obj.backtrace) if backtrace? && obj.backtrace
    format_cause(obj, lines)
    lines.join("\n\t")
  when nil; "<#{obj.class.name}> nil"
  else
    str = "<#{obj.class.name}> "
    str << case @obj_format
           when :inspect; obj.inspect
           when :yaml; try_yaml(obj)
           when :json; try_json(obj)
           else obj.to_s end
    str
  end
end

#headerObject

call-seq:

header

Returns a header string to be used at the beginning of a logging appender.


140
# File 'lib/logging/layout.rb', line 140

def header( ) '' end

#try_json(obj) ⇒ Object

Attempt to format the given object as a JSON string, but fall back to inspect formatting if JSON encoding fails.

obj - The Object to format.

Returns a String representation of the object.


254
255
256
257
258
# File 'lib/logging/layout.rb', line 254

def try_json( obj )
  MultiJson.encode(obj)
rescue StandardError
  obj.inspect
end

#try_yaml(obj) ⇒ Object

Attempt to format the obj using yaml, but fall back to inspect style formatting if yaml fails.

obj - The Object to format.

Returns a String representation of the object.


241
242
243
244
245
# File 'lib/logging/layout.rb', line 241

def try_yaml( obj )
  "\n#{obj.to_yaml}"
rescue TypeError
  obj.inspect
end