限制 Elmah 发送的电子邮件数量

11

有人知道如何像健康监控那样限制Elmah在一段时间内发送的电子邮件的好方法吗?

我希望能够将每个页面中出现的每个错误的电子邮件限制为每个错误和页面每小时只发送一次电子邮件。

查看 elmah 文档,似乎可以使用:

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

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

是否有更好的解决方案或现在正在使用的示例?

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;
}

1
我不想污染答案,但这是代码。 public class Util { private static string SerializeException(Exception e, string exceptionMessage = string.Empty) { 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; } } - Mantisimo

4

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

我最终为我的 CMS 编写了自己的事件日志记录、通知和汇总系统…… 我对每个异常的堆栈跟踪进行哈希处理,并使用它来“汇总”类似的事件(如果出现问题,Web 应用程序可能在不到一秒钟内收到数千个异常)。

我将通知周期配置为 1 天 - 每天只会通知第一个错误实例。最新的错误实例始终会被保存,但旧的实例会根据频率等因素“清理”到最后的 20 个左右……

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

非常好...而且由于它是通用的,它也适用于非错误事件,比如出版物、用户更改通知等。
我很好奇是否有人对将这种系统作为库公开感兴趣?

1
我认为人们会感兴趣,或者至少我会。 - beckelmw

2
我遇到了类似的问题,选择使用ELMAH的log-to-SQL方法。我在Web服务器上使用了SQLExpress 2008(免费版本),然后设置了SQL Reporting每天早上发送摘要电子邮件。
这种方法不需要编码,只需设置SQL服务器和报告服务即可。它具有让您运行月度错误日志报告而不仅仅是每天查看它们的好处。此外,您可以随意安排报告的频率。
ELMAH wiki页面提供了有关如何设置web.config以指向SQL服务器的信息。一旦数据在SQL中,有许多获取数据的选项,但我发现SQL Express报告服务非常适合我的需求。

这看起来很合理。但在这种特定情况下,我没有那种访问权限,尽管对于我的项目,我可能会选择这种方法。 - beckelmw

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接