class Logsly::Logging182::Layouts::Pattern::FormatMethodBuilder
This class is used to build the `format` method for the Pattern
layout. It parses the user defined pattern and emits Ruby source code (as a string) that can be `eval`d in the context of the Pattern
layout instance.
Constants
- COLOR_ALIAS_TABLE
Human name aliases for directives - used for colorization of tokens
- DIRECTIVE_RGXP
Matches the first directive encountered and the stuff around it.
-
$1 is the stuff before directive or “” if not applicable
-
$2 is the %#.# match within directive group
-
$3 is the directive letter
-
$4 is the precision specifier for the logger name
-
$5 is the stuff after the directive or “” if not applicable
-
- DIRECTIVE_TABLE
Arguments to sprintf keyed to directive letters
Attributes
Public Class Methods
Creates the format method builder and initializes some variables from the given Patter layout instance.
pattern_layout - The Pattern
Layout
instance
# File lib/logsly/logging182/layouts/pattern.rb, line 350 def initialize( pattern_layout ) @layout = pattern_layout @pattern = layout.pattern.dup @color_scheme = layout.color_scheme @sprintf_args = [] @format_string = '"' @name_map_count = 0 end
Public Instance Methods
This method returns a String
which can be `eval`d in the context of the Pattern
layout. When it is `eval`d, a `format` method is defined in the Pattern
layout.
At the heart of the format method is `sprintf`. The conversion pattern specified in the Pattern
layout is parsed and converted into a format string and corresponding arguments list. The format string and arguments are then processed by `sprintf` to format log events.
Returns a Ruby code as a String
.
# File lib/logsly/logging182/layouts/pattern.rb, line 385 def build_code build_format_string sprintf = "sprintf(" sprintf << format_string sprintf << ', ' + sprintf_args.join(', ') unless sprintf_args.empty? sprintf << ")" if colorize_lines? sprintf = "color_scheme.color(#{sprintf}, Logsly::Logging182::LNAMES[event.level])" end code = "undef :format if method_defined? :format\n" code << "def format( event )\n#{sprintf}\nend\n" end
This method builds the format string used by `sprintf` to format log events. The conversion pattern given by the user is iteratively parsed by a regular expression into separate format directives. Each directive builds up the format string and the corresponding arguments list that will be formatted.
The actual building of the format string is handled by separate directive specific methods. Those handlers also populate the arguments list passed to `sprintf`.
Returns the format String
.
# File lib/logsly/logging182/layouts/pattern.rb, line 412 def build_format_string while true match = DIRECTIVE_RGXP.match(pattern) _, pre, format, directive, precision, post = *match format_string << pre unless pre.empty? case directive when '%'; format_string << '%%' when 'c'; handle_logger( format, directive, precision ) when 'l'; handle_level( format, directive, precision ) when 'X'; handle_mdc( format, directive, precision ) when 'x'; handle_ndc( format, directive, precision ) when *DIRECTIVE_TABLE.keys handle_directives(format, directive, precision) when nil; break else raise ArgumentError, "illegal format character - '#{directive}'" end break if post.empty? self.pattern = post end format_string << '"' end
Returns `true` if the log messages should be colorized.
# File lib/logsly/logging182/layouts/pattern.rb, line 361 def colorize? color_scheme && !color_scheme.lines? end
Returns `true` if the log levels have special colorization defined.
# File lib/logsly/logging182/layouts/pattern.rb, line 371 def colorize_levels? color_scheme && color_scheme.levels? end
Returns `true` if the log messages should be colorized by line.
# File lib/logsly/logging182/layouts/pattern.rb, line 366 def colorize_lines? color_scheme && color_scheme.lines? end
Handles the rest of the directives; none of these need any special handling.
format - format String
directive - the directive character precision - added back to the format string
Returns nil
# File lib/logsly/logging182/layouts/pattern.rb, line 553 def handle_directives( format, directive, precision ) fmt = format + 's' fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[directive]) if colorize? format_string << fmt format_string << "{#{precision}}" if precision sprintf_args << DIRECTIVE_TABLE[directive] nil end
Add the log event level to the `format_string` and the `sprintf_args`. The color scheme is taken into account when formatting the log event level.
format - format String
directive - the directive character ('l') precision - added back to the format string
Returns nil
# File lib/logsly/logging182/layouts/pattern.rb, line 482 def handle_level( format, directive, precision ) if colorize_levels? name_map = Logsly::Logging182::LNAMES.map do |name| color_scheme.color(("#{format}s" % name), name) end var = "@name_map_#{name_map_count}" layout.instance_variable_set(var.to_sym, name_map) self.name_map_count += 1 format_string << '%s' format_string << "{#{precision}}" if precision sprintf_args << "#{var}[event.level]" else format_string << format + 's' format_string << "{#{precision}}" if precision sprintf_args << DIRECTIVE_TABLE[directive] end nil end
Add the logger name to the `format_string` and the `sprintf_args`. The `slice` argument is a little interesting - this is the number of logger name segments to keep. If we have a logger named “Foo::Bar::Baz” and our `slice` is 2, then “Bar::Baz” will appear in the generated log message. So the `slice` selects the last two parts of the logger name.
format - format String
directive - the directive character ('c') slice - the number of name segments to keep
Returns nil
# File lib/logsly/logging182/layouts/pattern.rb, line 451 def handle_logger( format, directive, slice ) fmt = format + 's' fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[directive]) if colorize? format_string << fmt sprintf_args << DIRECTIVE_TABLE[directive].dup if slice numeric = Integer(slice) rescue nil if numeric raise ArgumentError, "logger name slice must be an integer greater than zero: #{numeric}" unless numeric > 0 sprintf_args.last << ".split(Logsly::Logging182::Repository::PATH_DELIMITER)" \ ".last(#{slice}).join(Logsly::Logging182::Repository::PATH_DELIMITER)" else format_string << "{#{slice}}" end end nil end
Add a Mapped Diagnostic Context to the `format_string` and the `sprintf_args`. Only one MDC value is added at a time, so this directive can appear multiple times using various keys.
format - format String
directive - the directive character ('X') key - which MDC value to add to the log message
Returns nil
# File lib/logsly/logging182/layouts/pattern.rb, line 512 def handle_mdc( format, directive, key ) raise ArgumentError, "MDC must have a key reference" unless key fmt = format + 's' fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[directive]) if colorize? format_string << fmt sprintf_args << "Logsly::Logging182.mdc['#{key}']" nil end
Add a Nested Diagnostic Context to the `format_string` and the `sprintf_args`. Since the NDC is an Array of values, the directive will appear only once in the conversion pattern. A `separator` is inserted between the values in generated log message.
format - format String
directive - the directive character ('x') separator - used to separate the values in the NDC array
Returns nil
# File lib/logsly/logging182/layouts/pattern.rb, line 533 def handle_ndc( format, directive, separator ) fmt = format + 's' fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[directive]) if colorize? format_string << fmt separator = separator.to_s separator = ' ' if separator.empty? sprintf_args << "Logsly::Logging182.ndc.context.join('#{separator}')" nil end