Class: Logging::Layouts::Pattern::FormatMethodBuilder
- Inherits:
-
Object
- Object
- Logging::Layouts::Pattern::FormatMethodBuilder
- Defined in:
- lib/logging/layouts/pattern.rb
Overview
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.
Constant Summary collapse
- 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
-
%r/([^%]*)(?:(%-?\d*(?:\.\d+)?)([a-zA-Z%])(?:\{([^\}]+)\})?)?(.*)/m
- DIRECTIVE_TABLE =
Arguments to sprintf keyed to directive letters
{ 'c' => 'event.logger'.freeze, 'd' => 'format_date(event.time)'.freeze, 'F' => 'event.file'.freeze, 'l' => '::Logging::LNAMES[event.level]'.freeze, 'L' => 'event.line'.freeze, 'm' => 'format_obj(event.data)'.freeze, 'M' => 'event.method_name'.freeze, 'h' => "'#{Socket.gethostname}'".freeze, 'p' => 'Process.pid'.freeze, 'r' => 'Integer((event.time-@created_at)*1000).to_s'.freeze, 't' => 'Thread.current.object_id.to_s'.freeze, 'T' => 'Thread.current[:name]'.freeze, 'X' => :placeholder, 'x' => :placeholder, '%' => :placeholder }.freeze
- COLOR_ALIAS_TABLE =
Human name aliases for directives - used for colorization of tokens
{ 'c' => :logger, 'd' => :date, 'm' => :message, 'h' => :hostname, 'p' => :pid, 'r' => :time, 'T' => :thread, 't' => :thread_id, 'F' => :file, 'L' => :line, 'M' => :method, 'X' => :mdc, 'x' => :ndc }.freeze
Instance Attribute Summary collapse
-
#color_scheme ⇒ Object
readonly
Returns the value of attribute color_scheme.
-
#format_string ⇒ Object
readonly
Returns the value of attribute format_string.
-
#layout ⇒ Object
readonly
Returns the value of attribute layout.
-
#name_map_count ⇒ Object
Returns the value of attribute name_map_count.
-
#pattern ⇒ Object
Returns the value of attribute pattern.
-
#sprintf_args ⇒ Object
readonly
Returns the value of attribute sprintf_args.
Instance Method Summary collapse
-
#build_code ⇒ Object
This method returns a String which can be ‘eval`d in the context of the Pattern layout.
-
#build_format_string ⇒ Object
This method builds the format string used by ‘sprintf` to format log events.
-
#colorize? ⇒ Boolean
Returns ‘true` if the log messages should be colorized.
-
#colorize_levels? ⇒ Boolean
Returns ‘true` if the log levels have special colorization defined.
-
#colorize_lines? ⇒ Boolean
Returns ‘true` if the log messages should be colorized by line.
-
#handle_directives(format, directive, precision) ⇒ Object
Handles the rest of the directives; none of these need any special handling.
-
#handle_level(format, directive, precision) ⇒ Object
Add the log event level to the ‘format_string` and the `sprintf_args`.
-
#handle_logger(format, directive, slice) ⇒ Object
Add the logger name to the ‘format_string` and the `sprintf_args`.
-
#handle_mdc(format, directive, key) ⇒ Object
Add a Mapped Diagnostic Context to the ‘format_string` and the `sprintf_args`.
-
#handle_ndc(format, directive, separator) ⇒ Object
Add a Nested Diagnostic Context to the ‘format_string` and the `sprintf_args`.
-
#initialize(pattern_layout) ⇒ FormatMethodBuilder
constructor
Creates the format method builder and initializes some variables from the given Patter layout instance.
Constructor Details
#initialize(pattern_layout) ⇒ FormatMethodBuilder
Creates the format method builder and initializes some variables from the given Patter layout instance.
pattern_layout - The Pattern Layout instance
350 351 352 353 354 355 356 357 358 |
# File 'lib/logging/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 |
Instance Attribute Details
#color_scheme ⇒ Object (readonly)
Returns the value of attribute color_scheme.
340 341 342 |
# File 'lib/logging/layouts/pattern.rb', line 340 def color_scheme @color_scheme end |
#format_string ⇒ Object (readonly)
Returns the value of attribute format_string.
342 343 344 |
# File 'lib/logging/layouts/pattern.rb', line 342 def format_string @format_string end |
#layout ⇒ Object (readonly)
Returns the value of attribute layout.
338 339 340 |
# File 'lib/logging/layouts/pattern.rb', line 338 def layout @layout end |
#name_map_count ⇒ Object
Returns the value of attribute name_map_count.
343 344 345 |
# File 'lib/logging/layouts/pattern.rb', line 343 def name_map_count @name_map_count end |
#pattern ⇒ Object
Returns the value of attribute pattern.
339 340 341 |
# File 'lib/logging/layouts/pattern.rb', line 339 def pattern @pattern end |
#sprintf_args ⇒ Object (readonly)
Returns the value of attribute sprintf_args.
341 342 343 |
# File 'lib/logging/layouts/pattern.rb', line 341 def sprintf_args @sprintf_args end |
Instance Method Details
#build_code ⇒ Object
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.
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'lib/logging/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}, ::Logging::LNAMES[event.level])" end code = "undef :format if method_defined? :format\n" code << "def format( event )\n#{sprintf}\nend\n" end |
#build_format_string ⇒ Object
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.
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
# File 'lib/logging/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 |
#colorize? ⇒ Boolean
Returns ‘true` if the log messages should be colorized.
361 362 363 |
# File 'lib/logging/layouts/pattern.rb', line 361 def colorize? color_scheme && !color_scheme.lines? end |
#colorize_levels? ⇒ Boolean
Returns ‘true` if the log levels have special colorization defined.
371 372 373 |
# File 'lib/logging/layouts/pattern.rb', line 371 def colorize_levels? color_scheme && color_scheme.levels? end |
#colorize_lines? ⇒ Boolean
Returns ‘true` if the log messages should be colorized by line.
366 367 368 |
# File 'lib/logging/layouts/pattern.rb', line 366 def colorize_lines? color_scheme && color_scheme.lines? end |
#handle_directives(format, directive, precision) ⇒ Object
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
552 553 554 555 556 557 558 559 560 561 |
# File 'lib/logging/layouts/pattern.rb', line 552 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 |
#handle_level(format, directive, precision) ⇒ Object
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
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 |
# File 'lib/logging/layouts/pattern.rb', line 483 def handle_level( format, directive, precision ) if colorize_levels? name_map = ::Logging::LNAMES.map { |name| color_scheme.color(("#{format}s" % name), name) } 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 |
#handle_logger(format, directive, slice) ⇒ Object
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
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 |
# File 'lib/logging/layouts/pattern.rb', line 452 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(::Logging::Repository::PATH_DELIMITER)" \ ".last(#{slice}).join(::Logging::Repository::PATH_DELIMITER)" else format_string << "{#{slice}}" end end nil end |
#handle_mdc(format, directive, key) ⇒ Object
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
511 512 513 514 515 516 517 518 519 520 |
# File 'lib/logging/layouts/pattern.rb', line 511 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 << "::Logging.mdc['#{key}']" nil end |
#handle_ndc(format, directive, separator) ⇒ Object
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
532 533 534 535 536 537 538 539 540 541 542 |
# File 'lib/logging/layouts/pattern.rb', line 532 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 << "::Logging.ndc.context.join('#{separator}')" nil end |