class Logsly::Logging182::Appenders::Growl
This class provides an Appender
that can send notifications to the Growl
notification system on Mac OS X.
growlnotify
must be installed somewhere in the path in order for the appender to function properly.
Public Class Methods
Create an appender that will log messages to the Growl
framework on a Mac OS X machine.
Logsly::Logging182::Appender::new
# File lib/logsly/logging182/appenders/growl.rb, line 29 def initialize( name, opts = {} ) super @growl = "growlnotify -w -n \"#{@name}\" -t \"%s\" -m \"%s\" -p %d &" @coalesce = opts.getopt(:coalesce, false) @title_sep = opts.getopt(:separator) # provides a mapping from the default Logsly::Logging182 levels # to the Growl notification levels @map = [-2, -1, 0, 1, 2] map = opts.getopt(:map) self.map = map unless map.nil? setup_coalescing if @coalesce # make sure the growlnotify command can be called unless system('growlnotify -v >> /dev/null 2>&1') self.level = :off ::Logsly::Logging182.log_internal {'growl notifications have been disabled'} end end
Public Instance Methods
Configure the mapping from the Logsly::Logging182
levels to the Growl
notification levels. This is needed in order to log events at the proper Growl
level.
Without any configuration, the following mapping will be used:
:debug => -2 :info => -1 :warn => 0 :error => 1 :fatal => 2
# File lib/logsly/logging182/appenders/growl.rb, line 67 def map=( levels ) map = [] levels.keys.each do |lvl| num = ::Logsly::Logging182.level_num(lvl) map[num] = growl_level_num(levels[lvl]) end @map = map end
Private Instance Methods
Call the growlnotify application with the given parameters. If the system call fails, the growl appender will be disabled.
# File lib/logsly/logging182/appenders/growl.rb, line 191 def call_growl( *args ) unless system(@growl % args) self.level = :off ::Logsly::Logging182.log_internal {'growl notifications have been disabled'} end end
Attempt to coalesce the given message with any that might be pending in the queue to send to the growl notifier. Messages are coalesced with any in the queue that have the same title and priority.
There can be only one message in the queue, so if the title and/or priority don't match, the message in the queue is sent immediately to the growl notifier, and the current message is queued.
# File lib/logsly/logging182/appenders/growl.rb, line 145 def coalesce( *msg ) @c_mutex.synchronize do if @c_queue.empty? @c_queue << msg @c_thread.run else qmsg = @c_queue.last if qmsg.first != msg.first or qmsg.last != msg.last @c_queue << msg else qmsg[1] << "\n" << msg[1] end end end end
Send the message to the growl notifier using the given title and priority.
# File lib/logsly/logging182/appenders/growl.rb, line 128 def growl( title, message, priority ) message.tr!("`", "'") if @coalesce then coalesce(title, message, priority) else call_growl(title, message, priority) end end
Takes the given level as a string or integer and returns the corresponding Growl
notification level number.
# File lib/logsly/logging182/appenders/growl.rb, line 114 def growl_level_num( level ) level = Integer(level) if level < -2 or level > 2 raise ArgumentError, "level '#{level}' is not in range -2..2" end level end
Setup the appender to handle coalescing of messages before sending them to the growl notifier. This requires the creation of a thread and mutex for passing messages from the appender thread to the growl notifier thread.
# File lib/logsly/logging182/appenders/growl.rb, line 170 def setup_coalescing @c_mutex = Mutex.new @c_queue = [] @c_thread = Thread.new do loop do Thread.stop if @c_queue.empty? sleep 1 @c_mutex.synchronize { call_growl(*@c_queue.shift) until @c_queue.empty? } end # loop end # Thread.new end
Write the given event to the growl notification facility. The log event will be processed through the Layout
associated with this appender. The message will be logged at the level specified by the event.
# File lib/logsly/logging182/appenders/growl.rb, line 87 def write( event ) title = '' priority = 0 message = if event.instance_of?(::Logsly::Logging182::LogEvent) priority = @map[event.level] @layout.format(event) else event.to_s end return if message.empty? message = message.gsub(ColoredRegexp, '') if @title_sep title, message = message.split(@title_sep) title, message = '', title if message.nil? end growl(title.strip, message.strip, priority) self end