Limiting the Number of Emails Sent By Elmah

后端 未结 4 1528
有刺的猬
有刺的猬 2021-02-04 11:29

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 email

相关标签:
4条回答
  • 2021-02-04 11:42

    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.

    0 讨论(0)
  • 2021-02-04 11:43

    This codeplex project ASP.NET Exception Reporting which is a wrapper for Elmah looks promising. http://aspexceptionreporter.codeplex.com/

    0 讨论(0)
  • 2021-02-04 12:05

    I don't know if Elmah has that capability (the docs don't mention it), but ASP.NET's health monitoring does: 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?

    0 讨论(0)
  • 2021-02-04 12:08

    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);
                }
            });
    }
    
    0 讨论(0)
提交回复
热议问题