# # Author:: Christian Reiniger # License:: GNU GPL v2 or later, as described in the accompanying LICENSE file # Homepage: http://dsadmin.dotsrc.org/ # # ---- # Last change: # # CVS User:: $Author: creinig $ # Date:: $Date: 2006-10-24 10:29:33 +0200 (Tue, 24 Oct 2006) $ # Revision:: $Revision: 110 $ # require 'thread' require 'dsadmin/contractor' require 'dsadmin/system' require 'dsadmin/email' module Dsadmin # Collection of output handlers for the logging subsystem module LogWriters # Abstract base class for all output handlers class LogWriter include Dsadmin::Contractor # OVERRIDE def write(message, formatted_record) assertNotReachable end # Returns the "kind" of writer the object represents (:file, :stream, :email, ...) # OVERRIDE def kind assertNotReachable end # override if necessary def shutdown end end # Output handler for filesystem entities (plain files, named pipes etc) class FileWriter < LogWriter def write(message, formatted_record) @mutex.synchronize { @dest << formatted_record } end def shutdown @dest.close if @dest @dest = nil end def stream @dest end def filename @destname end def kind :file end private # Constructor # # Accepts parameterized filenames (printf-style): # * '%d' => current date (YYYY-MM-DD), # * '%p' => current process id, # * '%h' => hostname, # * '%i' => instance ID (only when running in an admind context), # * '%t' => current time (%H:%M:%S) def initialize(aFilename, config_manager) @sys = System.instance @destname = expandFilename(aFilename, config_manager) @dest = File.new(@destname, "a") @dest.sync = true @mutex = Mutex.new end # Generates a proper filename from the given one by replacing parameters # (%d, %p, ...) with their actual values def expandFilename(aFilename, config_manager) date_s = Date.today.to_s time_s = System.instance.now.strftime('%H:%M:%S') pid_s = Process.pid.to_s res = aFilename.gsub(/%d/, date_s) res = res.gsub(/%p/, pid_s) res = res.gsub(/%h/, Socket.gethostname) res = res.gsub(/%i/, config_manager.instanceid) if(config_manager.respond_to?(:instanceid)) res = res.gsub(/%t/, time_s) return config_manager.localpath(res) end # expandFilename end # Output handler for raw streams ($stdout, $stderr, pre-opened files or sockets, ...) or, # in fact, anything that responds to "<<" (like an array or a ring buffer). # The given stream is *not* automatically closed at handler shutdown. class StreamWriter < LogWriter def write(message, formatted_record) @stream << formatted_record end def kind :stream end attr_reader :stream private def initialize(stream) assertRespondTo(stream, "<<") @stream = stream end end # Output handler for email messages (one per log message). # Use only for low-frequency messages (bug reports etc) # FIXME: Implement queueing and bundling of messages to avoid flooding class EmailWriter < LogWriter def write(message, formatted_record) mail = Email.new(@facility) mail.subject = message.to_s mail.text = formatted_record mail.send end def kind :email end private # ---------------------------------------------------------- private # Constructor def initialize(mail_facility) # Try if the mail facility exists tmp = Email.new(mail_facility) @facility = mail_facility end end end # module LogWriters end # module Dsadmin