Class: Log4r::PatternFormatter

Inherits:
BasicFormatter show all
Defined in:
lib/log4r/formatter/patternformatter.rb

Overview

See log4r/formatter/patternformatter.rb

Constant Summary collapse

DirectiveTable =

Arguments to sprintf keyed to directive letters
%c - event short name
%C - event fullname
%d - date
%g - Global Diagnostic Context (GDC)
%t - trace
%m - message
%h - thread name
%p - process ID aka PID
%M - formatted message
%l - Level in string form
%x - Nested Diagnostic Context (NDC)
%X - Mapped Diagnostic Context (MDC), syntax is “%Xkey”
%% - Insert a %

{
  "c" => 'event.name',
  "C" => 'event.fullname',
  "d" => 'format_date',
  "g" => 'Log4r::GDC.get()',
  "t" => '(event.tracer.nil? ? "no trace" : event.tracer[0])',
  "T" => '(event.tracer.nil? ? "no trace" : event.tracer[0].split(File::SEPARATOR)[-1])',
  "m" => 'event.data',
  "h" => '(Thread.current[:name] or Thread.current.to_s)',
  "p" => 'Process.pid.to_s',
  "M" => 'format_object(event.data)',
  "l" => 'LNAMES[event.level]',
  "x" => 'Log4r::NDC.get()',
  "X" => 'Log4r::MDC.get("DTR_REPLACE")',
  "%" => '"%"'
}
DirectiveRegexp =

Matches the first directive encountered and the stuff around it.

  • $1 is the stuff before directive or “” if not applicable

  • $2 is the directive group or nil if there’s none

  • $3 is the %#.# match within directive group

  • $4 is the .# match which we don’t use (it’s there to match properly)

  • $5 is the directive letter

  • $6 is the stuff after the directive or “” if not applicable

  • $7 is the remainder

/([^%]*)((%-?\d*(\.\d+)?)([cCdgtTmhpMlxX%]))?(\{.+?\})?(.*)/
ISO8601 =

default date format

"%Y-%m-%d %H:%M:%S"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BasicFormatter

#format, #format_object

Methods inherited from SimpleFormatter

#format

Methods inherited from Formatter

#format

Constructor Details

#initialize(hash = {}) ⇒ PatternFormatter

Accepts the following hash arguments (either a string or a symbol):

pattern

A pattern format string.

date_pattern

A Time#strftime format string. See the Ruby Time class for details.

date_method

As an option to date_pattern, specify which Time.now method to call. For example, usec or to_s. Specify it as a String or Symbol.

The default date format is ISO8601, which looks like this:

yyyy-mm-dd hh:mm:ss    =>    2001-01-12 13:15:50


79
80
81
82
83
84
85
86
# File 'lib/log4r/formatter/patternformatter.rb', line 79

def initialize(hash={})
  super(hash)
  @pattern = (hash['pattern'] or hash[:pattern] or nil)
  @date_pattern = (hash['date_pattern'] or hash[:date_pattern] or nil)
  @date_method = (hash['date_method'] or hash[:date_method] or nil)
  @date_pattern = ISO8601 if @date_pattern.nil? and @date_method.nil?
  PatternFormatter.create_format_methods(self)
end

Instance Attribute Details

#date_methodObject (readonly)

Returns the value of attribute date_method.



62
63
64
# File 'lib/log4r/formatter/patternformatter.rb', line 62

def date_method
  @date_method
end

#date_patternObject (readonly)

Returns the value of attribute date_pattern.



62
63
64
# File 'lib/log4r/formatter/patternformatter.rb', line 62

def date_pattern
  @date_pattern
end

#patternObject (readonly)

Returns the value of attribute pattern.



62
63
64
# File 'lib/log4r/formatter/patternformatter.rb', line 62

def pattern
  @pattern
end

Class Method Details

.create_format_methods(pf) ⇒ Object

PatternFormatter works by dynamically defining a format method based on the supplied pattern format. This method contains a call to Kernel#sptrintf with arguments containing the data requested in the pattern format.

How is this magic accomplished? First, we visit each directive and change the %#.# component to %#.#s. The directive letter is then used to cull an appropriate entry from the DirectiveTable for the sprintf argument list. After assembling the method definition, we run module_eval on it, and voila.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/log4r/formatter/patternformatter.rb', line 99

def PatternFormatter.create_format_methods(pf) #:nodoc:
  # first, define the format_date method
  if pf.date_method
    module_eval "def pf.format_date; Time.now.#{pf.date_method}; end"
  else
    module_eval <<-EOS
      def pf.format_date
        Time.now.strftime "#{pf.date_pattern}"
      end
    EOS
  end
  # and now the main format method
  ebuff = "def pf.format(event)\n sprintf(\""
  _pattern = pf.pattern.dup
  args = [] # the args to sprintf which we'll append to ebuff lastly
  while true # work on each match in turn
    match = DirectiveRegexp.match _pattern
    ebuff << match[1] unless match[1].empty?
    break if match[2].nil?
    # deal with the directive by inserting a %#.#s where %#.# is copied
    # directy from the match
    ebuff << match[3] + "s"

	if ( match[5] == 'X' && match[6] != nil ) then

	  # MDC matches, need to be able to handle String, Symbol or Number
	  match6sub = /[\{\}\"]/
	  mdcmatches = match[6].match(/\{(:?)(\d*)(.*)\}/)

	  if ( mdcmatches[1] == "" && mdcmatches[2] == "" )
 match6sub = /[\{\}]/ # don't remove surrounding "'s if String
	  end
	  
	  args <<
 DirectiveTable[match[5]].gsub("DTR_REPLACE", match[6]).gsub(match6sub,'')
	else
	  args << DirectiveTable[match[5]]  # cull the data for our argument list
	end
    break if match[7].empty?
    _pattern = match[7]
  end
  ebuff << '\n", ' + args.join(', ') + ")\n"
  ebuff << "end\n"
  module_eval ebuff
end