# :include: ../rdoc/syslogoutputter # # Version:: $Id$ # Author:: Steve Lumos # Author:: Leon Torres require 'log4r/formatter/formatter' require 'log4r/outputter/outputter' require 'log4r/configurator' require 'syslog' module Log4r SYSLOGNAMES = Hash.new class SyslogOutputter < Outputter include Syslog::Constants # maps default log4r levels to syslog priorities (logevents never see ALL and OFF) # SYSLOG Levels are: # "DEBUG" => Syslog::LOG_DEBUG # "INFO" => Syslog::LOG_INFO # "NOTICE" => Syslog::LOG_NOTICE # "WARN" => Syslog::LOG_WARN # "ERROR" => Syslog::LOG_ERROR # "FATAL" => Syslog::LOG_FATAL # "ALERT" => Syslog::LOG_ALERT # "EMERG" => Syslog::LOG_EMERG SYSLOG_LEVELS_MAP = { "DEBUG" => LOG_DEBUG, "INFO" => LOG_INFO, "NOTICE" => LOG_NOTICE, # by default NOTICE is not in log4r "WARN" => LOG_WARNING, "ERROR" => LOG_ERR, "FATAL" => LOG_CRIT, "ALERT" => LOG_ALERT, # by default ALERT is not in log4r "EMERG" => LOG_EMERG, # by default EMERG is not in log4r } # mapping from Log4r default levels to syslog, by string name # "DEBUG" => "DEBUG" # "INFO" => "INFO" # "WARN" => "WARN" # "ERROR" => "ERROR" # "FATAL" => "FATAL" SYSLOG_LOG4R_MAP = { "DEBUG" => "DEBUG", "INFO" => "INFO", "WARN" => "WARN", "ERROR" => "ERROR", "FATAL" => "FATAL" # "NOTICE" => "INFO", # by default NOTICE is not in log4r # "ALERT" => "FATAL", # by default ALERT is not in log4r # "EMERG" => "FATAL" # by default EMERG is not in log4r } @levels_map = SYSLOG_LOG4R_MAP # There are 3 hash arguments # # [:ident] syslog ident, defaults to _name # [:logopt] syslog logopt, defaults to LOG_PID | LOG_CONS # [:facility] syslog facility, defaults to LOG_USER def initialize(_name, hash={}) super(_name, hash) ident = (hash[:ident] or hash['ident'] or _name) logopt = (hash[:logopt] or hash['logopt'] or LOG_PID | LOG_CONS).to_i facility = (hash[:facility] or hash['facility'] or LOG_USER).to_i map_levels_by_name_to_syslog() if ( Syslog.opened? ) then Logger.log_internal { "Syslog already initialized, to alter, " + "you must close first"} end @syslog = ( Syslog.opened? ) ? Syslog : Syslog.open(ident, logopt, facility) end def closed? return !@syslog.opened? end def close @syslog.close unless @syslog.nil? @level = OFF OutputterFactory.create_methods(self) Logger.log_internal {"Outputter '#{@name}' closed Syslog and set to OFF"} end # A single hash argument that maps custom names to syslog names # # [levels_map] A map that will create a linkage between levels # in a hash and underlying syslog levels. # By default, these are direct mapping of the log4r # levels (e.g. "DEBUG" => "DEBUG") # If you have defined your own custom levels, you # should provide this underlying mapping, otherwise # all messages will be mapped to the underlying syslog # level of INFO by default. # e.g. # You have created custom levels called: # Configurator.custom_levels "HIGH", "MEDIUM", "LOW" # To map these to 'equivilent' syslog levels, after instantiatin # a syslogoutputter: # SyslogOutputter.map_levels_by_name_to_syslog( # { "HIGH" => "ALERT", "MEDIUM" => "WARN", "LOW" => "INFO" } # ) def map_levels_by_name_to_syslog( lmap = SYSLOG_LOG4R_MAP ) @levels_map = lmap end def get_levels_map() return @levels_map end private def canonical_log(logevent) pri = SYSLOG_LEVELS_MAP[@levels_map[LNAMES[logevent.level]]] rescue pri = LOG_INFO o = format(logevent) if o.kind_of? Exception then msg = "#{o.class} at (#{o.backtrace[0]}): #{o.message}" elsif o.respond_to? :to_str then msg = o.to_str else msg = o.inspect end @syslog.log(pri, '%s', msg) end end end