public MailMessage GetEventNotificationMailMessage(EventNotification model) { string messageOrSource = !String.IsNullOrEmpty(model.Event.Message) ? model.Event.Message : model.Event.Source; if (String.IsNullOrEmpty(messageOrSource)) return null; string notificationType = "Occurrence event"; if (model.IsNew) notificationType = "New event"; else if (model.IsRegression) notificationType = "Regression event"; if (model.IsCritical) notificationType = String.Concat("Critical ", notificationType.ToLower()); var requestInfo = model.Event.GetRequestInfo(); var mailerModel = new EventNotificationModel(model) { BaseUrl = Settings.Current.BaseURL, Subject = String.Concat(notificationType, ": ", messageOrSource.Truncate(120)), Message = model.Event.Message, Source = model.Event.Source, Url = requestInfo != null ? requestInfo.GetFullPath(true, true, true) : null }; return _emailGenerator.GenerateMessage(mailerModel, "Notice").ToMailMessage(); }
public MailMessage GetEventNotificationMailMessage(EventNotification model) { if (!ShouldHandle(model.Event)) return null; var error = model.Event.GetError(); var stackingTarget = error.GetStackingTarget(); var requestInfo = model.Event.GetRequestInfo(); string notificationType = String.Concat(error.Type, " Occurrence"); if (model.IsNew) notificationType = String.Concat("New ", error.Type); else if (model.IsRegression) notificationType = String.Concat(error.Type, " Regression"); if (model.IsCritical) notificationType = String.Concat("Critical ", notificationType); var mailerModel = new EventNotificationModel(model) { BaseUrl = Settings.Current.BaseURL, NotificationType = notificationType, Url = requestInfo != null ? requestInfo.GetFullPath(true, true) : null, Error = stackingTarget.Error, Method = stackingTarget.Method, }; return _emailGenerator.GenerateMessage(mailerModel, "Notice"); }
public override MailMessage GetEventNotificationMailMessage(EventNotification model) { if (!ShouldHandle(model.Event)) return null; var error = model.Event.GetSimpleError(); if (error == null) return null; var requestInfo = model.Event.GetRequestInfo(); string errorType = !String.IsNullOrEmpty(error.Type) ? error.Type : "Error"; string notificationType = String.Concat(errorType, " Occurrence"); if (model.IsNew) notificationType = String.Concat(!model.IsCritical ? "New " : "new ", errorType); else if (model.IsRegression) notificationType = String.Concat(errorType, " Regression"); if (model.IsCritical) notificationType = String.Concat("Critical ", notificationType); var mailerModel = new EventNotificationModel(model) { BaseUrl = Settings.Current.BaseURL, Subject = String.Concat(notificationType, ": ", error.Message.Truncate(120)), Message = error.Message, Url = requestInfo != null ? requestInfo.GetFullPath(true, true, true) : null }; return _emailGenerator.GenerateMessage(mailerModel, "NoticeError").ToMailMessage(); }
public override MailMessage GetEventNotificationMailMessage(EventNotification model) { if (!ShouldHandle(model.Event)) return null; var error = model.Event.GetError(); var stackingTarget = error?.GetStackingTarget(); if (stackingTarget?.Error == null) return null; var requestInfo = model.Event.GetRequestInfo(); string errorType = !String.IsNullOrEmpty(stackingTarget.Error.Type) ? stackingTarget.Error.Type : "Error"; string notificationType = String.Concat(errorType, " occurrence"); if (model.IsNew) notificationType = String.Concat(!model.IsCritical ? "New " : "new ", error.Type); else if (model.IsRegression) notificationType = String.Concat(errorType, " regression"); if (model.IsCritical) notificationType = String.Concat("Critical ", notificationType); var mailerModel = new EventNotificationModel(model) { BaseUrl = Settings.Current.BaseURL, Subject = String.Concat(notificationType, ": ", stackingTarget.Error.Message.Truncate(120)), Url = requestInfo?.GetFullPath(true, true, true), Message = stackingTarget.Error.Message, TypeFullName = errorType, MethodFullName = stackingTarget.Method?.GetFullName() }; return _emailGenerator.GenerateMessage(mailerModel, "NoticeError").ToMailMessage(); }
public EventNotificationModel(EventNotification notification) { Event = notification.Event; ProjectName = notification.ProjectName; IsNew = notification.IsNew; IsCritical = notification.IsCritical; IsRegression = notification.IsRegression; TotalOccurrences = notification.TotalOccurrences; }
public override MailMessage GetEventNotificationMailMessage(EventNotification model) { if (!ShouldHandle(model.Event)) return null; var mailerModel = new EventNotificationModel(model) { BaseUrl = Settings.Current.BaseURL, Subject = String.Concat("Feature: ", model.Event.Source.Truncate(120)), }; return _emailGenerator.GenerateMessage(mailerModel, "Notice").ToMailMessage(); }
public override MailMessage GetEventNotificationMailMessage(EventNotification model) { if (!ShouldHandle(model.Event)) return null; string notificationType = "Log Message"; if (model.IsNew) notificationType = "New Log Source"; else if (model.IsRegression) notificationType = "Log Regression"; if (model.IsCritical) notificationType = String.Concat("Critical ", notificationType.ToLower()); var requestInfo = model.Event.GetRequestInfo(); var mailerModel = new EventNotificationModel(model) { BaseUrl = Settings.Current.BaseURL, Subject = String.Concat(notificationType, ": ", model.Event.Source.Truncate(120)), Url = requestInfo != null ? requestInfo.GetFullPath(true, true, true) : model.Event.Source }; return _emailGenerator.GenerateMessage(mailerModel, "Notice").ToMailMessage(); }
protected async override Task<JobResult> RunInternalAsync(CancellationToken token) { QueueEntry<EventNotificationWorkItem> queueEntry = null; try { queueEntry = _queue.Dequeue(); } catch (Exception ex) { if (!(ex is TimeoutException)) return JobResult.FromException(ex, "An error occurred while trying to dequeue the next EventNotification: {0}", ex.Message); } if (queueEntry == null) return JobResult.Success; var eventModel = _eventRepository.GetById(queueEntry.Value.EventId); if (eventModel == null) { queueEntry.Abandon(); return JobResult.FailedWithMessage("Could not load event {0}.", queueEntry.Value.EventId); } var eventNotification = new EventNotification(queueEntry.Value, eventModel); bool shouldLog = eventNotification.Event.ProjectId != Settings.Current.InternalProjectId; int emailsSent = 0; Log.Trace().Message("Process notification: project={0} event={1} stack={2}", eventNotification.Event.ProjectId, eventNotification.Event.Id, eventNotification.Event.StackId).WriteIf(shouldLog); var project = _projectRepository.GetById(eventNotification.Event.ProjectId, true); if (project == null) { queueEntry.Abandon(); return JobResult.FailedWithMessage("Could not load project {0}.", eventNotification.Event.ProjectId); } Log.Trace().Message("Loaded project: name={0}", project.Name).WriteIf(shouldLog); var organization = _organizationRepository.GetById(project.OrganizationId, true); if (organization == null) { queueEntry.Abandon(); return JobResult.FailedWithMessage("Could not load organization {0}.", project.OrganizationId); } Log.Trace().Message("Loaded organization: name={0}", organization.Name).WriteIf(shouldLog); var stack = _stackRepository.GetById(eventNotification.Event.StackId); if (stack == null) { queueEntry.Abandon(); return JobResult.FailedWithMessage("Could not load stack {0}.", eventNotification.Event.StackId); } if (!organization.HasPremiumFeatures) { queueEntry.Complete(); Log.Info().Message("Skipping \"{0}\" because organization \"{1}\" does not have premium features.", eventNotification.Event.Id, eventNotification.Event.OrganizationId).WriteIf(shouldLog); return JobResult.Success; } if (stack.DisableNotifications || stack.IsHidden) { queueEntry.Complete(); Log.Info().Message("Skipping \"{0}\" because stack \"{1}\" notifications are disabled or stack is hidden.", eventNotification.Event.Id, eventNotification.Event.StackId).WriteIf(shouldLog); return JobResult.Success; } if (token.IsCancellationRequested) { queueEntry.Abandon(); return JobResult.Cancelled; } Log.Trace().Message("Loaded stack: title={0}", stack.Title).WriteIf(shouldLog); int totalOccurrences = stack.TotalOccurrences; // after the first 2 occurrences, don't send a notification for the same stack more then once every 30 minutes var lastTimeSent = _cacheClient.Get<DateTime>(String.Concat("notify:stack-throttle:", eventNotification.Event.StackId)); if (totalOccurrences > 2 && !eventNotification.IsRegression && lastTimeSent != DateTime.MinValue && lastTimeSent > DateTime.Now.AddMinutes(-30)) { queueEntry.Complete(); Log.Info().Message("Skipping message because of stack throttling: last sent={0} occurrences={1}", lastTimeSent, totalOccurrences).WriteIf(shouldLog); return JobResult.Success; } // don't send more than 10 notifications for a given project every 30 minutes var projectTimeWindow = TimeSpan.FromMinutes(30); string cacheKey = String.Concat("notify:project-throttle:", eventNotification.Event.ProjectId, "-", DateTime.UtcNow.Floor(projectTimeWindow).Ticks); long notificationCount = _cacheClient.Increment(cacheKey, 1, projectTimeWindow); if (notificationCount > 10 && !eventNotification.IsRegression) { queueEntry.Complete(); Log.Info().Project(eventNotification.Event.ProjectId).Message("Skipping message because of project throttling: count={0}", notificationCount).WriteIf(shouldLog); return JobResult.Success; } if (token.IsCancellationRequested) { queueEntry.Abandon(); return JobResult.Cancelled; } foreach (var kv in project.NotificationSettings) { var settings = kv.Value; Log.Trace().Message("Processing notification: user={0}", kv.Key).WriteIf(shouldLog); 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 : "").WriteIf(shouldLog); continue; } if (!user.EmailNotificationsEnabled) { Log.Info().Message("User {0} with email address {1} has email notifications disabled.", kv.Key, user != null ? user.EmailAddress : "").WriteIf(shouldLog); continue; } if (!user.OrganizationIds.Contains(project.OrganizationId)) { Log.Error().Message("Unauthorized user: project={0} user={1} organization={2} event={3}", project.Id, kv.Key, project.OrganizationId, eventNotification.Event.Id).Write(); continue; } Log.Trace().Message("Loaded user: email={0}", user.EmailAddress).WriteIf(shouldLog); bool shouldReportNewError = settings.ReportNewErrors && eventNotification.IsNew && eventNotification.Event.IsError(); bool shouldReportCriticalError = settings.ReportCriticalErrors && eventNotification.IsCritical && eventNotification.Event.IsError(); bool shouldReportRegression = settings.ReportEventRegressions && eventNotification.IsRegression; bool shouldReportNewEvent = settings.ReportNewEvents && eventNotification.IsNew; bool shouldReportCriticalEvent = settings.ReportCriticalEvents && eventNotification.IsCritical; bool shouldReport = shouldReportNewError || shouldReportCriticalError || shouldReportRegression || shouldReportNewEvent || shouldReportCriticalEvent; Log.Trace().Message("Settings: newerror={0} criticalerror={1} regression={2} new={3} critical={4}", settings.ReportNewErrors, settings.ReportCriticalErrors, settings.ReportEventRegressions, settings.ReportNewEvents, settings.ReportCriticalEvents).WriteIf(shouldLog); Log.Trace().Message("Should process: newerror={0} criticalerror={1} regression={2} new={3} critical={4}", shouldReportNewError, shouldReportCriticalError, shouldReportRegression, shouldReportNewEvent, shouldReportCriticalEvent).WriteIf(shouldLog); var requestInfo = eventNotification.Event.GetRequestInfo(); // check for known bots if the user has elected to not report them if (shouldReport && requestInfo != null && !String.IsNullOrEmpty(requestInfo.UserAgent)) { ClientInfo info = null; try { info = Parser.GetDefault().Parse(requestInfo.UserAgent); } catch (Exception ex) { Log.Warn().Project(eventNotification.Event.ProjectId).Message("Unable to parse user agent {0}. Exception: {1}", requestInfo.UserAgent, ex.Message).Write(); } var botPatterns = project.Configuration.Settings.ContainsKey(SettingsDictionary.KnownKeys.UserAgentBotPatterns) ? project.Configuration.Settings.GetStringCollection(SettingsDictionary.KnownKeys.UserAgentBotPatterns).ToList() : new List<string>(); if (info != null && info.Device.IsSpider || requestInfo.UserAgent.AnyWildcardMatches(botPatterns)) { shouldReport = false; Log.Info().Message("Skipping because event is from a bot \"{0}\".", requestInfo.UserAgent).WriteIf(shouldLog); } } if (!shouldReport) continue; var model = new EventNotificationModel(eventNotification) { 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.Info().Message("Skipping because email is not on the outbound list and not in production mode.").WriteIf(shouldLog); continue; } Log.Trace().Message("Sending email to {0}...", user.EmailAddress).Write(); _mailer.SendNotice(user.EmailAddress, model); emailsSent++; Log.Trace().Message("Done sending email.").WriteIf(shouldLog); } // if we sent any emails, mark the last time a notification for this stack was sent. if (emailsSent > 0) { _cacheClient.Set(String.Concat("notify:stack-throttle:", eventNotification.Event.StackId), DateTime.Now, DateTime.Now.AddMinutes(15)); Log.Info().Message("Notifications sent: event={0} stack={1} count={2}", eventNotification.Event.Id, eventNotification.Event.StackId, emailsSent).WriteIf(shouldLog); } queueEntry.Complete(); return JobResult.Success; }
public void SendNotice(string emailAddress, EventNotification model) { var message = _pluginManager.GetEventNotificationMailMessage(model); if (message == null) { Log.Warn().Message("Unable to create event notification mail message for event \"{0}\". User: \"{1}\"", model.EventId, emailAddress).Write(); return; } message.To = emailAddress; QueueMessage(message.ToMailMessage()); }
public Task SendNoticeAsync(string emailAddress, EventNotification notification) { return Task.Run(() => SendNotice(emailAddress, notification)); }
public void SendNotice(string emailAddress, EventNotification model) {}
public async Task SendNoticeAsync(string emailAddress, EventNotification model) { var message = _pluginManager.GetEventNotificationMailMessage(model); if (message == null) return; message.To = emailAddress; await QueueMessage(message.ToMailMessage()); }
public Task SendNoticeAsync(string emailAddress, EventNotification model) { var message = _pluginManager.GetEventNotificationMailMessage(model); if (message == null) { Logger.Warn().Message("Unable to create event notification mail message for event \"{0}\". User: \"{1}\"", model.EventId, emailAddress).Write(); return TaskHelper.Completed(); } message.To = emailAddress; return QueueMessageAsync(message.ToMailMessage()); }
public Task SendNoticeAsync(string emailAddress, EventNotification model) { return Task.Delay(0); }
public Task SendNoticeAsync(string emailAddress, EventNotification notification) { return Task.FromResult(0); }
public void SendNotice(string emailAddress, EventNotification model) { var msg = _pluginManager.GetEventNotificationMailMessage(model); msg.To.Add(emailAddress); msg.Headers.Add("X-Mailer-Machine", Environment.MachineName); msg.Headers.Add("X-Mailer-Date", DateTime.Now.ToString()); SendMessage(msg); }
public virtual MailMessage GetEventNotificationMailMessage(EventNotification model) { return null; }
public Task SendNoticeAsync(string emailAddress, EventNotification model) { return Task.CompletedTask; }
public Task SendEventNoticeAsync(string emailAddress, EventNotification model) { var msg = _pluginManager.GetEventNotificationMailMessage(model); if (msg == null) { _logger.Warn("Unable to create event notification mail message for event \"{0}\". User: \"{1}\"", model.EventId, emailAddress); return Task.CompletedTask; } msg.To = emailAddress; return QueueMessageAsync(msg.ToMailMessage(), "eventnotice"); }
public async Task SendNoticeAsync(string emailAddress, EventNotification model) { var msg = _pluginManager.GetEventNotificationMailMessage(model); msg.To.Add(emailAddress); await QueueMessage(msg); }