class Sensu::Logger::Stream

Attributes

level[RW]

@!attribute [rw] level

@return level [Symbol] current log level.

Public Class Methods

create_level_methods() click to toggle source

Create a method for each of the log levels, they call add() to add log events to the log stream.

# File lib/sensu/logger/stream.rb, line 28
def self.create_level_methods
  LEVELS.each do |level|
    define_method(level) do |*args|
      add(level, *args)
    end
  end
end
new() click to toggle source

Initialize a log stream, redirect STDERR to STDOUT, create log level methods, and setup the reactor log event writer.

# File lib/sensu/logger/stream.rb, line 16
def initialize
  @stream = []
  @stream_callbacks = []
  @level = :info
  STDOUT.sync = true
  STDERR.reopen(STDOUT)
  self.class.create_level_methods
  setup_writer
end

Public Instance Methods

add(level, *args) click to toggle source

Add a log event to the log stream.

@param level [Symbol] log event level. @param args [Array] to pass to #create_log_event(). @return [TrueClass, FalseClass] if the log event was added.

# File lib/sensu/logger/stream.rb, line 49
def add(level, *args)
  unless level_filtered?(level)
    event = create_log_event(level, *args)
    if EM.reactor_running?
      schedule_write(event)
    else
      safe_write(event)
    end
    true
  else
    false
  end
end
level_filtered?(level) click to toggle source

Check to see if a log level is currently being filtered.

@param level [Symbol] log event level. @return [TrueClass, FalseClass]

# File lib/sensu/logger/stream.rb, line 40
def level_filtered?(level)
  LEVELS.index(level) < LEVELS.index(@level)
end
reopen(target) click to toggle source

Reopen the log stream output, write log events to a file.

@param target [IO, String] IO stream or file path.

# File lib/sensu/logger/stream.rb, line 66
def reopen(target)
  @reopen = target
  case target
  when IO
    STDOUT.reopen(target)
    STDOUT.sync = true
    STDERR.reopen(STDOUT)
  when String
    if File.writable?(target) || !File.exist?(target) && File.writable?(File.dirname(target))
      STDOUT.reopen(target, "a")
      STDOUT.sync = true
      STDERR.reopen(STDOUT)
    else
      error("log file is not writable", {
        :log_file => target
      })
    end
  end
end
setup_signal_traps() click to toggle source

Setup signal traps for the log stream. Signals:

TRAP: toggle debug logging.
USR2: reopen the log file.
# File lib/sensu/logger/stream.rb, line 90
def setup_signal_traps
  if Signal.list.include?("TRAP")
    Signal.trap("TRAP") do
      @level = case @level
      when :debug
        @previous_level || :info
      else
        @previous_level = @level
        :debug
      end
    end
  end
  if Signal.list.include?("USR2")
    Signal.trap("USR2") do
      if @reopen
        reopen(@reopen)
      end
    end
  end
end

Private Instance Methods

create_log_event(level, message, data=nil) click to toggle source

Create a JSON log event.

@param level [Symbol] log event level. @param message [String] log event message. @param data [Hash] log event data. @return [String] JSON log event.

# File lib/sensu/logger/stream.rb, line 119
def create_log_event(level, message, data=nil)
  event = {}
  event[:timestamp] = Time.now.strftime("%Y-%m-%dT%H:%M:%S.%6N%z")
  event[:level] = level
  event[:message] = message
  if data.is_a?(Hash)
    event.merge!(data)
  end
  MultiJson.dump(event)
end
register_callback(&callback) click to toggle source

Register a log stream callback (a write operation).

@param [Proc] callback to register, it will eventually be

called and passed a JSON log event as a parameter.
# File lib/sensu/logger/stream.rb, line 157
def register_callback(&callback)
  EM.schedule do
    if @stream.empty?
      @stream_callbacks << callback
    else
      callback.call(@stream.shift)
    end
  end
end
safe_write(event) click to toggle source

Write a JSON log event to STDOUT, which may be redirected to a log file. This method will take no action if the storage device has no space remaining.

# File lib/sensu/logger/stream.rb, line 146
def safe_write(event)
  begin
    puts event
  rescue Errno::ENOSPC
  end
end
schedule_write(event) click to toggle source

Schedule a log event write, pushing the JSON log event into the stream.

@param event [String] JSON log event.

# File lib/sensu/logger/stream.rb, line 134
def schedule_write(event)
  EM.schedule do
    @stream << event
    unless @stream_callbacks.empty?
      @stream_callbacks.shift.call(@stream.shift)
    end
  end
end
setup_writer() click to toggle source

Setup reactor log event writer. On shutdown, remaining log events will be written/flushed.

# File lib/sensu/logger/stream.rb, line 169
def setup_writer
  writer = Proc.new do |log_event|
    safe_write(log_event)
    EM.next_tick do
      register_callback(&writer)
    end
  end
  register_callback(&writer)
  EM.add_shutdown_hook do
    @stream.size.times do
      safe_write(@stream.shift)
    end
  end
end