module Logging
# 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.
#
class 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.
#
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
b = opts.fetch(:backtrace, ::Logging.backtrace)
@backtrace = case b
when :on, 'on', true; true
when :off, 'off', false; false
else
raise ArgumentError, "backtrace must be true or false"
end
end
# call-seq:
# format( event )
#
# Returns a string representation of the given logging _event_. It is
# up to subclasses to implement this method.
#
def format( event ) nil end
# call-seq:
# header
#
# Returns a header string to be used at the beginning of a logging
# appender.
#
def header( ) '' end
# call-seq:
# footer
#
# Returns a footer string to be used at the end of a logging appender.
#
def footer( ) '' end
# 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.
#
def format_obj( obj )
case obj
when String; obj
when Exception
str = "<#{obj.class.name}> #{obj.message}"
if @backtrace && !obj.backtrace.nil?
str << "\n\t" << obj.backtrace.join("\n\t")
end
str
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
# 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.
#
def try_yaml( obj )
"\n#{obj.to_yaml}"
rescue TypeError
obj.inspect
end
# 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.
#
def try_json( obj )
MultiJson.encode(obj)
rescue StandardError
obj.inspect
end
end # class Layout
end # module Logging