private void OnCrashesAdd(Crash CrashInstance) { Buggs_Crashes.Add(new Buggs_Crash { Bugg = this, Crash = CrashInstance }); SendPropertyChanged(null); }
/// <summary> /// Construct a processed callstack. /// </summary> /// <param name="CurrentCrash"></param> public CallStackContainer(Crash CurrentCrash) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(CrashId=" + CurrentCrash.Id + ")")) { ParseCallStack(CurrentCrash); } }
/// <summary> /// Gets the crash from an id. /// </summary> /// <param name="Id">The id of the crash we wish to examine.</param> /// <returns>The crash with the requested id.</returns> public Crash GetCrash(int Id) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(CrashId=" + Id + ")")) { try { IQueryable <Crash> Crashes = ( from CrashDetail in Context.Crashes where CrashDetail.Id == Id select CrashDetail ); Crash Result = Crashes.FirstOrDefault(); Result.ReadCrashContextIfAvailable(); return(Result); } catch (Exception Ex) { Debug.WriteLine("Exception in GetCrash: " + Ex.ToString()); } return(null); } }
private void OnCrashesRemove(Crash CrashInstance) { Buggs_Crash BuggCrash = Buggs_Crashes.FirstOrDefault(BuggCrashInstance => BuggCrashInstance.BuggId == Id && BuggCrashInstance.CrashId == CrashInstance.Id); Buggs_Crashes.Remove(BuggCrash); SendPropertyChanged(null); }
/// <summary> /// Construct a processed callstack. /// </summary> /// <param name="CurrentCrash"></param> public CallStackContainer( Crash CurrentCrash ) { using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(CrashId=" + CurrentCrash.Id + ")" ) ) { ParseCallStack( CurrentCrash ); } }
/// <summary> /// Build a callstack pattern for a crash to ease bucketing of crashes into Buggs. /// </summary> /// <param name="CrashInstance">A crash that was recently added to the database.</param> public void BuildPattern(Crash CrashInstance) { List <string> Pattern = new List <string>(); // Get an array of callstack items CallStackContainer CallStack = new CallStackContainer(CrashInstance); CallStack.bDisplayFunctionNames = true; if (CrashInstance.Pattern == null) { // Set the module based on the modules in the callstack CrashInstance.Module = CallStack.GetModuleName(); try { foreach (CallStackEntry Entry in CallStack.CallStackEntries) { FunctionCall CurrentFunctionCall = new FunctionCall(); if (FunctionCalls.Where(f => f.Call == Entry.FunctionName).Count() > 0) { CurrentFunctionCall = FunctionCalls.Where(f => f.Call == Entry.FunctionName).First(); } else { CurrentFunctionCall = new FunctionCall(); CurrentFunctionCall.Call = Entry.FunctionName; FunctionCalls.InsertOnSubmit(CurrentFunctionCall); } int Count = Crash_FunctionCalls.Where(c => c.CrashId == CrashInstance.Id && c.FunctionCallId == CurrentFunctionCall.Id).Count(); if (Count < 1) { Crash_FunctionCall JoinTable = new Crash_FunctionCall(); JoinTable.Crash = CrashInstance; JoinTable.FunctionCall = CurrentFunctionCall; Crash_FunctionCalls.InsertOnSubmit(JoinTable); } SubmitChanges(); Pattern.Add(CurrentFunctionCall.Id.ToString()); } CrashInstance.Pattern = string.Join("+", Pattern); SubmitChanges(); } catch (Exception Ex) { Debug.WriteLine("Exception in BuildPattern: " + Ex.ToString()); } } }
/// <summary> /// Retrieve a cached (and pre-parsed) callstack container from the cache, or parse the raw callstack, and add to the cache. /// </summary> /// <param name="CurrentCrash">The crash to retrieve the parsed callstack for.</param> /// <returns>A parsed callstack.</returns> public CallStackContainer GetCallStack(Crash CurrentCrash) { string Key = CacheKeyPrefix + CallstackKeyPrefix + CurrentCrash.Id; CallStackContainer CallStack = ( CallStackContainer )CacheInstance[Key]; if (CallStack == null) { CallStack = new CallStackContainer(CurrentCrash); CallStack.bDisplayFunctionNames = true; CacheInstance.Insert(Key, CallStack); } return(CallStack); }
/// <summary> /// Build a callstack pattern for a crash to ease bucketing of crashes into Buggs. /// </summary> /// <param name="CrashInstance">A crash that was recently added to the database.</param> public void BuildPattern(Crash CrashInstance) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(Crash=" + CrashInstance.Id + ")")) { List <string> Pattern = new List <string>(); // Get an array of callstack items CallStackContainer CallStack = new CallStackContainer(CrashInstance); CallStack.bDisplayFunctionNames = true; if (CrashInstance.Pattern == null) { // Set the module based on the modules in the callstack CrashInstance.Module = CallStack.GetModuleName(); try { foreach (CallStackEntry Entry in CallStack.CallStackEntries) { FunctionCall CurrentFunctionCall = new FunctionCall(); if (FunctionCalls.Where(f => f.Call == Entry.FunctionName).Count() > 0) { CurrentFunctionCall = FunctionCalls.Where(f => f.Call == Entry.FunctionName).First(); } else { CurrentFunctionCall = new FunctionCall(); CurrentFunctionCall.Call = Entry.FunctionName; FunctionCalls.InsertOnSubmit(CurrentFunctionCall); } SubmitChanges(); Pattern.Add(CurrentFunctionCall.Id.ToString()); } //CrashInstance.Pattern = "+"; CrashInstance.Pattern = string.Join("+", Pattern); // We need something like this +1+2+3+5+ for searching for exact pattern like +5+ //CrashInstance.Pattern += "+"; SubmitChanges(); } catch (Exception Ex) { FLogger.WriteException("BuildPattern: " + Ex.ToString()); } } } }
/// <summary> /// Retrieve a cached (and pre-parsed) callstack container from the cache, or parse the raw callstack, and add to the cache. /// </summary> /// <param name="CurrentCrash">The crash to retrieve the parsed callstack for.</param> /// <returns>A parsed callstack.</returns> public CallStackContainer GetCallStackFast( Crash CurrentCrash ) { using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(CrashId=" + CurrentCrash.Id + ")" ) ) { string Key = CacheKeyPrefix + CallstackKeyPrefix + CurrentCrash.Id; CallStackContainer CallStack = (CallStackContainer)CacheInstance[Key]; if( CallStack == null ) { CallStack = new CallStackContainer( CurrentCrash ); CallStack.bDisplayFunctionNames = true; CacheInstance.Insert( Key, CallStack ); } return CallStack; } }
/// <summary> /// Retrieve a cached (and pre-parsed) callstack container from the cache, or parse the raw callstack, and add to the cache. /// </summary> /// <param name="CurrentCrash">The crash to retrieve the parsed callstack for.</param> /// <returns>A parsed callstack.</returns> public CallStackContainer GetCallStack(Crash CurrentCrash) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(CrashId=" + CurrentCrash.Id + ")")) { string Key = CacheKeyPrefix + CallstackKeyPrefix + CurrentCrash.Id; CallStackContainer CallStack = (CallStackContainer)CacheInstance[Key]; if (CallStack == null) { CallStack = new CallStackContainer(CurrentCrash); CallStack.bDisplayFunctionNames = true; CacheInstance.Insert(Key, CallStack); } return(CallStack); } }
/// <summary> /// Sets the UserName and UserGroupName as derived data for a crash. /// </summary> /// <param name="CrashInstance">An instance of a crash we wish to augment with additional data.</param> public void PopulateUserInfo(Crash CrashInstance) { using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(CrashId=" + CrashInstance.Id + ")")) { try { int UserGroupId = CrashInstance.User.UserGroupId; var Result = Context.UserGroups.Where(i => i.Id == UserGroupId).First(); CrashInstance.UserGroupName = Result.Name; } catch (Exception Ex) { FLogger.Global.WriteException("PopulateUserInfo: " + Ex.ToString()); } } }
/// <summary> /// Retrieve a cached (and pre-parsed) callstack container from the cache, or parse the raw callstack, and add to the cache. /// </summary> /// <param name="currentCrash">The Crash to retrieve the parsed callstack for.</param> /// <returns>A parsed callstack.</returns> public DataModels.CallStackContainer GetCallStackFast(Crash currentCrash) { using (var logTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(CrashId=" + currentCrash.Id + ")")) { var key = CacheKeyPrefix + CallstackKeyPrefix + currentCrash.Id; var callStack = (CallStackContainer)CacheInstance[key]; if (callStack != null) { return(callStack); } callStack = new CallStackContainer(currentCrash); callStack.bDisplayFunctionNames = true; CacheInstance.Insert(key, callStack); return(callStack); } }
/// <summary> /// Sets the UserName and UserGroupName as derived data for a crash. /// </summary> /// <param name="CrashInstance">An instance of a crash we wish to augment with additional data.</param> public void PopulateUserInfo(Crash CrashInstance) { try { var query = ( from UserDetail in CrashRepositoryDataContext.Users where UserDetail.Id == CrashInstance.User.Id join UserGroupDetail in CrashRepositoryDataContext.UserGroups on UserDetail.UserGroupId equals UserGroupDetail.Id select UserGroupDetail.Name ); CrashInstance.UserGroupName = query.First(); } catch (Exception Ex) { Debug.WriteLine("Exception in PopulateUserInfo: " + Ex.ToString()); } }
/// <summary> /// Associate a crash with a Bugg. /// </summary> /// <param name="Bugg">The Bugg to add the crash reference to.</param> /// <param name="CurrentCrash">The crash to add to the Bugg.</param> /// <returns>true if a new relationship was added, false otherwise.</returns> public bool LinkCrashToBugg(Bugg Bugg, Crash CurrentCrash) { try { // Make sure we don't already have this relationship if (Context.Buggs_Crashes.Where(BuggInstance => BuggInstance.CrashId == CurrentCrash.Id && BuggInstance.BuggId == Bugg.Id).Count() < 1) { // We don't so create the relationship Buggs_Crash NewBugg = new Buggs_Crash(); NewBugg.CrashId = CurrentCrash.Id; NewBugg.BuggId = Bugg.Id; Context.Buggs_Crashes.InsertOnSubmit(NewBugg); return(true); } } catch (Exception Ex) { Debug.WriteLine("Exception in LinkCrashToBugg: " + Ex.ToString()); } return(false); }
void BuildPattern( Crash CrashInstance ) { List<string> Pattern = new List<string>(); // Get an array of callstack items CallStackContainer CallStack = new CallStackContainer( CrashInstance ); CallStack.bDisplayFunctionNames = true; if( CrashInstance.Pattern == null ) { // Set the module based on the modules in the callstack CrashInstance.Module = CallStack.GetModuleName(); try { using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(Id=" + CrashInstance.Id + ")" ) ) { foreach( CallStackEntry Entry in CallStack.CallStackEntries.Take( 64 ) ) { FunctionCall CurrentFunctionCall = new FunctionCall(); if( FunctionCalls.Where( f => f.Call == Entry.FunctionName ).Count() > 0 ) { CurrentFunctionCall = FunctionCalls.Where( f => f.Call == Entry.FunctionName ).First(); } else { CurrentFunctionCall = new FunctionCall(); CurrentFunctionCall.Call = Entry.FunctionName; FunctionCalls.InsertOnSubmit( CurrentFunctionCall ); } //CrashRepository.Context.SubmitChanges(); Pattern.Add( CurrentFunctionCall.Id.ToString() ); } //CrashInstance.Pattern = "+"; CrashInstance.Pattern = string.Join( "+", Pattern ); // We need something like this +1+2+3+5+ for searching for exact pattern like +5+ //CrashInstance.Pattern += "+"; CrashRepository.Context.SubmitChanges(); } } catch( Exception Ex ) { FLogger.WriteEvent( "Exception in BuildPattern: " + Ex.ToString() ); } } }
/// <summary> /// Associate a crash with a Bugg. /// </summary> /// <param name="Bugg">The Bugg to add the crash reference to.</param> /// <param name="CurrentCrash">The crash to add to the Bugg.</param> /// <returns>true if a new relationship was added, false otherwise.</returns> public bool LinkCrashToBugg( Bugg Bugg, Crash CurrentCrash ) { try { // Make sure we don't already have this relationship if( BuggsDataContext.Buggs_Crashes.Where( BuggInstance => BuggInstance.CrashId == CurrentCrash.Id && BuggInstance.BuggId == Bugg.Id ).Count() < 1 ) { // We don't so create the relationship Buggs_Crash NewBugg = new Buggs_Crash(); NewBugg.CrashId = CurrentCrash.Id; NewBugg.BuggId = Bugg.Id; BuggsDataContext.Buggs_Crashes.InsertOnSubmit( NewBugg ); return true; } } catch( Exception Ex ) { Debug.WriteLine( "Exception in LinkCrashToBugg: " + Ex.ToString() ); } return false; }
/// <summary> /// Parse a raw callstack into a pattern /// </summary> /// <param name="CurrentCrash">The crash with a raw callstack to parse.</param> private void ParseCallStack( Crash CurrentCrash ) { // Everything is disabled by default bDisplayUnformattedCallStack = false; bDisplayModuleNames = false; bDisplayFunctionNames = false; bDisplayFileNames = false; bDisplayFilePathNames = false; bool bSkipping = false; string LineToSkipUpto = ""; switch( CurrentCrash.CrashType ) { case 2: bSkipping = true; LineToSkipUpto = "FDebug::AssertFailed()"; break; case 3: bSkipping = true; LineToSkipUpto = "FDebug::EnsureFailed()"; break; } if (string.IsNullOrEmpty(CurrentCrash.RawCallStack)) { return; } CallStackEntries.Clear(); // Store off a pre split array of call stack lines string[] RawCallStackLines = CurrentCrash.RawCallStack.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); // Support older callstacks uploaded before UE4 upgrade if (!NewCallstackFormat.Match(RawCallStackLines[0]).Success) { foreach (string CurrentLine in RawCallStackLines) { // Exit if we've hit the max number of lines we want if (CallStackEntries.Count >= MaxLinesToParse) { break; } ParseUE3FormatCallstackLine(CurrentLine); } return; } foreach (string CurrentLine in RawCallStackLines) { // Exit if we've hit the max number of lines we want if( CallStackEntries.Count >= MaxLinesToParse ) { break; } if( bSkipping ) { if( CurrentLine.Contains( LineToSkipUpto ) ) { bSkipping = false; } } if( bSkipping ) { continue; } string ModuleName = "<Unknown>"; string FuncName = "<Unknown>"; string FilePath = ""; int LineNumber = 0; // Sample line "UE4_Engine!UEngine::Exec() + 21105 bytes [d:\depot\ue4\engine\source\runtime\engine\private\unrealengine.cpp:2777]" int PlingOffset = CurrentLine.IndexOf( '!' ); int PlusOffset = CurrentLine.IndexOf( " + " ); int BytesOffset = CurrentLine.IndexOf( " bytes" ); int OpenBracketOffset = CurrentLine.IndexOf( '[' ); int CloseBracketOffset = CurrentLine.LastIndexOf( ']' ); // Parse out the juicy info from the line of the callstack if( PlingOffset > 0 ) { ModuleName = CurrentLine.Substring( 0, PlingOffset ).Trim(); if( BytesOffset > PlingOffset ) { // Grab the function name if it exists FuncName = CurrentLine.Substring( PlingOffset + 1, BytesOffset - PlingOffset + " bytes".Length - 1 ).Trim(); // Grab the source file if( OpenBracketOffset > BytesOffset && CloseBracketOffset > BytesOffset && CloseBracketOffset > OpenBracketOffset ) { string FileLinePath = CurrentLine.Substring( OpenBracketOffset + 1, CloseBracketOffset - OpenBracketOffset - 1 ).Trim(); FilePath = FileLinePath.TrimEnd( "0123456789:".ToCharArray() ); int SourceLine = 0; Debug.Assert(FilePath.Length < FileLinePath.Length,"WRONG SIZE"); if( int.TryParse( FileLinePath.Substring(FilePath.Length + 1 ), out SourceLine ) ) { LineNumber = SourceLine; } } } } else if( BytesOffset > 0 ) { // Grab the module name if there is no function name ModuleName = CurrentLine.Substring( 0, PlusOffset ).Trim(); } CallStackEntries.Add( new CallStackEntry( CurrentLine, ModuleName, FilePath, FuncName, LineNumber ) ); } }
private void OnCrashesAdd( Crash CrashInstance ) { Buggs_Crashes.Add( new Buggs_Crash { Bugg = this, Crash = CrashInstance } ); SendPropertyChanged( null ); }
/// <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); }
partial void DeleteCrash(Crash instance);
private void detach_Crashes(Crash entity) { this.SendPropertyChanging(); entity.UserById = null; }
partial void InsertCrash(Crash instance);
/// <summary> /// Retrieve the parsed callstack for the crash. /// </summary> /// <param name="CrashInstance">The crash we require the callstack for.</param> /// <returns>A class containing the parsed callstack.</returns> public CallStackContainer GetCallStack(Crash CrashInstance) { CachedDataService CachedResults = new CachedDataService(HttpContext.Current.Cache, this); return(CachedResults.GetCallStackFast(CrashInstance)); }
public int CreateNewCrash(int AutoReporterId, string ComputerName, string UserName, string GameName, string PlatformName, string LanguageExt, string TimeOfCrash, string BuildVer, string ChangelistVer, string CommandLine, string BaseDir, string CallStack, string EngineMode) { string LogFileName = ConfigurationManager.AppSettings["LogFileName"]; int newID = -1; StreamWriter LogFile = null; try { LogFile = new StreamWriter(LogFileName, true); } catch (Exception) { // Ignore cases where the log file can't be opened (another instance may be writing to it already) } DateTime currentDate = DateTime.Now; if (LogFile != null) { LogFile.WriteLine(""); LogFile.WriteLine("Creating new report..." + currentDate.ToString("G")); } try { //TODO Catch exception if we fail to connect to the database var NewCrash = new Crash(); if (CallStack.Contains("Assertion failed:")) { NewCrash.CrashType = 2; } else if (CallStack.Contains("Ensure condition failed:")) { NewCrash.CrashType = 3; } else { NewCrash.CrashType = 1; } NewCrash.BaseDir = BaseDir; NewCrash.BuildVersion = BuildVer; NewCrash.ChangeListVersion = ChangelistVer; NewCrash.CommandLine = CommandLine; NewCrash.ComputerName = ComputerName; NewCrash.EngineMode = EngineMode; NewCrash.GameName = GameName; NewCrash.LanguageExt = LanguageExt; NewCrash.PlatformName = PlatformName; NewCrash.RawCallStack = CallStack; NewCrash.TimeOfCrash = ConvertDumpTimeToDateTime(TimeOfCrash); NewCrash.Status = "New"; using (var DataContext = new CrashReportDataContext()) { // Crashes after this upgrade refer to users by ID NewCrash.UserNameId = DataContext.FindOrAddUser(UserName); DataContext.Crashes.InsertOnSubmit(NewCrash); DataContext.SubmitChanges(); } newID = NewCrash.Id; } catch (Exception e) { if (LogFile != null) { LogFile.WriteLine("Exception caught!"); LogFile.WriteLine(e.Message); LogFile.Close(); } return newID; } //TODO Catch any execptions from failing to open the connection to the db. /* catch (conn e) { if (LogFile != null) { LogFile.WriteLine("Failed to open connection to database!"); LogFile.WriteLine("ConnectionString"); LogFile.WriteLine(e.Message); LogFile.Close(); } return -1; }*/ if (LogFile != null) { LogFile.WriteLine("Successfully created new record with id " + newID.ToString()); LogFile.Close(); } return newID; }
/// <summary> /// Construct a processed callstack. /// </summary> /// <param name="CurrentCrash"></param> public CallStackContainer(Crash CurrentCrash) { ParseCallStack(CurrentCrash); }
/// <summary> /// Constructor /// </summary> /// <param name="Crash">Crash</param> public FCrashMinimal( Crash Crash ) { TimeOfCrash = Crash.TimeOfCrash.Value; UserId = Crash.UserNameId.Value; }
/// <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> /// Parse a raw callstack into a pattern /// </summary> /// <param name="CurrentCrash">The crash with a raw callstack to parse.</param> private void ParseCallStack(Crash CurrentCrash) { // Everything is disabled by default bDisplayUnformattedCallStack = false; bDisplayModuleNames = false; bDisplayFunctionNames = false; bDisplayFileNames = false; bDisplayFilePathNames = false; bool bSkipping = false; string LineToSkipUpto = ""; switch (CurrentCrash.CrashType) { case 2: bSkipping = true; LineToSkipUpto = "FDebug::AssertFailed()"; break; case 3: bSkipping = true; LineToSkipUpto = "FDebug::EnsureFailed()"; break; } if (string.IsNullOrEmpty(CurrentCrash.RawCallStack)) { return; } CallStackEntries.Clear(); // Store off a pre split array of call stack lines string[] RawCallStackLines = CurrentCrash.RawCallStack.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); int Middle = RawCallStackLines.Length / 2; // Support older callstacks uploaded before UE4 upgrade if (!NewCallstackFormat.Match(RawCallStackLines[Middle]).Success) { foreach (string CurrentLine in RawCallStackLines) { // Exit if we've hit the max number of lines we want if (CallStackEntries.Count >= MaxLinesToParse) { break; } ParseUE3FormatCallstackLine(CurrentLine); } return; } foreach (string CurrentLine in RawCallStackLines) { // Exit if we've hit the max number of lines we want if (CallStackEntries.Count >= MaxLinesToParse) { break; } if (bSkipping) { if (CurrentLine.Contains(LineToSkipUpto)) { bSkipping = false; } } if (bSkipping) { continue; } string ModuleName = "<Unknown>"; string FuncName = "<Unknown>"; string FilePath = ""; int LineNumber = 0; // // Generic sample line "UE4_Engine!UEngine::Exec() {+ 21105 bytes} [d:\depot\ue4\engine\source\runtime\engine\private\unrealengine.cpp:2777]" // // Mac // thread_start() Address = 0x7fff87ae141d (filename not found) [in libsystem_pthread.dylib] // // Linux // Unknown!AFortPlayerController::execServerSaveLoadoutData(FFrame&, void*) + some bytes int ModuleSeparator = CurrentLine.IndexOf('!'); int PlusOffset = CurrentLine.IndexOf(" + "); int OpenFuncSymbol = CurrentLine.IndexOf('('); int CloseFuncSymbol = CurrentLine.IndexOf(')'); int OpenBracketOffset = CurrentLine.IndexOf('['); int CloseBracketOffset = CurrentLine.LastIndexOf(']'); int MacModuleStart = CurrentLine.IndexOf("[in "); int MacModuleEnd = MacModuleStart > 0 ? CurrentLine.IndexOf("]", MacModuleStart) : 0; bool bLinux = CurrentCrash.PlatformName.Contains("Linux"); bool bMac = CurrentCrash.PlatformName.Contains("Mac"); bool bWindows = CurrentCrash.PlatformName.Contains("Windows"); // Parse out the juicy info from the line of the callstack if (ModuleSeparator > 0) { ModuleName = CurrentLine.Substring(0, ModuleSeparator).Trim(); if (OpenFuncSymbol > ModuleSeparator && CloseFuncSymbol > OpenFuncSymbol) { // Grab the function name if it exists FuncName = CurrentLine.Substring(ModuleSeparator + 1, OpenFuncSymbol - ModuleSeparator - 1).Trim(); FuncName += "()"; // Grab the source file if (OpenBracketOffset > CloseFuncSymbol && CloseBracketOffset > OpenBracketOffset && bWindows) { string FileLinePath = CurrentLine.Substring(OpenBracketOffset + 1, CloseBracketOffset - OpenBracketOffset - 1).Trim(); FilePath = FileLinePath.TrimEnd("0123456789:".ToCharArray()); int SourceLine = 0; Debug.Assert(FilePath.Length < FileLinePath.Length, "WRONG SIZE"); if (int.TryParse(FileLinePath.Substring(FilePath.Length + 1), out SourceLine)) { LineNumber = SourceLine; } } } } else if (bWindows) { // Grab the module name if there is no function name int WhiteSpacePos = CurrentLine.IndexOf(' '); ModuleName = WhiteSpacePos > 0 ? CurrentLine.Substring(0, WhiteSpacePos) : CurrentLine; } if (bMac && MacModuleStart > 0 && MacModuleEnd > 0) { int AddressOffset = CurrentLine.IndexOf("Address ="); int OpenFuncSymbolMac = AddressOffset > 0 ? CurrentLine.Substring(0, AddressOffset).LastIndexOf('(') : 0; if (OpenFuncSymbolMac > 0) { FuncName = CurrentLine.Substring(0, OpenFuncSymbolMac).Trim(); FuncName += "()"; } ModuleName = CurrentLine.Substring(MacModuleStart + 3, MacModuleEnd - MacModuleStart - 3).Trim(); } // Remove callstack entries that match any of these functions. var FuncsToRemove = new HashSet <string>(new string[] { "RaiseException", "FDebug::", "Error::Serialize", "FOutputDevice::Logf", "FMsg::Logf", "ReportCrash", "NewReportEnsure", }); bool Contains = FuncsToRemove.Contains(FuncName, new CustomFuncComparer()); if (!Contains) { CallStackEntries.Add(new CallStackEntry(CurrentLine, ModuleName, FilePath, FuncName, LineNumber)); } } }
partial void UpdateCrash(Crash instance);
private void detach_Crashes(Crash entity) { this.SendPropertyChanging(); entity.CallStackPattern = null; }
private void attach_Crashes(Crash entity) { this.SendPropertyChanging(); entity.UserById = this; }
/// <summary> /// Parse a raw callstack into a pattern /// </summary> /// <param name="CurrentCrash">The crash with a raw callstack to parse.</param> private void ParseCallStack(Crash CurrentCrash) { // Everything is disabled by default bDisplayUnformattedCallStack = false; bDisplayModuleNames = false; bDisplayFunctionNames = false; bDisplayFileNames = false; bDisplayFilePathNames = false; bool bSkipping = false; string LineToSkipUpto = ""; switch (CurrentCrash.CrashType) { case 2: bSkipping = true; LineToSkipUpto = "FDebug::AssertFailed()"; break; case 3: bSkipping = true; LineToSkipUpto = "FDebug::EnsureFailed()"; break; } if (string.IsNullOrEmpty(CurrentCrash.RawCallStack)) { return; } CallStackEntries.Clear(); // Store off a pre split array of call stack lines string[] RawCallStackLines = CurrentCrash.RawCallStack.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); // Support older callstacks uploaded before UE4 upgrade if (!NewCallstackFormat.Match(RawCallStackLines[0]).Success) { foreach (string CurrentLine in RawCallStackLines) { // Exit if we've hit the max number of lines we want if (CallStackEntries.Count >= MaxLinesToParse) { break; } ParseUE3FormatCallstackLine(CurrentLine); } return; } foreach (string CurrentLine in RawCallStackLines) { // Exit if we've hit the max number of lines we want if (CallStackEntries.Count >= MaxLinesToParse) { break; } if (bSkipping) { if (CurrentLine.Contains(LineToSkipUpto)) { bSkipping = false; } } if (bSkipping) { continue; } string ModuleName = "<Unknown>"; string FuncName = "<Unknown>"; string FilePath = ""; int LineNumber = 0; // Sample line "UE4_Engine!UEngine::Exec() + 21105 bytes [d:\depot\ue4\engine\source\runtime\engine\private\unrealengine.cpp:2777]" int PlingOffset = CurrentLine.IndexOf('!'); int PlusOffset = CurrentLine.IndexOf(" + "); int BytesOffset = CurrentLine.IndexOf(" bytes"); int OpenBracketOffset = CurrentLine.IndexOf('['); int CloseBracketOffset = CurrentLine.LastIndexOf(']'); // Parse out the juicy info from the line of the callstack if (PlingOffset > 0) { ModuleName = CurrentLine.Substring(0, PlingOffset).Trim(); if (BytesOffset > PlingOffset) { // Grab the function name if it exists FuncName = CurrentLine.Substring(PlingOffset + 1, BytesOffset - PlingOffset + " bytes".Length - 1).Trim(); // Grab the source file if (OpenBracketOffset > BytesOffset && CloseBracketOffset > BytesOffset && CloseBracketOffset > OpenBracketOffset) { string FileLinePath = CurrentLine.Substring(OpenBracketOffset + 1, CloseBracketOffset - OpenBracketOffset - 1).Trim(); FilePath = FileLinePath.TrimEnd("0123456789:".ToCharArray()); int SourceLine = 0; Debug.Assert(FilePath.Length < FileLinePath.Length, "WRONG SIZE"); if (int.TryParse(FileLinePath.Substring(FilePath.Length + 1), out SourceLine)) { LineNumber = SourceLine; } } } } else if (BytesOffset > 0) { // Grab the module name if there is no function name ModuleName = CurrentLine.Substring(0, PlusOffset).Trim(); } CallStackEntries.Add(new CallStackEntry(CurrentLine, ModuleName, FilePath, FuncName, LineNumber)); } }
private void detach_CrashesFromName(Crash entity) { this.SendPropertyChanging(); entity.UserByName = null; }
private void OnCrashesRemove( Crash CrashInstance ) { Buggs_Crash BuggCrash = Buggs_Crashes.FirstOrDefault( BuggCrashInstance => BuggCrashInstance.BuggId == Id && BuggCrashInstance.CrashId == CrashInstance.Id ); Buggs_Crashes.Remove( BuggCrash ); SendPropertyChanged( null ); }