/// <summary> /// Creates an incident and a report. /// </summary> public void CreateReportAndIncident(out int reportId, out int incidentId) { ErrorReportEntity report; using (var uow = CreateUnitOfWork()) { report = new ErrorReportEntity(ApplicationId, Guid.NewGuid().ToString("N"), DateTime.UtcNow, new ErrorReportException(new Exception("mofo")), new List <ErrorReportContextCollection> { new ErrorReportContextCollection("Maps", new Dictionary <string, string>()) }) { Title = "Missing here" }; report.Init(report.GenerateHashCodeIdentifier()); uow.SaveChanges(); } using (var dbContext = CreateUnitOfWork()) { var incident = new IncidentBeingAnalyzed(report); var incRepos = new AnalyticsRepository(dbContext); incRepos.CreateIncident(incident); incidentId = incident.Id; report.IncidentId = incident.Id; incRepos.CreateReport(report); reportId = report.Id; dbContext.SaveChanges(); } }
public void CreateIncident(IncidentBeingAnalyzed incident) { if (incident == null) { throw new ArgumentNullException("incident"); } if (string.IsNullOrEmpty(incident.ReportHashCode)) { throw new InvalidOperationException("ReportHashCode is required to be able to detect duplicates"); } using (var cmd = _unitOfWork.CreateCommand()) { cmd.CommandText = "INSERT INTO Incidents (ReportHashCode, ApplicationId, CreatedAtUtc, HashCodeIdentifier, StackTrace, ReportCount, UpdatedAtUtc, Description, FullName, IsReOpened, LastReportAtUtc)" + " VALUES (@ReportHashCode, @ApplicationId, @CreatedAtUtc, @HashCodeIdentifier, @StackTrace, @ReportCount, @UpdatedAtUtc, @Description, @FullName, 0, @LastReportAtUtc);select SCOPE_IDENTITY();"; cmd.AddParameter("Id", incident.Id); cmd.AddParameter("ReportHashCode", incident.ReportHashCode); cmd.AddParameter("ApplicationId", incident.ApplicationId); cmd.AddParameter("CreatedAtUtc", incident.CreatedAtUtc); cmd.AddParameter("HashCodeIdentifier", incident.HashCodeIdentifier); cmd.AddParameter("ReportCount", incident.ReportCount); cmd.AddParameter("UpdatedAtUtc", incident.UpdatedAtUtc); cmd.AddParameter("Description", incident.Description); cmd.AddParameter("StackTrace", incident.StackTrace); cmd.AddParameter("FullName", incident.FullName); cmd.AddParameter("LastReportAtUtc", incident.LastReportAtUtc); var id = (int)(decimal)cmd.ExecuteScalar(); incident.GetType() .GetProperty("Id", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) .SetValue(incident, id); } //_unitOfWork.Insert(incident); }
/// <summary> /// Creates an incident and a report. /// </summary> public void CreateReportAndIncident(out int reportId, out int incidentId) { using (var uow = CreateUnitOfWork()) { CreateUserAndApplication(uow, out var accountId, out var applicationId); var report = new ErrorReportEntity(applicationId, Guid.NewGuid().ToString("N"), DateTime.UtcNow, new ErrorReportException(new Exception("mofo")), new List <ErrorReportContext> { new ErrorReportContext("Maps", new Dictionary <string, string>()) }) { Title = "Missing here" }; report.Init(report.GenerateHashCodeIdentifier()); var incident = new IncidentBeingAnalyzed(report); var incRepos = new AnalyticsRepository(new AnalysisDbContext(uow), ConfigStore); incRepos.CreateIncident(incident); incidentId = incident.Id; report.IncidentId = incident.Id; incRepos.CreateReport(report); reportId = report.Id; uow.SaveChanges(); } }
public void UpdateIncident(IncidentBeingAnalyzed incident) { if (incident == null) { throw new ArgumentNullException("incident"); } _unitOfWork.Update(incident); }
private IncidentBeingAnalyzed BuildIncident(ErrorReportEntity entity) { if (entity.Exception == null) { return(new IncidentBeingAnalyzed(entity)); } if (entity.Exception.Name == "AggregateException") { try { var exception = entity.Exception; //TODO: Check if there are more than one InnerExceptions and then abort this specialization. while (exception != null && exception.Name == "AggregateException") { exception = exception.InnerException; } var incident = new IncidentBeingAnalyzed(entity, exception); return(incident); } catch (Exception) { } } if (entity.Exception.Name == "ReflectionTypeLoadException") { try { var item = JObject.Parse(entity.Exception.Everything); var i = new IncidentBeingAnalyzed(entity); var items = (JObject)item["LoaderExceptions"]; var exception = items.First; //var incident = new Incident(entity, exception); //incident.AddIncidentTags(new[] { "ReflectionTypeLoadException" }); //return incident; //TODO: load LoaderExceptions which is an Exception[] array } catch (Exception) { } } return(new IncidentBeingAnalyzed(entity)); }
public void Should_load_ignored_state_into_class_correctly() { var report = new ErrorReportEntity(FirstApplicationId, Guid.NewGuid().ToString("N"), DateTime.UtcNow, new ErrorReportException(new Exception("mofo")), new List <ErrorReportContext> { new ErrorReportContext("Maps", new Dictionary <string, string>()) }) { Title = "Missing here" }; report.Init(report.GenerateHashCodeIdentifier()); using (var uow = new AnalysisDbContext(CreateUnitOfWork())) { var incident = new IncidentBeingAnalyzed(report); var incRepos = new AnalyticsRepository(uow, new TestConfigStore()); incRepos.CreateIncident(incident); report.IncidentId = incident.Id; incRepos.CreateReport(report); } }
/// <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(); }