Class: ScoutAgent::WireTap

Inherits:
Object
  • Object
show all
Includes:
Severity
Defined in:
lib/scout_agent/wire_tap.rb

Overview

WireTap is a complete replacement for Ruby’s standard Logger class, with a few changes:

  • The code is multi-Process safe

  • Log can be duplicated on a second device

  • The default formatter produces a trimmed down output

  • Severity levels can be dynamically altered (not used in the agent)

The main change was to make the code work for multiple processes. This is done by forcing code to aquire the proper locks during all file interactions. Log rotation also had to be changed to avoid moving an active log file out from under another process. Instead, files are copied and truncated. This also required a seek() to the end of the file before each write to be added to defeat some pos() caching that seemed to be occurring. The end results of all of this is that WireTap is safer than Logger, but slower because of the extra precausions it must take.

The tap=() method on instances of this class, allows you to set a second device input can be copied to.

Defined Under Namespace

Modules: Severity Classes: Error, Formatter, LogDevice, ShiftingError

Constant Summary

Constants included from Severity

Severity::DEBUG, Severity::ERROR, Severity::FATAL, Severity::INFO, Severity::UNKNOWN, Severity::WARN

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logdev, shift_age = 0, shift_size = 1048576) ⇒ WireTap

Wraps logdev for logging.

You can set shift_age and/or shift_size to setup log rotation. You can pass :daily, :weekly, or :monthly as shift_age to get the named rotation. Alternately, you can set shift_age to the number of log files to keep and shift_size to the byte size at which log files are rotated out.



370
371
372
373
374
375
376
377
# File 'lib/scout_agent/wire_tap.rb', line 370

def initialize(logdev, shift_age = 0, shift_size = 1048576)
  @logdev    = logdev &&
               LogDevice.new( logdev, :shift_age  => shift_age,
                                      :shift_size => shift_size )
  @formatter = Formatter.new
  @level     = min_level
  @progname  = nil
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

Dynamic level method dispatch. See Severity for details.



479
480
481
482
483
484
485
486
487
488
# File 'lib/scout_agent/wire_tap.rb', line 479

def method_missing(method, *args, &block)
  case method.to_s
  when /\A(#{level_re})\?\z/i
    level?($1, *args, &block)
  when /\A(#{level_re})\z/i
    add(levels[$1.upcase], nil, *args, &block)
  else
    super
  end
end

Instance Attribute Details

#formatterObject

The Formatter instance being used to format the messages logged by this WireTap instance.



383
384
385
# File 'lib/scout_agent/wire_tap.rb', line 383

def formatter
  @formatter
end

#levelObject Also known as: sev_threshold

The current level below which no messages will be logged.



385
386
387
# File 'lib/scout_agent/wire_tap.rb', line 385

def level
  @level
end

#prognameObject

The Process name used in messages logged by this instance.



389
390
391
# File 'lib/scout_agent/wire_tap.rb', line 389

def progname
  @progname
end

Instance Method Details

#<<(message) ⇒ Object

Write’s a raw message to the log without any formatting or preprocessing.



465
466
467
# File 'lib/scout_agent/wire_tap.rb', line 465

def <<(message)
  @logdev.write(message) unless @logdev.nil?
end

#add(severity, message = nil, progname = nil, &block) ⇒ Object Also known as: log

A low-level way to log a message with severity. You can optionally pass a progname override. You can also choose to pass the message in a block that will be run to build the message only if it would be written.



440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
# File 'lib/scout_agent/wire_tap.rb', line 440

def add(severity, message = nil, progname = nil, &block)
  severity ||= max_level
  return true if @logdev.nil? or severity < @level
  progname ||= @progname
  if message.nil?
    if block.nil?
      message, progname = progname, @progname
    else
      message = block.call
    end
  end
  output = @formatter.call( level_names[severity] || "ANY",
                            Time.now,
                            progname,
                            message )
  @logdev.write(output)
  tap.write(output) if tap
  true
end

#closeObject

Closes the underlying log.



491
492
493
# File 'lib/scout_agent/wire_tap.rb', line 491

def close
  @logdev.close unless @logdev.nil?
end

#datetime_formatObject

Returns the timestamp format currently in use (or nil if the default is being used) to format messages for this instance.



413
414
415
# File 'lib/scout_agent/wire_tap.rb', line 413

def datetime_format
  @formatter.datetime_format
end

#datetime_format=(datetime_format) ⇒ Object

Sets a new timestamp format on the Formatter used to format messages for this instance. datetime_format should be a strftime() pattern String.



405
406
407
# File 'lib/scout_agent/wire_tap.rb', line 405

def datetime_format=(datetime_format)
  @formatter.datetime_format = datetime_format
end

#level?(level) ⇒ Boolean

Returns true if a level message would currently be written.

Returns:

  • (Boolean)


431
432
433
# File 'lib/scout_agent/wire_tap.rb', line 431

def level?(level)
  @level <= level_by_name(level)
end

#quiet=(boolean) ⇒ Object

A simple wrapper for LogDevice#quiet=().



397
398
399
# File 'lib/scout_agent/wire_tap.rb', line 397

def quiet=(boolean)
  @logdev.quiet = boolean
end

#quiet?Boolean

A simple wrapper for LogDevice#quiet?().

Returns:

  • (Boolean)


392
393
394
# File 'lib/scout_agent/wire_tap.rb', line 392

def quiet?
  @logdev.quiet?
end

#respond_to?(message, include_private = false) ⇒ Boolean

An override to show the dynamic level methods. See Severity for details.

Returns:

  • (Boolean)


470
471
472
473
474
475
476
# File 'lib/scout_agent/wire_tap.rb', line 470

def respond_to?(message, include_private = false)
  if level_methods.include? message.to_s
    true
  else
    super
  end
end

#tapObject

Returns the secondary device messages are being logged to (or nil if none is in use).



426
427
428
# File 'lib/scout_agent/wire_tap.rb', line 426

def tap
  @tap ||= nil
end

#tap=(logdev) ⇒ Object

Sets a second logdev all messages should be copied to.



418
419
420
# File 'lib/scout_agent/wire_tap.rb', line 418

def tap=(logdev)
  @tap = logdev && LogDevice.new(logdev)
end