class TeeLogger::TeeLogger
Logger that writes to multiple outputs. Behaves just like Ruby's Logger, and like a hash of String => Logger.
A typical use might be to log to STDOUT, but also to a file:
log = TeeLogger.new(STDOUT, "filename.log") log.level = Logger::WARN # applies to all outputs log.level = "INFO" # convenience shortcut
By using the instance as a hash, you can also set individual log levels for individual loggers:
log = TeeLogger.new(STDOUT, "filename.log") log.each do |name, logger| if name.include?("filename.log") logger.level = "WARN" else logger.level = "DEBUG" end end
Constants
- LOG_FUNCTIONS
Define log functions as strings, for internal re-use
Public Class Methods
new(*args)
click to toggle source
Start with any amount of IO objects or filenames; defaults to STDOUT
# File lib/teelogger.rb, line 116 def initialize(*args) # Handle default if args.empty? args = [STDOUT] end # Initialization @default_level = Logger::Severity::INFO @formatter = ::TeeLogger::Formatter.new @loggers = {} @ios = {} # Load built-in filters load_filters(*args) # Create logs for all arguments args.each do |arg| add_logger(arg) end end
Public Instance Methods
add_logger(arg)
click to toggle source
Add a logger to the current loggers.
# File lib/teelogger.rb, line 60 def add_logger(arg) key = nil logger = nil io = nil if arg.is_a? String # We have a filename key = File.basename(arg) # Try to create the logger. io = File.new(arg, File::WRONLY | File::APPEND | File::CREAT) logger = Logger.new(io) # Initialize logger io.write "Logging to '#{arg}' initialized with level #{string_level(@default_level)}.\n" logger.level = convert_level(@default_level) else # We have some other object - let's hope it's an IO object key = nil case arg when STDOUT key = 'STDOUT' when STDERR key = 'STDERR' else key = arg.to_s end # Try to create the logger. io = arg logger = Logger.new(io) # Initialize logger io.write "Logging to #{key} initialized with level #{string_level(@default_level)}.\n" logger.level = convert_level(@default_level) end # Set the logger formatter logger.formatter = @formatter # Extend logger instances with extra functionality logger.extend(::TeeLogger::LoggerExtensions) logger.teelogger_io = io logger.flush_interval = DEFAULT_FLUSH_INTERVAL # Flush the "Logging to..." line logger.flush if not key.nil? and not logger.nil? and not io.nil? @loggers[key] = logger @ios[key] = io end end
exception(message, ex)
click to toggle source
Log an exception
# File lib/teelogger.rb, line 169 def exception(message, ex) error("#{message} got #{ex.message}:\n#{ex.backtrace.join("\n")}") end
formatter=(formatter)
click to toggle source
Set the formatter
# File lib/teelogger.rb, line 156 def formatter=(formatter) # Update the default formatter @formatter = formatter # Set all loggers' formatters @loggers.each do |key, logger| logger.formatter = formatter end end
level=(val)
click to toggle source
Set log level; override this to also accept strings
# File lib/teelogger.rb, line 140 def level=(val) # Convert strings to the constant value val = convert_level(val) # Update the default log level @default_level = val # Set all loggers' log levels @loggers.each do |key, logger| logger.level = val end end
method_missing(meth, *args, &block)
click to toggle source
# File lib/teelogger.rb, line 228 def method_missing(meth, *args, &block) dispatch(meth, *args, &block) end
respond_to_missing?(meth, include_private = false)
click to toggle source
Every function this class doesn't have should be mapped to the original logger
# File lib/teelogger.rb, line 209 def respond_to_missing?(meth, include_private = false) if @loggers.nil? or @loggers.empty? raise "No loggers created, can't do anything." end meth_name = meth.to_s # All loggers are the same, so we need to check only one of them. @loggers.each do |key, logger| if logger.respond_to?(meth_name, include_private) return true end break end # If this didn't work, we're also emulating a hash return @loggers.respond_to?(meth_name, include_private) end
Private Instance Methods
dispatch(meth, *args, &block)
click to toggle source
# File lib/teelogger.rb, line 235 def dispatch(meth, *args, &block) if @loggers.nil? or @loggers.empty? raise "No loggers created, can't do anything." end # Try dispatching the call, with preprocessing based on whether it # is a log function or not. meth_name = meth.to_s ret = [] if LOG_FUNCTIONS.include? meth_name ret = dispatch_log(meth_name, *args) else ret = dispatch_other(meth_name, *args, &block) end # Some double checking on the return value(s). if not ret.empty? return ret end # If the method wasn't from the loggers, we'll try to send it to the # hash. return @loggers.send(meth_name, *args, &block) end
dispatch_log(meth_name, *args)
click to toggle source
# File lib/teelogger.rb, line 262 def dispatch_log(meth_name, *args) # Filter all arguments args = apply_filters(*args) # Compose message msg = args.map do |arg| if arg.is_a? String arg else arg.inspect end end message = msg.join("|") # Try to write the message to all loggers. ret = [] @loggers.each do |key, logger| if logger.respond_to? meth_name ret << logger.send(meth_name, key) do message end end end return ret end
dispatch_other(meth_name, *args, &block)
click to toggle source
# File lib/teelogger.rb, line 289 def dispatch_other(meth_name, *args, &block) ret = [] @loggers.each do |key, logger| if logger.respond_to? meth_name ret << logger.send(meth_name, *args, &block) end end return ret end