/// <summary> /// Analyze report /// </summary> /// <param name="report">report</param> /// <exception cref="ArgumentNullException">report</exception> public void Analyze(ErrorReportEntity report) { if (report == null) { throw new ArgumentNullException("report"); } var exists = _repository.ExistsByClientId(report.ClientReportId); if (exists) { _logger.Warn("Report have already been uploaded: " + report.ClientReportId); return; } try { var hashCode = _hashCodeGenerator.GenerateHashCode(report); report.Init(hashCode); } catch (Exception ex) { _logger.Fatal("Failed to store report " + JsonConvert.SerializeObject(report), ex); return; } var isReOpened = false; var firstLine = report.GenerateHashCodeIdentifier(); var incident = _repository.FindIncidentForReport(report.ApplicationId, report.ReportHashCode, firstLine); if (incident == null) { incident = BuildIncident(report); _repository.CreateIncident(incident); } else { if (incident.ReportCount > 10000) { _logger.Debug("Reportcount is more than 10000. Ignoring report for incident " + incident.Id); return; } if (incident.IsIgnored) { _logger.Info("Incident is ignored: " + JsonConvert.SerializeObject(report)); incident.WasJustIgnored(); _repository.UpdateIncident(incident); return; } if (incident.IsSolved) { isReOpened = true; incident.ReOpen(); _eventBus.PublishAsync(new IncidentReOpened(incident.ApplicationId, incident.Id, incident.CreatedAtUtc)); } incident.AddReport(report); _repository.UpdateIncident(incident); } report.IncidentId = incident.Id; _repository.CreateReport(report); _logger.Debug("saving report " + report.Id + " for incident " + incident.Id); var appName = _repository.GetAppName(incident.ApplicationId); var summary = new IncidentSummaryDTO(incident.Id, incident.Description) { ApplicationId = incident.ApplicationId, ApplicationName = appName, CreatedAtUtc = incident.CreatedAtUtc, LastUpdateAtUtc = incident.UpdatedAtUtc, IsReOpened = incident.IsReOpened, Name = incident.Description, ReportCount = incident.ReportCount }; var sw = new Stopwatch(); sw.Start(); _logger.Debug("Publishing now: " + report.ClientReportId); var e = new ReportAddedToIncident(summary, ConvertToCoreReport(report), isReOpened); _eventBus.PublishAsync(e); if (sw.ElapsedMilliseconds > 200) { _logger.Debug("Publish took " + sw.ElapsedMilliseconds); } sw.Stop(); }
/// <summary> /// Analyze report /// </summary> /// <param name="report">report</param> /// <exception cref="ArgumentNullException">report</exception> public async Task Analyze(IMessageContext context, ErrorReportEntity report) { if (report == null) { throw new ArgumentNullException("report"); } var countThisMonth = _repository.GetMonthReportCount(); if (countThisMonth >= 500) { _repository.AddMissedReport(DateTime.Today); return; } var exists = _repository.ExistsByClientId(report.ClientReportId); if (exists) { _logger.Warn("Report have already been uploaded: " + report.ClientReportId); return; } try { var hashCode = _hashCodeGenerator.GenerateHashCode(report); report.Init(hashCode); } catch (Exception ex) { var reportJson = JsonConvert.SerializeObject(report); if (reportJson.Length > 1000000) { reportJson = reportJson.Substring(0, 100000) + "[....]"; } _logger.Fatal("Failed to init report " + reportJson, ex); return; } var applicationVersion = GetVersionFromReport(report); var isReOpened = false; var firstLine = report.GenerateHashCodeIdentifier(); var incident = _repository.FindIncidentForReport(report.ApplicationId, report.ReportHashCode, firstLine); if (incident == null) { incident = BuildIncident(report); _repository.CreateIncident(incident); var evt = new IncidentCreated(incident.ApplicationId, incident.Id, incident.Description, incident.FullName) { CreatedAtUtc = incident.CreatedAtUtc, ApplicationVersion = applicationVersion, }; await _domainQueue.PublishAsync(context.Principal, evt); await context.SendAsync(evt); } else { await _repository.StoreReportStats(new ReportMapping() { IncidentId = incident.Id, ErrorId = report.ClientReportId, ReceivedAtUtc = report.CreatedAtUtc }); if (incident.IsIgnored) { _logger.Info("Incident is ignored: " + JsonConvert.SerializeObject(report)); incident.WasJustIgnored(); _repository.UpdateIncident(incident); return; } if (incident.IsClosed) { if (applicationVersion != null && incident.IsReportIgnored(applicationVersion)) { _logger.Info("Ignored report since it's for a version less that the solution version: " + JsonConvert.SerializeObject(report)); incident.WasJustIgnored(); _repository.UpdateIncident(incident); return; } isReOpened = true; incident.ReOpen(); var evt = new IncidentReOpened(incident.ApplicationId, incident.Id, incident.CreatedAtUtc) { ApplicationVersion = applicationVersion }; await context.SendAsync(evt); await _domainQueue.PublishAsync(context.Principal, evt); } incident.AddReport(report); _repository.UpdateIncident(incident); if (incident.ReportCount > 25) { _logger.Debug("Report count is more than 25. Storing only report stats for incident " + incident.Id); return; } } if (!string.IsNullOrWhiteSpace(report.EnvironmentName)) { _repository.SaveEnvironmentName(incident.Id, report.EnvironmentName); } report.IncidentId = incident.Id; _repository.CreateReport(report); _logger.Debug("saving report " + report.Id + " for incident " + incident.Id); var appName = _repository.GetAppName(incident.ApplicationId); var summary = new IncidentSummaryDTO(incident.Id, incident.Description) { ApplicationId = incident.ApplicationId, ApplicationName = appName, CreatedAtUtc = incident.CreatedAtUtc, LastUpdateAtUtc = incident.UpdatedAtUtc, IsReOpened = incident.IsReOpened, Name = incident.Description, ReportCount = incident.ReportCount }; var sw = new Stopwatch(); sw.Start(); _logger.Debug("Publishing now: " + report.ClientReportId); var e = new ReportAddedToIncident(summary, ConvertToCoreReport(report, applicationVersion), isReOpened); await context.SendAsync(e); await context.SendAsync(new ProcessInboundContextCollections()); if (sw.ElapsedMilliseconds > 200) { _logger.Debug("PublishAsync took " + sw.ElapsedMilliseconds); } sw.Stop(); }
/// <summary> /// Analyze report /// </summary> /// <param name="report">report</param> /// <exception cref="ArgumentNullException">report</exception> public async Task Analyze(IMessageContext context, ErrorReportEntity report) { if (report == null) { throw new ArgumentNullException(nameof(report)); } var countThisMonth = _repository.GetMonthReportCount(); if (countThisMonth >= 500) { _repository.AddMissedReport(DateTime.Today); return; } _logger.Debug("Running as " + context.Principal.ToFriendlyString()); var exists = _repository.ExistsByClientId(report.ClientReportId); if (exists) { _logger.Warn($"Report have already been uploaded: {report.ClientReportId} for {report.RemoteAddress}."); return; } ErrorHashCode hashcodeResult; try { hashcodeResult = _hashCodeGenerator.GenerateHashCode(report); report.Init(hashcodeResult.HashCode); } catch (Exception ex) { var reportJson = JsonConvert.SerializeObject(report); if (reportJson.Length > 1000000) { reportJson = reportJson.Substring(0, 100000) + "[....]"; } _logger.Fatal($"Failed to init report {reportJson}", ex); return; } var storeReport = true; var applicationVersion = GetVersionFromReport(report); var isReOpened = false; IncidentBeingAnalyzed incident = null; if (hashcodeResult.CompabilityHashSource != null) { incident = _repository.FindIncidentForReport(report.ApplicationId, hashcodeResult.CompabilityHashSource, hashcodeResult.CollisionIdentifier); if (incident != null) { report.Init(hashcodeResult.CompabilityHashSource); } } if (incident == null) { incident = _repository.FindIncidentForReport(report.ApplicationId, report.ReportHashCode, hashcodeResult.CollisionIdentifier); } var isNewIncident = false; if (incident == null) { if (report.Exception == null) { _logger.Debug("Got no exception"); } isNewIncident = true; incident = BuildIncident(report); _repository.CreateIncident(incident); await _repository.StoreReportStats(new ReportMapping() { IncidentId = incident.Id, ErrorId = report.ClientReportId, ReceivedAtUtc = report.CreatedAtUtc }); var evt = new IncidentCreated(incident.ApplicationId, incident.Id, incident.Description, incident.FullName) { CreatedAtUtc = incident.CreatedAtUtc, ApplicationVersion = applicationVersion, }; _logger.Info($"Storing IncidentCreated with {context.Principal.ToFriendlyString()}: {JsonConvert.SerializeObject(evt)}"); await _domainQueue.PublishAsync(context.Principal, evt); await context.SendAsync(evt); } else { if (incident.IsIgnored) { _logger.Info("Incident is ignored: " + JsonConvert.SerializeObject(report)); incident.WasJustIgnored(); _repository.UpdateIncident(incident); return; } // Do this before checking closed // as we want to see if it still gets reports. var stat = new ReportMapping() { IncidentId = incident.Id, ErrorId = report.ClientReportId, ReceivedAtUtc = report.CreatedAtUtc }; await _repository.StoreReportStats(stat); _logger.Debug("Storing stats " + JsonConvert.SerializeObject(stat)); if (incident.IsClosed) { if (applicationVersion != null && incident.IsReportIgnored(applicationVersion)) { _logger.Info("Ignored report since it's for a version less that the solution version: " + JsonConvert.SerializeObject(report)); incident.WasJustIgnored(); _repository.UpdateIncident(incident); return; } isReOpened = true; incident.ReOpen(); var evt = new IncidentReOpened(incident.ApplicationId, incident.Id, incident.CreatedAtUtc) { ApplicationVersion = applicationVersion }; await context.SendAsync(evt); await _domainQueue.PublishAsync(context.Principal, evt); } incident.AddReport(report); // Let's continue to receive reports once a day when // limit is reached (to get more fresh data, and still not load the system unnecessary). var timesSinceLastReport = DateTime.UtcNow.Subtract(incident.LastStoredReportUtc); if (incident.ReportCount > _reportConfig.Value.MaxReportsPerIncident && timesSinceLastReport < TimeSpan.FromMinutes(10)) { _repository.UpdateIncident(incident); _logger.Debug($"Report count is more than {_reportConfig.Value.MaxReportsPerIncident}. Ignoring reports for incident {incident.Id}. Minutes since last report: " + timesSinceLastReport.TotalMinutes); storeReport = false; //don't exit here, since we want to be able to process reports } } if (!string.IsNullOrWhiteSpace(report.EnvironmentName)) { _repository.SaveEnvironmentName(incident.Id, report.EnvironmentName); } report.IncidentId = incident.Id; if (storeReport) { incident.LastStoredReportUtc = DateTime.UtcNow; _repository.UpdateIncident(incident); _repository.CreateReport(report); _logger.Debug($"saving report {report.Id} for incident {incident.Id}"); } var appName = _repository.GetAppName(incident.ApplicationId); var summary = new IncidentSummaryDTO(incident.Id, incident.Description) { ApplicationId = incident.ApplicationId, ApplicationName = appName, CreatedAtUtc = incident.CreatedAtUtc, LastUpdateAtUtc = incident.UpdatedAtUtc, IsReOpened = incident.IsReOpened, Name = incident.Description, ReportCount = incident.ReportCount }; var sw = new Stopwatch(); sw.Start(); var e = new ReportAddedToIncident(summary, ConvertToCoreReport(report, applicationVersion), isReOpened) { IsNewIncident = isNewIncident, IsStored = storeReport, EnvironmentName = report.EnvironmentName }; await context.SendAsync(e); if (storeReport) { await context.SendAsync(new ProcessInboundContextCollections()); } if (sw.ElapsedMilliseconds > 200) { _logger.Debug($"PublishAsync took {sw.ElapsedMilliseconds}"); } sw.Stop(); }