Does anyone know of a good way to limit the number of emails sent by Elmah during a time period like you can with Health Monitoring?
I want to be able to limit the emails for each error from each page to only an email once an hour or so for that particular error and page.
Looking at the elmah documentation it looks like using:
void ErrorMail_Filtering开发者_开发知识库(object sender, ExceptionFilterEventArgs e)
{
// perform filtering here
}
in the global.ascx file might be an option. I could setup a static object per application that contains some the error details and the time logged and check it and cancel the email notification if need be?
Do anyone have a better solution or an example of what they are using now?
I wrote this using the same method as in your question. Seems to work nicely.
public static DateTime RoundUp(this DateTime dt, TimeSpan d)
{
return new DateTime(((dt.Ticks + d.Ticks - 1) / d.Ticks) * d.Ticks);
}
static ConcurrentDictionary<int, KeyValuePair<DateTime, string>> _concurrent = new ConcurrentDictionary<int, KeyValuePair<DateTime, string>>();
/// <summary>
/// This is an Elmah event used by the elmah engine when sending out emails. It provides an opportunity to weed out
/// irrelavent emails.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void ErrorMail_Filtering(object sender, ExceptionFilterEventArgs e)
{
preventSpammingDigestEmail(e);
}
/// <summary>
/// Prevents spamming by throttling emails to 5 minute intervals.
/// </summary>
/// <param name="e"></param>
private static void preventSpammingDigestEmail(ExceptionFilterEventArgs e)
{
DateTime roundedTimeStamp = DateTime.Now.RoundUp(TimeSpan.FromMinutes(5));
string serialisedException = Util.SerializeException(e.Exception);
var lastRaisedException = new KeyValuePair<DateTime, string>
(roundedTimeStamp, serialisedException);
int key = lastRaisedException.GetHashCode();
bool errorHasAlreadyBeenRaised = _concurrent.ContainsKey(key);
// If event has already been raised in the last five minutes dont raise again
if (errorHasAlreadyBeenRaised)
{
e.Dismiss();
return;
}
// Record that it has been raised
_concurrent.TryAdd(key, lastRaisedException);
// Clean up existing entries
Task.Factory.StartNew(() =>
{
var toRemove =
_concurrent.Where(pair => pair.Value.Key < DateTime.Now.Date).Select(pair => pair.Key).ToArray();
foreach (var i in toRemove)
{
KeyValuePair<DateTime, string> keyValuePair;
_concurrent.TryRemove(i, out keyValuePair);
}
});
}
private static string SerializeException(Exception e, string exceptionMessage = "")
{
if (e == null)
return String.Empty;
exceptionMessage = String.Format("{0}{1}{2}\n{3}", exceptionMessage, (exceptionMessage == String.Empty)
? String.Empty
: "\n\n", e.Message, e.StackTrace);
if (e.InnerException != null)
exceptionMessage = SerializeException(e.InnerException, exceptionMessage);
return exceptionMessage;
}
I don't know if Elmah has that capability (the docs don't mention it), but ASP.NET's health monitoring does: https://web.archive.org/web/20210513222150/http://aspnet.4guysfromrolla.com/articles/032107-1.aspx
I ended up writing my own event logging, notification, and rollup system for my CMS... I hash the stack trace of each exception and use it to 'roll-up' similar events (a web app may get thousands of exceptions in less than a second if something goes wrong).
I configured my notification period to 1 day - I only get notified of the first instance of an error each day. The latest instance of an error is always saved, but older instances are 'cleaned up' to the last 20 or so, depending upon frequency, etc....
It integrates with the authentication system, so administrators/developers get an 'inbox' of events they have subscribed to, and can look at debug info in real time, while preventing unathenticated users from seeing any debugging info at all.
Really nice... And since it's generic, it works for non-error events also, like publications, user change notifications, etc.
I'm curious if anyone would be interested in that kind of system exposed as a library?
I had a similar problem and opted to use the log-to-SQL method for ELMAH. I used SQLExpress 2008 (free-version) on my Web server and then setup SQL Reporting to send digest emails every morning.
This method required no coding, just setup of the SQL server and reporting services. It has the benefit of letting you run reports on months of error logs rather than just seeing them daily. In addition, though, you can schedule reports as frequently as you like.
The ELMAH wiki page has information on how to setup the web.config to point to a SQL server. There are many options for getting the data out, once the data is in SQL but I find the SQL Express reporting services were perfect for my needs.
This codeplex project ASP.NET Exception Reporting which is a wrapper for Elmah looks promising. http://aspexceptionreporter.codeplex.com/
精彩评论