/// <summary> /// Add a crash passed in the payload as Xml to the database. /// </summary> /// <param name="id">Unused.</param> /// <returns>The row id of the newly added crash.</returns> public ActionResult AddCrash(int id) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(NewCrashId=" + id + ")")) { CrashReporterResult NewCrashResult = new CrashReporterResult(); NewCrashResult.ID = -1; try { using (StreamReader Reader = new StreamReader(Request.InputStream, Request.ContentEncoding)) { string Result = Reader.ReadToEnd(); CrashDescription NewCrash = XmlHandler.FromXmlString <CrashDescription>(Result); NewCrashResult.ID = LocalCrashRepository.AddNewCrash(NewCrash); NewCrashResult.bSuccess = true; } } catch (Exception Ex) { NewCrashResult.Message = Ex.ToString(); NewCrashResult.bSuccess = false; } string ReturnResult = XmlHandler.ToXmlString <CrashReporterResult>(NewCrashResult); return(Content(ReturnResult, "text/xml")); } }
private void UnsafeAddCrash(CrashReporterResult NewCrashResult, CrashRepository Crashes) { using (StreamReader Reader = new StreamReader(Request.InputStream, Request.ContentEncoding)) { string Result = Reader.ReadToEnd(); CrashDescription NewCrash = XmlHandler.FromXmlString <CrashDescription>(Result); NewCrashResult.ID = Crashes.AddNewCrash(NewCrash); NewCrashResult.bSuccess = true; } }
/// <summary> /// Add a crash passed in the payload as Xml to the database. /// </summary> /// <param name="id">Unused.</param> /// <returns>The row id of the newly added crash.</returns> public ActionResult AddCrash(int id) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(NewCrashId=" + id + ")")) { CrashRepository Crashes = new CrashRepository(); CrashReporterResult NewCrashResult = new CrashReporterResult(); NewCrashResult.ID = -1; string PayloadString = string.Empty; for (int Index = 0; Index < 3; Index++) { try { using (StreamReader Reader = new StreamReader(Request.InputStream, Request.ContentEncoding)) { PayloadString = Reader.ReadToEnd(); CrashDescription NewCrash = XmlHandler.FromXmlString <CrashDescription>(PayloadString); NewCrashResult.ID = Crashes.AddNewCrash(NewCrash); NewCrashResult.bSuccess = true; } break; } catch (SqlException SqlExc) { if (SqlExc.Number == -2) { FLogger.Global.WriteEvent(string.Format("AddCrash:Timeout, retrying {0} of 3", Index + 1)); } else { NewCrashResult.Message = SqlExc.ToString(); NewCrashResult.bSuccess = false; break; } } catch (Exception Ex) { StringBuilder MessageBuilder = new StringBuilder(); MessageBuilder.AppendLine("Exception was:"); MessageBuilder.AppendLine(Ex.ToString()); MessageBuilder.AppendLine("Received payload was:"); MessageBuilder.AppendLine(PayloadString); NewCrashResult.Message = MessageBuilder.ToString(); NewCrashResult.bSuccess = false; break; } System.Threading.Thread.Sleep(5000 * (Index + 1)); } string ReturnResult = XmlHandler.ToXmlString <CrashReporterResult>(NewCrashResult); return(Content(ReturnResult, "text/xml")); } }
/// <summary> /// Add a new crash to the db based on a CrashDescription sent from the client. /// </summary> /// <param name="NewCrashInfo">The crash description sent from the client.</param> /// <returns>The id of the newly added crash.</returns> public int AddNewCrash(CrashDescription NewCrashInfo) { int NewID = -1; Crash NewCrash = new Crash(); NewCrash.Branch = NewCrashInfo.BranchName; NewCrash.BaseDir = NewCrashInfo.BaseDir; NewCrash.BuildVersion = NewCrashInfo.BuildVersion; NewCrash.BuiltFromCL = NewCrashInfo.BuiltFromCL.ToString(); NewCrash.CommandLine = NewCrashInfo.CommandLine; NewCrash.EngineMode = NewCrashInfo.EngineMode; NewCrash.MachineId = NewCrashInfo.MachineGuid; //if there's a valid username assign the associated UserNameId else use "anonymous" NewCrash.UserNameId = FRepository.Get(this).FindOrAddUser(!string.IsNullOrEmpty(NewCrashInfo.UserName) ? NewCrashInfo.UserName : UserNameAnonymous); //If there's a valid EpicAccountId assign that. if (!string.IsNullOrEmpty(NewCrashInfo.EpicAccountId)) { NewCrash.EpicAccountId = NewCrashInfo.EpicAccountId; } NewCrash.Description = ""; if (NewCrashInfo.UserDescription != null) { NewCrash.Description = string.Join(Environment.NewLine, NewCrashInfo.UserDescription); } NewCrash.EngineMode = NewCrashInfo.EngineMode; NewCrash.GameName = NewCrashInfo.GameName; NewCrash.LanguageExt = NewCrashInfo.Language; // Converted by the crash process. NewCrash.PlatformName = NewCrashInfo.Platform; if (NewCrashInfo.ErrorMessage != null) { NewCrash.Summary = string.Join("\n", NewCrashInfo.ErrorMessage); } if (NewCrashInfo.CallStack != null) { NewCrash.RawCallStack = string.Join("\n", NewCrashInfo.CallStack); } if (NewCrashInfo.SourceContext != null) { NewCrash.SourceContext = string.Join("\n", NewCrashInfo.SourceContext); } NewCrash.TimeOfCrash = NewCrashInfo.TimeofCrash; NewCrash.bAllowToBeContacted = NewCrashInfo.bAllowToBeContacted; NewCrash.Jira = ""; NewCrash.FixedChangeList = ""; // Set the crash type NewCrash.CrashType = 1; if (NewCrash.RawCallStack != null) { if (NewCrash.RawCallStack.Contains("FDebug::AssertFailed")) { NewCrash.CrashType = 2; } else if (NewCrash.RawCallStack.Contains("FDebug::Ensure")) { NewCrash.CrashType = 3; } else if (NewCrash.RawCallStack.Contains("FDebug::OptionallyLogFormattedEnsureMessageReturningFalse")) { NewCrash.CrashType = 3; } else if (NewCrash.RawCallStack.Contains("NewReportEnsure")) { NewCrash.CrashType = 3; } } // As we're adding it, the status is always new NewCrash.Status = "New"; /* * Unused Crashes' fields. * * Title nchar(20) * Selected bit * Version int * AutoReporterID int * Processed bit -> renamed to AllowToBeContacted * HasDiagnosticsFile bit always true * HasNewLogFile bit * HasMetaData bit always true */ // Set the unused fields to the default values. //NewCrash.Title = ""; removed from dbml //NewCrash.Selected = false; removed from dbml //NewCrash.Version = 4; removed from dbml //NewCrash.AutoReporterID = 0; removed from dbml //NewCrash.HasNewLogFile = false;removed from dbml // //NewCrash.HasDiagnosticsFile = true; //NewCrash.HasMetaData = true; NewCrash.UserActivityHint = NewCrashInfo.UserActivityHint; // Add the crash to the database Context.Crashes.InsertOnSubmit(NewCrash); SubmitChanges(); NewID = NewCrash.Id; // Build a callstack pattern for crash bucketing NewCrash.BuildPattern(Context); return(NewID); }
/// <summary> /// Create a new crash data model object and insert it into the database /// </summary> /// <param name="description"></param> /// <returns></returns> private Crash CreateCrash(CrashDescription description) { var newCrash = new Crash { Branch = description.BranchName, BaseDir = description.BaseDir, BuildVersion = description.EngineVersion, EngineVersion = description.BuildVersion, ChangeListVersion = description.BuiltFromCL.ToString(), CommandLine = description.CommandLine, EngineMode = description.EngineMode, ComputerName = description.MachineGuid }; //if there's a valid username assign the associated UserNameId else use "anonymous". var userName = (!string.IsNullOrEmpty(description.UserName)) ? description.UserName : UserNameAnonymous; var user = _unitOfWork.UserRepository.GetByUserName(userName); if (user != null) { newCrash.UserNameId = user.Id; } else { newCrash.User = new User() { UserName = description.UserName, UserGroupId = 5 }; } //If there's a valid EpicAccountId assign that. if (!string.IsNullOrEmpty(description.EpicAccountId)) { newCrash.EpicAccountId = description.EpicAccountId; } newCrash.Description = ""; if (description.UserDescription != null) { newCrash.Description = string.Join(Environment.NewLine, description.UserDescription); } newCrash.EngineMode = description.EngineMode; newCrash.GameName = description.GameName; newCrash.LanguageExt = description.Language; //Converted by the crash process. newCrash.PlatformName = description.Platform; if (description.ErrorMessage != null) { newCrash.Summary = string.Join("\n", description.ErrorMessage); } if (description.CallStack != null) { newCrash.RawCallStack = string.Join("\n", description.CallStack); } if (description.SourceContext != null) { newCrash.SourceContext = string.Join("\n", description.SourceContext); } newCrash.TimeOfCrash = description.TimeofCrash; newCrash.Processed = description.bAllowToBeContacted; newCrash.Jira = ""; newCrash.FixedChangeList = ""; newCrash.ProcessFailed = description.bProcessorFailed; // Set the crash type newCrash.CrashType = 1; //if we have a crash type set the crash type if (!string.IsNullOrEmpty(description.CrashType)) { switch (description.CrashType.ToLower()) { case "crash": newCrash.CrashType = 1; break; case "assert": newCrash.CrashType = 2; break; case "ensure": newCrash.CrashType = 3; break; case "": case null: default: newCrash.CrashType = 1; break; } } else //else fall back to the old behavior and try to determine type from RawCallStack { if (newCrash.RawCallStack != null) { if (newCrash.RawCallStack.Contains("FDebug::AssertFailed")) { newCrash.CrashType = 2; } else if (newCrash.RawCallStack.Contains("FDebug::Ensure")) { newCrash.CrashType = 3; } else if (newCrash.RawCallStack.Contains("FDebug::OptionallyLogFormattedEnsureMessageReturningFalse")) { newCrash.CrashType = 3; } else if (newCrash.RawCallStack.Contains("NewReportEnsure")) { newCrash.CrashType = 3; } } } // As we're adding it, the status is always new newCrash.Status = "New"; /* * Unused Crashes' fields. * * Title nchar(20) * Selected bit * Version int * AutoReporterID int * Processed bit -> renamed to AllowToBeContacted * HasDiagnosticsFile bit always true * HasNewLogFile bit * HasMetaData bit always true */ // Set the unused fields to the default values. //NewCrash.Title = ""; removed from dbml //NewCrash.Selected = false; removed from dbml //NewCrash.Version = 4; removed from dbml //NewCrash.AutoReporterID = 0; removed from dbml //NewCrash.HasNewLogFile = false;removed from dbml //NewCrash.HasDiagnosticsFile = true; //NewCrash.HasMetaData = true; newCrash.UserActivityHint = description.UserActivityHint; BuildPattern(newCrash); if (newCrash.CommandLine == null) { newCrash.CommandLine = ""; } _unitOfWork.Dispose(); _unitOfWork = new UnitOfWork(new CrashReportEntities()); var callStackRepository = _unitOfWork.CallstackRepository; try { var crashRepo = _unitOfWork.CrashRepository; //if we don't have any callstack data then insert the crash and return if (string.IsNullOrEmpty(newCrash.Pattern)) { crashRepo.Save(newCrash); _unitOfWork.Save(); return(newCrash); } //If this isn't a new pattern then link it to our crash data model if (callStackRepository.Any(data => data.Pattern == newCrash.Pattern)) { var callstackPattern = callStackRepository.First(data => data.Pattern == newCrash.Pattern); newCrash.PatternId = callstackPattern.id; } else { //if this is a new callstack pattern then insert into data model and create a new bugg. var callstackPattern = new CallStackPattern { Pattern = newCrash.Pattern }; callStackRepository.Save(callstackPattern); _unitOfWork.Save(); newCrash.PatternId = callstackPattern.id; } //Mask out the line number and File path from our error message. var errorMessageString = description.ErrorMessage != null?String.Join("", description.ErrorMessage) : ""; //Create our masking regular expressions var fileRegex = new Regex(@"(\[File:).*?(])"); //Match the filename out the file name var lineRegex = new Regex(@"(\[Line:).*?(])"); //Match the line no. /** * Regex to match ints of two characters or longer * First term ((?<=\s)|(-)) : Positive look behind, match if preceeded by whitespace or if first character is '-' * Second term (\d{3,}) match three or more decimal chracters in a row. * Third term (?=(\s|$)) positive look ahead match if followed by whitespace or end of line/file. */ var intRegex = new Regex(@"-?\d{3,}"); /** * Regular expression for masking out floats */ var floatRegex = new Regex(@"-?\d+\.\d+"); /** * Regular expression for masking out hexadecimal numbers */ var hexRegex = new Regex(@"0x[\da-fA-F]+"); //mask out terms matches by our regex's var trimmedError = fileRegex.Replace(errorMessageString, ""); trimmedError = lineRegex.Replace(trimmedError, ""); trimmedError = floatRegex.Replace(trimmedError, ""); trimmedError = hexRegex.Replace(trimmedError, ""); trimmedError = intRegex.Replace(trimmedError, ""); //Check to see if the masked error message is unique ErrorMessage errorMessage = null; if (_unitOfWork.ErrorMessageRepository.Any(data => data.Message.Contains(trimmedError))) { errorMessage = _unitOfWork.ErrorMessageRepository.First(data => data.Message.Contains(trimmedError)); } else { //if it's a new message then add it to the database. errorMessage = new ErrorMessage() { Message = trimmedError }; _unitOfWork.ErrorMessageRepository.Save(errorMessage); _unitOfWork.Save(); } //Check for an existing bugg with this pattern and error message / no error message if (_unitOfWork.BuggRepository.Any(data => (data.PatternId == newCrash.PatternId || data.Pattern == newCrash.Pattern) && (newCrash.CrashType == 3 || (data.ErrorMessageId == errorMessage.Id || data.ErrorMessageId == null)))) { //if a bugg exists for this pattern update the bugg data var bugg = _unitOfWork.BuggRepository.First(data => data.PatternId == newCrash.PatternId) ?? _unitOfWork.BuggRepository.First(data => data.Pattern == newCrash.Pattern); bugg.PatternId = newCrash.PatternId; if (newCrash.CrashType != 3) { bugg.CrashType = newCrash.CrashType; bugg.ErrorMessageId = errorMessage.Id; } //also update the bugg data while we're here bugg.TimeOfLastCrash = newCrash.TimeOfCrash; if (String.Compare(newCrash.BuildVersion, bugg.BuildVersion, StringComparison.Ordinal) != 1) { bugg.BuildVersion = newCrash.BuildVersion; } _unitOfWork.Save(); //if a bugg exists update this crash from the bugg //buggs are authoritative in this case newCrash.Buggs.Add(bugg); newCrash.Jira = bugg.TTPID; newCrash.FixedChangeList = bugg.FixedChangeList; newCrash.Status = bugg.Status; _unitOfWork.CrashRepository.Save(newCrash); _unitOfWork.Save(); } else { //if there's no bugg for this pattern create a new bugg and insert into the data store. var bugg = new Bugg(); bugg.TimeOfFirstCrash = newCrash.TimeOfCrash; bugg.TimeOfLastCrash = newCrash.TimeOfCrash; bugg.TTPID = newCrash.Jira; bugg.Pattern = newCrash.Pattern; bugg.PatternId = newCrash.PatternId; bugg.NumberOfCrashes = 1; bugg.NumberOfUsers = 1; bugg.NumberOfUniqueMachines = 1; bugg.BuildVersion = newCrash.BuildVersion; bugg.CrashType = newCrash.CrashType; bugg.Status = newCrash.Status; bugg.FixedChangeList = newCrash.FixedChangeList; bugg.ErrorMessageId = errorMessage.Id; newCrash.Buggs.Add(bugg); _unitOfWork.BuggRepository.Save(bugg); _unitOfWork.CrashRepository.Save(newCrash); _unitOfWork.Save(); } } catch (DbEntityValidationException dbentEx) { var messageBuilder = new StringBuilder(); messageBuilder.AppendLine("Db Entity Validation Exception Exception was:"); messageBuilder.AppendLine(dbentEx.ToString()); var innerEx = dbentEx.InnerException; while (innerEx != null) { messageBuilder.AppendLine("Inner Exception : " + innerEx.Message); innerEx = innerEx.InnerException; } if (dbentEx.EntityValidationErrors != null) { messageBuilder.AppendLine("Validation Errors : "); foreach (var valErr in dbentEx.EntityValidationErrors) { messageBuilder.AppendLine(valErr.ValidationErrors.Select(data => data.ErrorMessage).Aggregate((current, next) => current + "; /n" + next)); } } FLogger.Global.WriteException(messageBuilder.ToString()); } catch (Exception ex) { var messageBuilder = new StringBuilder(); messageBuilder.AppendLine("Create Crash Exception : "); messageBuilder.AppendLine(ex.Message.ToString()); var innerEx = ex.InnerException; while (innerEx != null) { messageBuilder.AppendLine("Inner Exception : " + innerEx.Message); innerEx = innerEx.InnerException; } FLogger.Global.WriteException("Create Crash Exception : " + messageBuilder.ToString()); _slackWriter.Write("Create Crash Exception : " + messageBuilder.ToString()); throw; } return(newCrash); }
/// <summary> /// Create an Xml payload representing a new crash. /// </summary> /// <param name="DirInfo">The DirectoryInfo of the report folder.</param> /// <param name="NewContext">The generic crash context.</param> /// <param name="bHasVideoFile">Whether the report contains a video file.</param> /// <param name="bHasLog">Whether the report contains a log file.</param> /// <param name="bHasMinidump">Whether the report contains a minidump.</param> /// <returns>A string of Xml payload representing the newly found crash report.</returns> private string CreateCrash(DirectoryInfo DirInfo, FGenericCrashContext NewContext, bool bHasVideoFile, bool bHasLog, bool bHasMinidump) { string XmlPayload = ""; try { FEngineVersion EngineVersion = new FEngineVersion(NewContext.PrimaryCrashProperties.EngineVersion); // Create a new crash description for uploading CrashDescription NewCrash = new CrashDescription(); NewCrash.BranchName = EngineVersion.GetCleanedBranch(); NewCrash.GameName = NewContext.PrimaryCrashProperties.GameName; NewCrash.Platform = NewContext.PrimaryCrashProperties.PlatformFullName; NewCrash.EngineMode = NewContext.PrimaryCrashProperties.EngineMode; NewCrash.BuildVersion = EngineVersion.VersionNumber; NewCrash.CommandLine = NewContext.PrimaryCrashProperties.CommandLine; NewCrash.BaseDir = NewContext.PrimaryCrashProperties.BaseDir; NewCrash.Language = NewContext.PrimaryCrashProperties.AppDefaultLocale; // // Create a locate and get the system language. // int SystemLanguageCode = 0; // int.TryParse( ReportData.SystemLanguage, out SystemLanguageCode ); // try // { // if( SystemLanguageCode > 0 ) // { // CultureInfo SystemLanguageCI = new CultureInfo( SystemLanguageCode ); // NewCrash.SystemLanguage = SystemLanguageCI.Name; // } // } // catch( System.Exception ) // { // // Default to en-US // NewCrash.SystemLanguage = "en-US"; // } NewCrash.MachineGuid = NewContext.PrimaryCrashProperties.MachineId; // Valid for all kind of builds, previously only for UE4 releases. NewCrash.UserName = NewContext.PrimaryCrashProperties.UserName; // Only valid for non-UE4 releases. NewCrash.EpicAccountId = NewContext.PrimaryCrashProperties.EpicAccountId; // Only valid for UE4 releases. NewCrash.CallStack = NewContext.PrimaryCrashProperties.GetCallstack(); NewCrash.SourceContext = NewContext.PrimaryCrashProperties.GetSourceContext(); NewCrash.ErrorMessage = NewContext.PrimaryCrashProperties.GetErrorMessage(); NewCrash.UserDescription = NewContext.PrimaryCrashProperties.GetUserDescription(); // Iterate through all files and find a file with the earliest date. DateTime TimeOfCrash = DateTime.UtcNow; foreach (var File in DirInfo.GetFiles()) { if (File.CreationTimeUtc < TimeOfCrash) { TimeOfCrash = File.CreationTimeUtc; } } //NewCrash.TimeofCrash = NewContext.PrimaryCrashProperties.TimeofCrash; NewCrash.TimeofCrash = TimeOfCrash; NewCrash.bHasMiniDump = bHasMinidump; NewCrash.bHasLog = bHasLog; NewCrash.bHasVideo = bHasVideoFile; NewCrash.BuiltFromCL = (int)EngineVersion.Changelist; NewCrash.bAllowToBeContacted = NewContext.PrimaryCrashProperties.bAllowToBeContacted; // Ignore any callstack that is shorter than expected, usually the callstack is invalid. if (NewCrash.CallStack.Length <= CrashReporterConstants.MinCallstackDepth) { CrashReporterProcessServicer.WriteFailure("! BadStack: BuiltFromCL=" + string.Format("{0,7}", NewContext.PrimaryCrashProperties.EngineVersion) + " Path=" + NewContext.CrashDirectory); } else { XmlPayload = XmlHandler.ToXmlString <CrashDescription>(NewCrash); } } catch (Exception Ex) { CrashReporterProcessServicer.WriteException("CreateCrash: " + Ex.ToString()); } return(XmlPayload); }
/// <summary> /// Add a new crash to the db based on a CrashDescription sent from the client. /// </summary> /// <param name="NewCrashInfo">The crash description sent from the client.</param> /// <returns>The id of the newly added crash.</returns> public int AddNewCrash(CrashDescription NewCrashInfo) { int NewID = -1; Crash NewCrash = new Crash(); NewCrash.Branch = NewCrashInfo.BranchName; NewCrash.BaseDir = NewCrashInfo.BaseDir; NewCrash.BuildVersion = NewCrashInfo.BuildVersion; NewCrash.ChangeListVersion = NewCrashInfo.BuiltFromCL.ToString(); NewCrash.CommandLine = NewCrashInfo.CommandLine; NewCrash.EngineMode = NewCrashInfo.EngineMode; // Valid MachineID and UserName, updated crash from non-UE4 release if (!string.IsNullOrEmpty(NewCrashInfo.MachineGuid) && !string.IsNullOrEmpty(NewCrashInfo.UserName)) { NewCrash.ComputerName = NewCrashInfo.MachineGuid; NewCrash.UserNameId = CrashRepositoryDataContext.FindOrAddUser(NewCrashInfo.UserName); } // Valid MachineID and EpicAccountId, updated crash from UE4 release else if (!string.IsNullOrEmpty(NewCrashInfo.MachineGuid) && !string.IsNullOrEmpty(NewCrashInfo.EpicAccountId)) { NewCrash.EpicAccountId = NewCrashInfo.EpicAccountId; NewCrash.UserNameId = CrashRepositoryDataContext.FindOrAddUser(UserNameAnonymous); } // Crash from an older version. else { // MachineGuid for older crashes is obsolete, so ignore it. //NewCrash.ComputerName = NewCrashInfo.MachineGuid; NewCrash.UserNameId = CrashRepositoryDataContext.FindOrAddUser ( !string.IsNullOrEmpty(NewCrashInfo.UserName) ? NewCrashInfo.UserName : UserNameAnonymous ); } NewCrash.Description = ""; if (NewCrashInfo.UserDescription != null) { NewCrash.Description = string.Join(Environment.NewLine, NewCrashInfo.UserDescription); } NewCrash.EngineMode = NewCrashInfo.EngineMode; NewCrash.GameName = NewCrashInfo.GameName; NewCrash.LanguageExt = NewCrashInfo.Language; // Converted by the crash process. NewCrash.PlatformName = NewCrashInfo.Platform; if (NewCrashInfo.ErrorMessage != null) { NewCrash.Summary = string.Join("\n", NewCrashInfo.ErrorMessage); } if (NewCrashInfo.CallStack != null) { NewCrash.RawCallStack = string.Join("\n", NewCrashInfo.CallStack); } if (NewCrashInfo.SourceContext != null) { NewCrash.SourceContext = string.Join("\n", NewCrashInfo.SourceContext); } NewCrash.TimeOfCrash = NewCrashInfo.TimeofCrash; NewCrash.HasLogFile = NewCrashInfo.bHasLog; NewCrash.HasMiniDumpFile = NewCrashInfo.bHasMiniDump; NewCrash.HasDiagnosticsFile = NewCrashInfo.bHasDiags; NewCrash.HasVideoFile = NewCrashInfo.bHasVideo; NewCrash.HasMetaData = NewCrashInfo.bHasWERData; NewCrash.TTPID = ""; NewCrash.FixedChangeList = ""; // Set the crash type NewCrash.CrashType = 1; if (NewCrash.RawCallStack != null) { if (NewCrash.RawCallStack.Contains("FDebug::AssertFailed()")) { NewCrash.CrashType = 2; } else if (NewCrash.RawCallStack.Contains("FDebug::EnsureFailed()")) { NewCrash.CrashType = 3; } } // As we're adding it, the status is always new NewCrash.Status = "New"; /* * Unused Crashes' fields. * * Title nchar(20) * Selected bit * Version int * AutoReporterID int * Processed bit * HasDiagnosticsFile bit * HasNewLogFile bit * HasMetaData bit */ // Set the unused fields to the default values. NewCrash.Title = ""; NewCrash.Selected = false; NewCrash.Version = 4; NewCrash.AutoReporterID = 0; NewCrash.Processed = true; //NewCrash.HasDiagnosticsFile = true; NewCrash.HasNewLogFile = false; //NewCrash.HasMetaData = true; // Add the crash to the database CrashRepositoryDataContext.Crashes.InsertOnSubmit(NewCrash); CrashRepositoryDataContext.SubmitChanges(); NewID = NewCrash.Id; // Build a callstack pattern for crash bucketing CrashRepositoryDataContext.BuildPattern(NewCrash); return(NewID); }