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.



356
357
358
359
360
361
362
363
# File 'lib/scout_agent/wire_tap.rb', line 356

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.



455
456
457
458
459
460
461
462
463
464
# File 'lib/scout_agent/wire_tap.rb', line 455

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.



369
370
371
# File 'lib/scout_agent/wire_tap.rb', line 369

def formatter
  @formatter
end

#levelObject Also known as: sev_threshold

The current level below which no messages will be logged.



371
372
373
# File 'lib/scout_agent/wire_tap.rb', line 371

def level
  @level
end

#prognameObject

The Process name used in messages logged by this instance.



375
376
377
# File 'lib/scout_agent/wire_tap.rb', line 375

def progname
  @progname
end

Instance Method Details

#<<(message) ⇒ Object

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



441
442
443
# File 'lib/scout_agent/wire_tap.rb', line 441

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.



416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
# File 'lib/scout_agent/wire_tap.rb', line 416

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.



467
468
469
# File 'lib/scout_agent/wire_tap.rb', line 467

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.



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

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.



381
382
383
# File 'lib/scout_agent/wire_tap.rb', line 381

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)


407
408
409
# File 'lib/scout_agent/wire_tap.rb', line 407

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

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

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

Returns:

  • (Boolean)


446
447
448
449
450
451
452
# File 'lib/scout_agent/wire_tap.rb', line 446

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).



402
403
404
# File 'lib/scout_agent/wire_tap.rb', line 402

def tap
  @tap ||= nil
end

#tap=(logdev) ⇒ Object

Sets a second logdev all messages should be copied to.



394
395
396
# File 'lib/scout_agent/wire_tap.rb', line 394

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