From 2f511388327d40d0b30dae2c264b86e094eb10c8 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Sat, 22 Sep 2007 22:29:06 -0700 Subject: [PATCH] finish smtp email functionality (auth), human readable logs for contacts --- History.txt | 4 +- lib/god/contact.rb | 2 +- lib/god/contacts/email.rb | 27 +++++++-- lib/god/hub.rb | 125 ++++++++++++++++++++------------------- test/configs/contact/contact.god | 13 +++- 5 files changed, 100 insertions(+), 71 deletions(-) diff --git a/History.txt b/History.txt index b12a345..d5724cc 100644 --- a/History.txt +++ b/History.txt @@ -5,7 +5,7 @@ * Add TriggerCondition for conditions that need info about state changes * Implement notification system * Add Tasks (a generalization of Watches) to do non-process related tasks - * Add example init.d file in GOD_INSTALL_DIR/init/god + * Add example init.d file in GOD_INSTALL_DIR/init/god [scott becker] * Add human readable info to conditions (and make low level log lines debug) * Minor Enchancements * Allow EventConditions to do transition overloading @@ -22,7 +22,7 @@ * Flapping < TriggerCondition - trigger on state change * HttpResponseCode < PollCondition - trigger on http response code or timeout (thx scott becker) * New Contacts - * Email < Contact - notify via email (smtp, sendmail) + * Email < Contact - notify via email (smtp) * Bug Fixes * Fix abort not aborting problem * Fix -p option not working for god binary diff --git a/lib/god/contact.rb b/lib/god/contact.rb index c382183..7f54fc1 100644 --- a/lib/god/contact.rb +++ b/lib/god/contact.rb @@ -3,7 +3,7 @@ module God class Contact include Configurable - attr_accessor :name, :group, :throttle + attr_accessor :name, :group, :info def self.generate(kind) sym = kind.to_s.capitalize.gsub(/_(.)/){$1.upcase}.intern diff --git a/lib/god/contacts/email.rb b/lib/god/contacts/email.rb index 372b390..a8db376 100644 --- a/lib/god/contacts/email.rb +++ b/lib/god/contacts/email.rb @@ -13,7 +13,12 @@ module God self.delivery_method = :smtp - self.server_settings = {} + self.server_settings = {:address => 'localhost', + :port => 25} + # :domain + # :user_name + # :password + # :authentication self.format = lambda do |name, email, message, time, priority, category| <<-EOF @@ -41,14 +46,24 @@ Category: #{category} begin body = Email.format.call(self.name, self.email, message, time, priority, category) - puts body - puts - # Net::SMTP.start('localhost', 25) do |smtp| - # smtp.send_message body, Email.message_settings[:from], self.email - # end + args = [Email.server_settings[:address], Email.server_settings[:port]] + if Email.server_settings[:authentication] + args << Email.server_settings[:domain] + args << Email.server_settings[:user_name] + args << Email.server_settings[:password] + args << Email.server_settings[:authentication] + end + + Net::SMTP.start(*args) do |smtp| + smtp.send_message body, Email.message_settings[:from], self.email + end + + self.info = "sent email to #{self.email}" rescue => e puts e.message puts e.backtrace.join("\n") + + self.info = "failed to send email to #{self.email}: #{e.message}" end end end diff --git a/lib/god/hub.rb b/lib/god/hub.rb index 3a4ac3e..04b3439 100644 --- a/lib/god/hub.rb +++ b/lib/god/hub.rb @@ -55,11 +55,11 @@ module God result = condition.test # log - self.log(watch, metric, condition, result) + messages = self.log(watch, metric, condition, result) # notify if condition.notify - self.notify(condition, msg) + self.notify(condition, messages.last) end # after-condition @@ -105,34 +105,41 @@ module God def self.handle_event(condition) Thread.new do - metric = self.directory[condition] + begin + metric = self.directory[condition] - unless metric.nil? - watch = metric.watch + unless metric.nil? + watch = metric.watch - watch.mutex.synchronize do - # log - self.log(watch, metric, condition, true) + watch.mutex.synchronize do + # log + messages = self.log(watch, metric, condition, true) - # notify - if condition.notify - self.notify(condition, msg) - end + # notify + if condition.notify + self.notify(condition, messages.last) + end - # get the destination - dest = - if condition.transition - # condition override - condition.transition - else - # regular - metric.destination && metric.destination[true] - end + # get the destination + dest = + if condition.transition + # condition override + condition.transition + else + # regular + metric.destination && metric.destination[true] + end - if dest - watch.move(dest) + if dest + watch.move(dest) + end end end + rescue => e + message = format("Unhandled exception (%s): %s\n%s", + e.class, e.message, e.backtrace.join("\n")) + Syslog.crit message + abort message end end end @@ -140,35 +147,34 @@ module God # helpers def self.log(watch, metric, condition, result) + status = + if (metric.destination && metric.destination.keys.size == 2) || result == true + "[trigger]" + else + "[ok]" + end + + messages = [] + # log info if available if condition.info - begin - status = - if (metric.destination && metric.destination.keys.size == 2) || result == true - "[trigger]" - else - "[ok]" - end - - Array(condition.info).each do |condition_info| - msg = "#{watch.name} #{status} #{condition_info} (#{condition.base_name})" - Syslog.debug(msg) - LOG.log(watch, :info, msg % []) - end - rescue Exception => e - puts e.message - puts e.backtrace.join("\n") + Array(condition.info).each do |condition_info| + messages << "#{watch.name} #{status} #{condition_info} (#{condition.base_name})" + Syslog.debug(messages.last) + LOG.log(watch, :info, messages.last % []) end else - msg = "#{watch.name} [unknown] (#{condition.base_name})" - Syslog.debug(msg) - LOG.log(watch, :info, msg % []) + messages << "#{watch.name} #{status} (#{condition.base_name})" + Syslog.debug(messages.last) + LOG.log(watch, :info, messages.last % []) end # log - msg = watch.name + ' ' + condition.base_name + " [#{result}] " + self.dest_desc(metric, condition) - Syslog.debug(msg) - LOG.log(watch, :debug, msg) + debug_message = watch.name + ' ' + condition.base_name + " [#{result}] " + self.dest_desc(metric, condition) + Syslog.debug(debug_message) + LOG.log(watch, :debug, debug_message) + + messages end def self.dest_desc(metric, condition) @@ -184,24 +190,23 @@ module God end def self.notify(condition, message) - begin - spec = Contact.normalize(condition.notify) + spec = Contact.normalize(condition.notify) - # resolve contacts - resolved_contacts = - spec[:contacts].inject([]) do |acc, contact_name_or_group| - acc += Array(God.contacts[contact_name_or_group] || God.contact_groups[contact_name_or_group]) - acc - end + # resolve contacts + resolved_contacts = + spec[:contacts].inject([]) do |acc, contact_name_or_group| + acc += Array(God.contacts[contact_name_or_group] || God.contact_groups[contact_name_or_group]) + acc + end + + # notify each contact + resolved_contacts.each do |c| + c.notify(message, Time.now, spec[:priority], spec[:category]) - p resolved_contacts + msg = "#{condition.watch.name} #{c.info ? c.info : "notification sent for contact: #{c.name}"} (#{c.base_name})" - resolved_contacts.each do |c| - c.notify(message, Time.now, spec[:priority], spec[:category]) - end - rescue => e - puts e.message - puts e.backtrace.join("\n") + Syslog.debug(msg) + LOG.log(condition.watch, :info, msg % []) end end end diff --git a/test/configs/contact/contact.god b/test/configs/contact/contact.god index f102d29..bae840e 100644 --- a/test/configs/contact/contact.god +++ b/test/configs/contact/contact.god @@ -1,4 +1,13 @@ -God::Contacts::Email.message_settings = {:from => 'god@powerset.com'} +God::Contacts::Email.message_settings = {:from => 'support@gravatar.com'} + +God::Contacts::Email.server_settings = { + :address => "mail.authsmtp.com", + :port => 2525, + :domain => "gravatar.com", + :authentication => :plain, + :user_name => "xxx", + :password => "yyy" +} God.contact(:email) do |c| c.name = 'tom' @@ -46,7 +55,7 @@ God.watch do |w| # start if process is not running w.transition(:up, :start) do |on| on.condition(:process_exits) do |c| - c.notify = {:contacts => ['developers', 'kevin'], :priority => 1, :category => 'product'} + c.notify = {:contacts => ['tom'], :priority => 1, :category => 'product'} end end -- 2.11.4.GIT