aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick J Cherry <patrick@bytemark.co.uk>2011-07-08 17:24:08 +0100
committerPatrick J Cherry <patrick@bytemark.co.uk>2011-07-08 17:24:08 +0100
commit1ac431fa21907a2a95d87901825cff3dc462746b (patch)
treebee0d55b3fb936bdd77095cdb32970379f4c82d0
parentfdfd98e5117b269d1f30dfbbd9c1cf2cf037658a (diff)
Added first basic history functionality, and rejigged when notify is called for
an alert.
-rw-r--r--lib/mauve/alert.rb204
-rw-r--r--lib/mauve/alert_changed.rb4
-rw-r--r--lib/mauve/alert_group.rb2
-rw-r--r--lib/mauve/history.rb26
-rw-r--r--lib/mauve/notifiers/email.rb6
-rw-r--r--lib/mauve/notifiers/sms_aql.rb19
-rw-r--r--lib/mauve/notifiers/templates/email.html.erb6
-rw-r--r--lib/mauve/notifiers/templates/email.txt.erb6
-rw-r--r--lib/mauve/notifiers/templates/xmpp.txt.erb6
-rw-r--r--lib/mauve/notifiers/xmpp.rb12
-rw-r--r--lib/mauve/person.rb2
-rw-r--r--lib/mauve/server.rb2
-rw-r--r--views/alert.haml10
13 files changed, 192 insertions, 113 deletions
diff --git a/lib/mauve/alert.rb b/lib/mauve/alert.rb
index 7768f50..bea2fc4 100644
--- a/lib/mauve/alert.rb
+++ b/lib/mauve/alert.rb
@@ -1,5 +1,6 @@
require 'mauve/proto'
require 'mauve/alert_changed'
+require 'mauve/history'
require 'mauve/datamapper'
require 'sanitize'
@@ -60,7 +61,7 @@ module Mauve
property :id, Serial
property :alert_id, String, :required => true, :unique_index => :alert_index, :length=>256
property :source, String, :required => true, :unique_index => :alert_index, :length=>512
- property :subject, String, :length=>512, :length=>512
+ property :subject, String, :length=>512
property :summary, String, :length=>1024
property :detail, Text, :length=>65535
property :importance, Integer, :default => 50
@@ -75,11 +76,13 @@ module Mauve
property :will_clear_at, DateTime
property :will_raise_at, DateTime
property :will_unacknowledge_at, DateTime
-# property :will_unacknowledge_after, Integer
-
has n, :changes, :model => AlertChanged
+ has n, :histories, :model => Mauve::History
has 1, :alert_earliest_date
+ before :save, :take_copy_of_changes
+ after :save, :notify_if_needed
+
validates_with_method :check_dates
def to_s
@@ -141,73 +144,121 @@ module Mauve
def subject; attribute_get(:subject) || attribute_get(:source) || "not set" ; end
def detail; attribute_get(:detail) || "_No detail set._" ; end
- def subject=(subject); set_changed_if_different( :subject, subject ); end
- def summary=(summary); set_changed_if_different( :summary, summary ); end
+ # def subject=(subject); set_changed_if_different( :subject, subject ); end
+ # def summary=(summary); set_changed_if_different( :summary, summary ); end
# def source=(source); attribute_set( :source, source ); end
# def detail=(detail); attribute_set( :detail, detail ); end
protected
- def set_changed_if_different(attribute, value)
- return if self.__send__(attribute) == value
- self.update_type ||= :changed
- attribute_set(attribute.to_sym, value)
+ #def set_changed_if_different(attribute, value)
+ # return if self.__send__(attribute) == value
+ # self.update_type ||= "changed"
+ # attribute_set(attribute.to_sym, value)
+ #end
+
+ #
+ # This allows us to take a copy of the changes before we save.
+ #
+ def take_copy_of_changes
+ @changes_before_save = Hash.new
+ self.original_attributes.each do |k,v|
+ @changes_before_save[k.name] = v
+ end
end
-
+
+ #
+ # This sends notifications. It is called after each save.
+ #
+ def notify_if_needed
+ #
+ # Make sure we don't barf
+ #
+ @changes_before_save ||= Hash.new
+
+ is_a_change = [:subject, :summary].any?{|k| @changes_before_save.keys.include?(k)}
+
+ #
+ # We notify if the update type has changed, or if the update type is
+ # "raised", and the above is_a_change condition is true
+ #
+ if @changes_before_save.has_key?(:update_type) or (self.update_type == "raised" and is_a_change)
+ self.notify
+
+ h = History.new(:alert => self, :type => "update")
+
+ if self.update_type == "acknowledged"
+ h.event = "ACKNOWLEDGED by #{self.acknowledged_by} until #{self.will_unacknowledge_at}"
+
+ elsif is_a_change
+ h.event = "CHANGED: "
+ h.event += @changes_before_save.keys.collect{|k| "#{k.to_s}: #{@changes_before_save[k]} -> #{self.__send__(k)}"}.join(", ")
+
+ else
+ h.event = self.update_type.upcase
+
+ end
+
+ h.save
+ end
+
+ true
+ end
+
public
+ def notify
+ self.alert_group.notify(self)
+ end
+
def acknowledge!(person, ack_until = Time.now+3600)
raise ArgumentError unless person.is_a?(Person)
raise ArgumentError unless ack_until.is_a?(Time)
-
+ raise ArgumentError, "Cannot acknowledge a cleared alert" if self.cleared?
+
self.acknowledged_by = person.username
self.acknowledged_at = MauveTime.now
self.will_unacknowledge_at = ack_until
- self.update_type = :acknowledged
+ self.update_type = "acknowledged"
logger.error("Couldn't save #{self}") unless save
- AlertGroup.notify([self]) if self.raised?
end
def unacknowledge!
self.acknowledged_by = nil
self.acknowledged_at = nil
self.will_unacknowledge_at = nil
- self.update_type = (raised? ? :raised : :cleared)
+ self.update_type = (raised? ? "raised" : "cleared")
logger.error("Couldn't save #{self}") unless save
- AlertGroup.notify([self]) if self.raised?
end
- def raise!
- already_raised = raised? && !acknowledged?
+ def raise!(at = MauveTime.now)
self.acknowledged_by = nil
self.acknowledged_at = nil
self.will_unacknowledge_at = nil
- self.raised_at = MauveTime.now
+ self.raised_at = at if self.raised_at.nil?
self.will_raise_at = nil
self.cleared_at = nil
# Don't clear will_clear_at
- self.update_type = :raised
-
+ self.update_type = "raised" if self.update_type.nil? or self.update_type != "changed" or self.original_attributes[Alert.properties[:update_type]] == "cleared"
+
+ logger.debug("saving #{self.inspect}")
logger.error("Couldn't save #{self}") unless save
- AlertGroup.notify([self]) unless already_raised
end
- def clear!(notify=true)
- already_cleared = cleared?
+ def clear!(at = MauveTime.now)
self.acknowledged_by = nil
self.acknowledged_at = nil
self.will_unacknowledge_at = nil
self.raised_at = nil
# Don't clear will_raise_at
- self.cleared_at = MauveTime.now
+ self.cleared_at = at if self.cleared_at.nil?
self.will_clear_at = nil
- self.update_type = :cleared
+ self.update_type = "cleared"
logger.error("Couldn't save #{self}") unless save
- AlertGroup.notify([self]) unless !notify || already_cleared
end
# Returns the time at which a timer loop should call poll_event to either
@@ -223,19 +274,29 @@ module Mauve
(will_raise_at and will_raise_at.to_time <= MauveTime.now)
clear! if will_clear_at && will_clear_at.to_time <= MauveTime.now
end
-
+
+
+ #
+ # Tests to see if an alert is raised/acknowledged given a certain set of
+ # dates/times.
+ #
+ #
+
def raised?
!raised_at.nil? and (cleared_at.nil? or raised_at > cleared_at)
end
-
+
def acknowledged?
!acknowledged_at.nil?
end
-
+
+ #
+ # Cleared is just the opposite of raised.
+ #
def cleared?
- !raised?
+ !raised?
end
-
+
class << self
#
@@ -310,7 +371,7 @@ module Mauve
alerts_updated = []
- logger.debug("Alert update received from wire: #{update.inspect.split.join(", ")}")
+ logger.debug("Alert update received from wire: #{update.inspect.split("\n").join(" ")}")
#
# Transmission time helps us determine any time offset
@@ -357,14 +418,6 @@ module Mauve
alert_db = first(:alert_id => alert.id, :source => update.source) ||
new(:alert_id => alert.id, :source => update.source)
-
- #
- # Work out what state the alert was in before receiving this update.
- #
- was_raised = alert_db.raised?
- was_cleared = alert_db.cleared?
- was_acknowledged = alert_db.acknowledged?
-
alert_db.update_type = nil
##
@@ -380,7 +433,7 @@ module Mauve
# This prevents the raised time constantly changing on alerts
# that are already raised.
#
- alert_db.raised_at = raise_time unless was_raised or alert_db.raised_at.nil?
+ alert_db.raised_at = raise_time if alert_db.raised_at.nil?
alert_db.will_raise_at = nil
else
alert_db.raised_at = nil
@@ -393,7 +446,7 @@ module Mauve
#
# Don't reset the cleared_at time (see above for raised_at timings).
#
- alert_db.cleared_at = clear_time unless was_cleared or alert_db.cleared_at.nil?
+ alert_db.cleared_at = clear_time if alert_db.cleared_at.nil?
alert_db.will_clear_at = nil
else
alert_db.cleared_at = nil
@@ -401,33 +454,16 @@ module Mauve
end
end
- #
- # Clear old cleared_at time, if the raised_at time is newer
- #
- if alert_db.cleared_at && alert_db.raised_at && alert_db.cleared_at < alert_db.raised_at
- alert_db.cleared_at = nil
- end
-
- if alert_db.cleared?
- alert_db.update_type = :cleared
- else
- alert_db.update_type = :raised
- end
-
- #
- # If the alert is cleared ,or has just been raised unset the acknowledge dates.
- #
- if alert_db.acknowledged? and (alert_db.cleared? or (alert_db.raised? and !was_raised))
- alert_db.acknowledged_at = nil
- end
-
#
# Set the subject
#
if alert.subject and !alert.subject.empty?
alert_db.subject = Alert.remove_html(alert.subject)
else
- alert_db.subject = alert_db.source
+ #
+ # Use the source, Luke, but only when the subject hasn't already been set.
+ #
+ alert_db.subject = alert_db.source if alert_db.subject.nil?
end
alert_db.summary = Alert.remove_html(alert.summary) if alert.summary && !alert.summary.empty?
@@ -439,35 +475,24 @@ module Mauve
alert_db.importance = alert.importance if alert.importance != 0
- alert_db.update_type = :changed unless alert_db.update_type
-
- #
- # This decides if we notify.
+ #
+ # This will probably get overwritten below.
#
- should_notify = case alert_db.update_type.to_sym
- when :raised
- !was_raised
- when :acknowledged
- !was_acknowledged
- when :cleared
- !was_cleared
- else
- alert_db.raised?
- end
-
- alerts_updated << alert_db if should_notify
+ # alert_db.update_type = "changed" unless alert_db.update_type
alert_db.updated_at = reception_time
- logger.debug "Saving #{alert_db}"
-
- if !alert_db.save
- if alert_db.errors.respond_to?("full_messages")
- msg = alert_db.errors.full_messages
+ if alert_db.raised?
+ #
+ # If we're acknowledged, just save.
+ #
+ if alert_db.acknowledged?
+ alert_db.save
else
- msg = alert_db.errors.inspect
+ alert_db.raise!
end
- logger.error "Couldn't save update #{alert} because of #{msg}"
+ else
+ alert_db.clear!
end
end
@@ -481,15 +506,10 @@ module Mauve
:alert_id.not => alert_ids_mentioned,
:cleared_at => nil
).each do |alert_db|
- logger.debug "Replace: clearing #{alert_db.id}"
- alert_db.clear!(false)
- alerts_updated << alert_db
+ alert_db.clear!
end
end
- logger.debug "Got #{alerts_updated.length} alerts to notify about" if alerts_updated.length > 0
-
- AlertGroup.notify(alerts_updated)
end
def logger
diff --git a/lib/mauve/alert_changed.rb b/lib/mauve/alert_changed.rb
index ebcbbda..0b0f72a 100644
--- a/lib/mauve/alert_changed.rb
+++ b/lib/mauve/alert_changed.rb
@@ -61,11 +61,11 @@ module Mauve
# @return [Boolean] true if it was relevant, false otherwise.
def was_relevant_when_raised?
- if :acknowledged == update_type.to_sym and true == was_relevant
+ if "acknowledged" == update_type and true == was_relevant
return true
end
- return was_relevant if update_type.to_sym == :raised
+ return was_relevant if update_type == "raised"
previous = AlertChanged.first(:id.lt => id,
:alert_id => alert_id,
diff --git a/lib/mauve/alert_group.rb b/lib/mauve/alert_group.rb
index 4895200..75f97fd 100644
--- a/lib/mauve/alert_group.rb
+++ b/lib/mauve/alert_group.rb
@@ -104,7 +104,7 @@ module Mauve
unless alert.is_a?(Alert)
logger.warn "Got given a #{alert.class} instead of an Alert!"
- logger.debug caller.join("\n")
+ logger.debug caller.join("\n")
return false
end
diff --git a/lib/mauve/history.rb b/lib/mauve/history.rb
new file mode 100644
index 0000000..6c4969b
--- /dev/null
+++ b/lib/mauve/history.rb
@@ -0,0 +1,26 @@
+# encoding: UTF-8
+require 'mauve/datamapper'
+require 'log4r'
+
+module Mauve
+ class History
+ include DataMapper::Resource
+
+ # so .first always returns the most recent update
+ default_scope(:default).update(:order => [:created_at.desc, :id.desc])
+
+ property :id, Serial
+ property :alert_id, Integer, :required => true
+ property :type, String, :required => true, :default => "unknown"
+ property :event, Text, :required => true
+ property :created_at, DateTime
+
+ belongs_to :alert
+
+ def logger
+ Log4r::Logger.new self.class.to_s
+ end
+
+ end
+
+end
diff --git a/lib/mauve/notifiers/email.rb b/lib/mauve/notifiers/email.rb
index 75588f4..129afec 100644
--- a/lib/mauve/notifiers/email.rb
+++ b/lib/mauve/notifiers/email.rb
@@ -47,14 +47,20 @@ module Mauve
message = prepare_message(destination, alert, all_alerts, conditions)
args = [@server, @port]
args += [@username, @password, @login_method.to_sym] if @login_method
+ history = Mauve::History.new(:alert => alert, :type => :notification)
+
begin
Net::SMTP.start(*args) do |smtp|
smtp.send_message(message, @from, destination)
end
+ history.event = "Sent mail to #{destination}."
+ history.save
true
rescue StandardError => ex
logger.error "SMTP failure: #{ex.to_s}"
logger.debug ex.backtrace.join("\n")
+ history.event = "Failed to send mail to #{destination} due to #{ex.to_s}"
+ history.save
false
end
end
diff --git a/lib/mauve/notifiers/sms_aql.rb b/lib/mauve/notifiers/sms_aql.rb
index 856c494..b295e6c 100644
--- a/lib/mauve/notifiers/sms_aql.rb
+++ b/lib/mauve/notifiers/sms_aql.rb
@@ -41,12 +41,19 @@ module Mauve
'Content-Length' => opts_string.length.to_s
})
- raise response unless response.kind_of?(Net::HTTPSuccess)
-
- #
- # Woo -- return true!
- #
- true
+ history = Mauve::History.new(:alert => alert, :type => :notification)
+ if response.kind_of?(Net::HTTPSuccess)
+ history.event = "Sent SMS via AQL to #{destination}"
+ history.save
+ #
+ # Woo -- return true!
+ #
+ true
+ else
+ history.event = "Failed to send SMS via AQL to #{destination} due to #{response.class.to_s}"
+ history.save
+ false
+ end
end
protected
diff --git a/lib/mauve/notifiers/templates/email.html.erb b/lib/mauve/notifiers/templates/email.html.erb
index ab65b48..bf5aed5 100644
--- a/lib/mauve/notifiers/templates/email.html.erb
+++ b/lib/mauve/notifiers/templates/email.html.erb
@@ -2,10 +2,10 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><title></title></head><body>
<p><strong><%= alert.update_type.upcase %>:</strong> <%
-case alert.update_type.to_sym
-when :cleared
+case alert.update_type
+when "cleared"
%><%= alert.cleared_at.to_s_relative %><%
-when :acknowledged
+when "acknowledged"
%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by%><%
else
%><%= alert.raised_at.to_s_relative %><%
diff --git a/lib/mauve/notifiers/templates/email.txt.erb b/lib/mauve/notifiers/templates/email.txt.erb
index 57b9309..d112718 100644
--- a/lib/mauve/notifiers/templates/email.txt.erb
+++ b/lib/mauve/notifiers/templates/email.txt.erb
@@ -1,8 +1,8 @@
<%= alert.update_type.upcase %>: <%
-case alert.update_type.to_sym
-when :cleared
+case alert.update_type
+when "cleared"
%><%= alert.cleared_at.to_s_relative %><%
-when :acknowledged
+when "acknowledged"
%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by %><%
else
%><%= alert.raised_at.to_s_relative %><%
diff --git a/lib/mauve/notifiers/templates/xmpp.txt.erb b/lib/mauve/notifiers/templates/xmpp.txt.erb
index 331d7ef..2f86cb6 100644
--- a/lib/mauve/notifiers/templates/xmpp.txt.erb
+++ b/lib/mauve/notifiers/templates/xmpp.txt.erb
@@ -1,8 +1,8 @@
<%= alert.update_type.upcase %>: <%
-case alert.update_type.to_sym
-when :cleared
+case alert.update_type
+when "cleared"
%><%= alert.cleared_at.to_s_relative %><%
-when :acknowledged
+when "acknowledged"
%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by %><%
else
%><%= alert.raised_at.to_s_relative %><%
diff --git a/lib/mauve/notifiers/xmpp.rb b/lib/mauve/notifiers/xmpp.rb
index 4c30643..c4e1785 100644
--- a/lib/mauve/notifiers/xmpp.rb
+++ b/lib/mauve/notifiers/xmpp.rb
@@ -203,7 +203,17 @@ module Mauve
alert.to_s
end
- send_message(destination_jid, txt)
+ history = Mauve::History.new(:alert_id => alert.id, :type => :notification)
+
+ if send_message(destination_jid, txt)
+ history.event = "Sent XMPP message to #{destination_jid}"
+ history.save
+ true
+ else
+ history.event = "Failed to send XMPP message to #{destination_jid}"
+ history.save
+ false
+ end
end
# Sends a message to the destionation.
diff --git a/lib/mauve/person.rb b/lib/mauve/person.rb
index 2a6ddee..0290faf 100644
--- a/lib/mauve/person.rb
+++ b/lib/mauve/person.rb
@@ -217,7 +217,7 @@ module Mauve
def current_alerts
Alert.all_raised.select do |alert|
my_last_update = AlertChanged.first(:person => username, :alert_id => alert.id)
- my_last_update && my_last_update.update_type != :cleared
+ my_last_update && my_last_update.update_type != "cleared"
end
end
diff --git a/lib/mauve/server.rb b/lib/mauve/server.rb
index c985e15..51587c0 100644
--- a/lib/mauve/server.rb
+++ b/lib/mauve/server.rb
@@ -4,6 +4,7 @@ require 'socket'
# require 'mauve/datamapper'
require 'mauve/proto'
require 'mauve/alert'
+require 'mauve/history'
require 'mauve/mauve_thread'
require 'mauve/mauve_time'
require 'mauve/timer'
@@ -86,6 +87,7 @@ module Mauve
#
Alert.auto_upgrade!
AlertChanged.auto_upgrade!
+ History.auto_upgrade!
Mauve::AlertEarliestDate.create_view!
#
diff --git a/views/alert.haml b/views/alert.haml
index b752f35..7e7503f 100644
--- a/views/alert.haml
+++ b/views/alert.haml
@@ -56,7 +56,15 @@
= change.person
at
= change.at.to_s_human
-
+ %tr
+ %th History
+ %td
+ %ul
+ - @alert.histories.each do |history|
+ %li
+ = history.event
+ at
+ = (history.created_at.nil? ? "unkown" : history.created_at.to_s_human)
%h2 Actions
- if !@alert.acknowledged?
%form{:method => :post, :action => "/alert/#{@alert.id}/acknowledge"}