コード例 #1
0
        private object ProcessNotification(IMessage<ErrorNotification> message) {
            int emailsSent = 0;
            ErrorNotification errorNotification = message.GetBody();
            Log.Trace().Message("Process notification: project={0} error={1} stack={2}", errorNotification.ProjectId, errorNotification.ErrorId, errorNotification.ErrorStackId).Write();

            var project = _projectRepository.GetByIdCached(errorNotification.ProjectId);
            if (project == null) {
                Log.Error().Message("Could not load project {0}.", errorNotification.ProjectId).Write();
                return null;
            }
            Log.Trace().Message("Loaded project: name={0}", project.Name).Write();

            var organization = _organizationRepository.GetByIdCached(project.OrganizationId);
            if (organization == null) {
                Log.Error().Message("Could not load organization {0}.", project.OrganizationId).Write();
                return null;
            }
            Log.Trace().Message("Loaded organization: name={0}", organization.Name).Write();

            var stack = _stackRepository.GetById(errorNotification.ErrorStackId);
            if (stack == null) {
                Log.Error().Message("Could not load stack {0}.", errorNotification.ErrorStackId).Write();
                return null;
            }

            if (!organization.HasPremiumFeatures) {
                Log.Trace().Message("Skipping because organization does not have premium features.").Write();
                return null;
            }

            if (stack.DisableNotifications || stack.IsHidden) {
                Log.Trace().Message("Skipping because stack notifications are disabled or it's hidden.").Write();
                return null;
            }

            Log.Trace().Message("Loaded stack: title={0}", stack.Title).Write();
            int totalOccurrences = stack.TotalOccurrences;

            // after the first 5 occurrences, don't send a notification for the same stack more then once every 15 minutes
            var lastTimeSent = _cacheClient.Get<DateTime>(String.Concat("NOTIFICATION_THROTTLE_", errorNotification.ErrorStackId));
            if (totalOccurrences > 5 && !errorNotification.IsRegression && lastTimeSent != DateTime.MinValue &&
                lastTimeSent > DateTime.Now.AddMinutes(-15)) {
                Log.Info().Message("Skipping message because of throttling: last sent={0} occurrences={1}", lastTimeSent, totalOccurrences).Write();
                return null;
            }

            foreach (var kv in project.NotificationSettings) {
                var settings = kv.Value;
                Log.Trace().Message("Processing notification: user={0}", kv.Key).Write();

                var user = _userRepository.GetById(kv.Key);
                if (user == null || String.IsNullOrEmpty(user.EmailAddress)) {
                    Log.Error().Message("Could not load user {0} or blank email address {1}.", kv.Key, user != null ? user.EmailAddress : "").Write();
                    continue;
                }

                if (!user.IsEmailAddressVerified) {
                    Log.Info().Message("User {0} with email address {1} has not been verified.", kv.Key, user != null ? user.EmailAddress : "").Write();
                    continue;
                }

                if (!user.EmailNotificationsEnabled) {
                    Log.Trace().Message("User {0} with email address {1} has email notifications disabled.", kv.Key, user != null ? user.EmailAddress : "").Write();
                    continue;
                }

                if (!user.OrganizationIds.Contains(project.OrganizationId)) {
                    // TODO: Should this notification setting be deleted?
                    Log.Error().Message("Unauthorized user: project={0} user={1} organization={2} error={3}", project.Id, kv.Key,
                        project.OrganizationId, errorNotification.ErrorId).Write();
                    continue;
                }

                Log.Trace().Message("Loaded user: email={0}", user.EmailAddress).Write();

                bool shouldReportOccurrence = settings.Mode != NotificationMode.None;
                bool shouldReportCriticalError = settings.ReportCriticalErrors && errorNotification.IsCritical;
                bool shouldReportRegression = settings.ReportRegressions && errorNotification.IsRegression;

                Log.Trace().Message("Settings: mode={0} critical={1} regression={2} 404={3} bots={4}",
                    settings.Mode, settings.ReportCriticalErrors,
                    settings.ReportRegressions, settings.Report404Errors,
                    settings.ReportKnownBotErrors).Write();
                Log.Trace().Message("Should process: occurrence={0} critical={1} regression={2}",
                    shouldReportOccurrence, shouldReportCriticalError,
                    shouldReportRegression).Write();

                if (settings.Mode == NotificationMode.New && !errorNotification.IsNew) {
                    shouldReportOccurrence = false;
                    Log.Trace().Message("Skipping because message is not new.").Write();
                }

                // check for 404s if the user has elected to not report them
                if (shouldReportOccurrence && settings.Report404Errors == false && errorNotification.Code == "404") {
                    shouldReportOccurrence = false;
                    Log.Trace().Message("Skipping because message is 404.").Write();
                }

                // check for known bots if the user has elected to not report them
                if (shouldReportOccurrence && settings.ReportKnownBotErrors == false &&
                    !String.IsNullOrEmpty(errorNotification.UserAgent)) {
                    ClientInfo info = null;
                    try {
                        info = Parser.GetDefault().Parse(errorNotification.UserAgent);
                    } catch (Exception ex) {
                        Log.Warn().Project(errorNotification.ProjectId).Message("Unable to parse user agent {0}. Exception: {1}",
                            errorNotification.UserAgent, ex.Message).Write();
                    }

                    if (info != null && info.Device.IsSpider) {
                        shouldReportOccurrence = false;
                        Log.Trace().Message("Skipping because message is bot.").Write();
                    }
                }

                // stack being set to send all will override all other settings
                if (!shouldReportOccurrence && !shouldReportCriticalError && !shouldReportRegression)
                    continue;

                var model = new ErrorNotificationModel(errorNotification) {
                    ProjectName = project.Name,
                    TotalOccurrences = totalOccurrences
                };

                // don't send notifications in non-production mode to email addresses that are not on the outbound email list.
                if (Settings.Current.WebsiteMode != WebsiteMode.Production
                    && !Settings.Current.AllowedOutboundAddresses.Contains(v => user.EmailAddress.ToLowerInvariant().Contains(v))) {
                    Log.Trace().Message("Skipping because email is not on the outbound list and not in production mode.").Write();
                    continue;
                }

                Log.Trace().Message("Sending email to {0}...", user.EmailAddress).Write();
                _mailer.SendNotice(user.EmailAddress, model);
                emailsSent++;
                Log.Trace().Message("Done sending email.").Write();
            }

            // if we sent any emails, mark the last time a notification for this stack was sent.
            if (emailsSent > 0)
                _cacheClient.Set(String.Concat("NOTIFICATION_THROTTLE_", errorNotification.ErrorStackId), DateTime.Now, DateTime.Now.AddMinutes(15));

            return null;
        }
