module Log

Singleton logger for use with both console and gtk+ apps. Logs to both a file and the console/queue for shell/UI apps. Uses Mutex.synchronize where required to provide thread safety.

Public Instance Methods

call_details() click to toggle source

Get timestamp and location of call

# File lib/nub/log.rb, line 73
def call_details
  @@_monitor.synchronize{

    # Skip first 3 on stack (i.e. 0 = block in call_details, 1 = synchronize, 2 = call_detail)
    stack = caller_locations(3, 20)

    # Skip past any calls in 'log.rb' or 'monitor.rb'
    i = -1
    while i += 1 do
      mod = File.basename(stack[i].path, '.rb')
      break if !['log', 'monitor'].include?(mod)
    end

    # Save lineno from original location
    lineno = stack[i].lineno

    # Skip over block type functions to use method.
    # Note: there may not be a non block method e.g. in thread case
    regexps = [Regexp.new('^rescue\s.*in\s'), Regexp.new('^block\s.*in\s'), Regexp.new('^each$')]
    while regexps.any?{|regexp| stack[i].label =~ regexp} do
      break if i + 1 == stack.size
      i += 1
    end

    # Set label, clean up for block case
    label = stack[i].label
    regexps.each{|x| label = label.gsub(label[x], "") if stack[i].label =~ x}
    label = stack[i].label if label.empty?

    # Construct stamp
    location = ":#{File.basename(stack[i].path, '.rb')}:#{label}:#{lineno}"
    return Time.now.utc.iso8601(3), location
  }
end
debug(*args) click to toggle source
# File lib/nub/log.rb, line 200
def debug(*args)
  @@_monitor.synchronize{
    if LogLevel.debug <= self.level
      opts = args.find{|x| x.is_a?(Hash)}
      opts[:type] = 'D' if opts
      args << {:type => 'D'} if !opts
      newline = (opts && opts.key?(:newline)) ? opts[:newline] : true
      return newline ? self.puts(*args) : self.print(*args)
    end
    return true
  }
end
die(msg) click to toggle source

Log the given message in red and exit @param msg [String] message to log

# File lib/nub/log.rb, line 215
def die(msg)
  @@_monitor.synchronize{
    msg += "!" if msg.is_a?(String) && msg[-1] != "!"
    self.puts("Error: #{msg}".colorize(:red), stamp: false) and exit
  }
end
empty?() click to toggle source

Check if the log queue is empty

# File lib/nub/log.rb, line 228
def empty?
  return @@_queue ? @@_queue.empty? : true
end
error(*args) click to toggle source
# File lib/nub/log.rb, line 164
def error(*args)
  @@_monitor.synchronize{
    opts = args.find{|x| x.is_a?(Hash)}
    opts[:loc] = true and opts[:type] = 'E' if opts
    args << {:loc => true, :type => 'E'} if !opts
    newline = (opts && opts.key?(:newline)) ? opts[:newline] : true
    return newline ? self.puts(*args) : self.print(*args)
  }
end
info(*args) click to toggle source
# File lib/nub/log.rb, line 187
def info(*args)
  @@_monitor.synchronize{
    if LogLevel.info <= self.level
      opts = args.find{|x| x.is_a?(Hash)}
      opts[:type] = 'I' if opts
      args << {:type => 'I'} if !opts
      newline = (opts && opts.key?(:newline)) ? opts[:newline] : true
      return newline ? self.puts(*args) : self.print(*args)
    end
    return true
  }
end
init(path:nil, level:LogLevel.debug, queue:false, stdout:true) click to toggle source

Singleton's init method can be called multiple times to reset. @param path [String] path to log file @param queue [Bool] use a queue as well @param stdout [Bool] turn on or off stdout @param level [LogLevel] level at which to log

# File lib/nub/log.rb, line 55
def init(path:nil, level:LogLevel.debug, queue:false, stdout:true)
  self.id ||= 'singleton'.object_id
  self.path = path ? File.expand_path(path) : nil
  self.level = level

  @@_queue = queue ? Queue.new : nil
  @@_stdout = stdout
  $stdout.sync = true

  # Open log file creating as needed
  if self.path
    FileUtils.mkdir_p(File.dirname(self.path)) if !File.exist?(File.dirname(self.path))
    @file = File.open(self.path, 'a')
    @file.sync = true
  end
end
pop() click to toggle source

Remove an item from the queue, block until one exists

# File lib/nub/log.rb, line 223
def pop
  return @@_queue ? @@_queue.pop : nil
end
print(*args) click to toggle source
puts(*args) click to toggle source
# File lib/nub/log.rb, line 135
def puts(*args)
  @@_monitor.synchronize{
    str = !args.first.is_a?(Hash) ? args.first.to_s : ''

    # Format message
    opts = args.find{|x| x.is_a?(Hash)}
    loc = (opts && opts.key?(:loc)) ? opts[:loc] : false
    type = (opts && opts.key?(:type)) ? opts[:type] : ""
    stamp = (opts && opts.key?(:stamp)) ? opts[:stamp] : true

    str = str.colorize(:red) if type == 'E'
    str = str.colorize(:light_yellow) if type == 'W'

    if stamp or loc
      timestamp, location = self.call_details
      location = loc ? location : ""
      type = ":#{type}" if !type.empty?
      str = "#{timestamp}#{location}#{type}:: #{str}"
    end

    # Handle output
    @file.puts(str.strip_color) if self.path
    @@_queue << "#{str}\n" if @@_queue
    $stdout.puts(str) if @@_stdout

    return true
  }
end
warn(*args) click to toggle source
# File lib/nub/log.rb, line 174
def warn(*args)
  @@_monitor.synchronize{
    if LogLevel.warn <= self.level
      opts = args.find{|x| x.is_a?(Hash)}
      opts[:type] = 'W' if opts
      args << {:type => 'W'} if !opts
      newline = (opts && opts.key?(:newline)) ? opts[:newline] : true
      return newline ? self.puts(*args) : self.print(*args)
    end
    return true
  }
end