Class: ScoutAgent::WireTap::LogDevice

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

Overview

This Class is used to wrap a device passed to WireTap and then manage interactions with that device. These interactions are handled in a multi-Thread and multi-Process safe way.

WireTap’s LogDevice requires a bigger underlying File-like interface than Logger’s version do to the extra locking and rotation requirements. It skips these steps when the device does not support them though, to make it possible to log to something like $stdout.

Constant Summary collapse

SECONDS_IN_A_DAY =

Used in log rotation calculations.

60 * 60 * 24

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(log = nil, options = Hash.new) ⇒ LogDevice

Wraps log with options, which may include :shift_age and :shift_size. See WireTap::new() for details on these settings.



141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/scout_agent/wire_tap.rb', line 141

def initialize(log = nil, options = Hash.new)
  if log.respond_to?(:write) and log.respond_to?(:close)
    @dev      = log
    @filename = nil
  else
    @dev      = open_log(log)
    @filename = log
  end
  @shift_age  = options[:shift_age]  || 7
  @shift_size = options[:shift_size] || 1048576
  @lock       = Mutex.new
end

Instance Attribute Details

#devObject (readonly)

The underlying device being managed.



155
156
157
# File 'lib/scout_agent/wire_tap.rb', line 155

def dev
  @dev
end

#filenameObject (readonly)

A base name for files created by this device.



157
158
159
# File 'lib/scout_agent/wire_tap.rb', line 157

def filename
  @filename
end

Instance Method Details

#closeObject

Closes the underlying dev in a multi-Thread safe manner.



192
193
194
195
196
# File 'lib/scout_agent/wire_tap.rb', line 192

def close
  @lock.synchronize do
    @dev.close
  end
end

#write(message) ⇒ Object

Writes message to dev in a multi-Thread and multi-Process safe manner.

Before any write occurs, a check is made to see if the content should be shifted. That process will be trigger, if needed.



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/scout_agent/wire_tap.rb', line 166

def write(message)
  @lock.synchronize do
    not @dev.respond_to?(:flock) or @dev.flock(File::LOCK_EX)
    begin
      begin
        shift_log if @filename and @dev.respond_to?(:stat)
      rescue Exception => error  # shifting failed for whatever reason
        raise ShiftingError, "Shifting failed:  #{error.message}"
      end
      begin
        # 
        # make sure we are in the right place, even if the data has been
        # truncated() by another process as part of rotation
        # 
        @dev.seek(0, IO::SEEK_END)
      rescue Errno::ESPIPE  # illegal seek, probably $stdout or $stderr
        # do nothing:  such streams are always at the end
      end
      @dev.write(message)
    ensure
      not @dev.respond_to?(:flock) or @dev.flock(File::LOCK_UN)
    end
  end
end