コード例 #2
0
ファイル: NullMailer.cs プロジェクト: khoussem/Exceptionless
 public Task SendNoticeAsync(string emailAddress, ErrorNotificationModel notification) {
     return Task.Delay(0);
 }
コード例 #3
0
 public Task SendNoticeAsync(string emailAddress, ErrorNotificationModel notification) {
     return Task.Run(() => SendNotice(emailAddress, notification));
 }
コード例 #4
0
ファイル: NullMailer.cs プロジェクト: khoussem/Exceptionless
 public void SendNotice(string emailAddress, ErrorNotificationModel notification) {}
コード例 #5
0
        public void SendNotice(string emailAddress, ErrorNotificationModel notification) {
            string notificationType = String.Concat(notification.TypeName, " Occurrence");
            if (notification.IsNew)
                notificationType = String.Concat("New ", notification.TypeName);
            else if (notification.IsRegression)
                notificationType = String.Concat(notification.TypeName, " Regression");

            if (notification.IsCritical)
                notificationType = String.Concat("Critical ", notificationType);

            notification.BaseUrl = Settings.Current.BaseURL;
            notification.NotificationType = notificationType;

            MailMessage msg = _emailGenerator.GenerateMessage(notification, "Notice");
            msg.To.Add(emailAddress);
            msg.Headers.Add("X-Mailer-Machine", Environment.MachineName);
            msg.Headers.Add("X-Mailer-Date", DateTime.Now.ToString());
            SendMessage(msg);
        }