11

有谁知道像使用 Health Monitoring 一样限制 Elmah 在一段时间内发送的电子邮件数量的好方法?

我希望能够将每个页面中每个错误的电子邮件限制为仅每小时一次的电子邮件,以针对该特定错误和页面。

查看 elmah 文档,它看起来像使用:

void ErrorMail_Filtering(object sender, ExceptionFilterEventArgs e)
{
    // perform filtering here   
}

在 global.ascx 文件中可能是一个选项。我可以为每个应用程序设置一个静态对象,其中包含一些错误详细信息和记录的时间,并检查它并在需要时取消电子邮件通知?

有没有人有更好的解决方案或他们现在使用的示例?

4

4 回答 4

7

我使用与您的问题相同的方法编写了此文件。似乎工作得很好。

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;
}
于 2013-07-15T09:49:48.413 回答
4

我不知道 Elmah 是否有这种能力(文档没有提到),但是 ASP.NET 的健康监控有:http ://aspnet.4guysfromrolla.com/articles/032107-1.aspx

我最终为我的 CMS 编写了自己的事件日志记录、通知和汇总系统...我对每个异常的堆栈跟踪进行哈希处理,并使用它来“汇总”类似的事件(网络应用程序可能会在更少的时间内获得数千个异常如果出现问题,则超过一秒钟)。

我将通知期限配置为 1 天 - 我每天只收到第一个错误实例的通知。总是保存最新的错误实例,但较旧的实例被“清理”到最后 20 个左右,具体取决于频率等......

它与身份验证系统集成,因此管理员/开发人员可以获得他们订阅的事件的“收件箱”,并且可以实时查看调试信息,同时防止未经身份验证的用户看到任何调试信息。

真的很好......而且由于它是通用的,它也适用于非错误事件,如出版物、用户更改通知等。

我很好奇是否有人会对作为图书馆公开的那种系统感兴趣?

于 2010-01-04T16:35:51.950 回答
2

我遇到了类似的问题,并选择对 ELMAH 使用 log-to-SQL 方法。我在我的 Web 服务器上使用了 SQLExpress 2008(免费版),然后设置 SQL Reporting 以每天早上发送摘要电子邮件。

这种方法不需要编码,只需设置 SQL 服务器和报告服务。它的好处是让您可以在几个月的错误日志上运行报告,而不仅仅是每天查看它们。此外,您可以根据需要随时安排报告。

ELMAH wiki 页面包含有关如何设置 web.config 以指向 SQL 服务器的信息。一旦数据在 SQL 中,有很多选项可以获取数据,但我发现 SQL Express 报告服务非常适合我的需求。

于 2010-01-04T16:29:53.257 回答
0

这个作为 Elmah 包装器的 codeplex 项目 ASP.NET Exception Reporting 看起来很有希望。http://aspexceptionreporter.codeplex.com/

于 2010-01-04T21:04:05.260 回答