double ReadProcessAddReport( DirectoryInfo DirInfo, FGenericCrashContext NewContext ) { try { string DumpFileName = null; string LogFileName = null; string DiagnosticsFileName = ""; string VideoFileName = null; string CrashContextName = ""; foreach( FileInfo Info in DirInfo.GetFiles() ) { switch( Info.Extension.ToLower() ) { case ".avi": case ".mp4": VideoFileName = Info.Name; break; case ".runtime-xml": CrashContextName = Info.Name; break; case ".log": LogFileName = Info.Name; break; case ".txt": if (string.Compare( Info.Name, CrashReporterConstants.DiagnosticsFileName, true ) == 0) { DiagnosticsFileName = Info.Name; ReadDiagnosticsFile( NewContext ); } break; case ".dmp": case ".mdmp": DumpFileName = Info.Name; // Check to see if this has been processed locally FileInfo DiagnosticsInfo = new FileInfo( Path.Combine( DirInfo.FullName, CrashReporterConstants.DiagnosticsFileName ) ); if (!DiagnosticsInfo.Exists && !NewContext.HasProcessedData()) { ProcessDumpFile( Info.FullName, NewContext ); } // Check to see if a new one has been created DiagnosticsInfo.Refresh(); if( DiagnosticsInfo.Exists ) { DiagnosticsFileName = DiagnosticsInfo.Name; } break; default: break; } } // Check if the new context has processed data. if (!NewContext.HasProcessedData()) { CrashReporterProcessServicer.WriteEvent(string.Format("PROC-{0} ", ProcessorIndex) + "% Warning no callstack or error msg : BuiltFromCL=" + string.Format("{0,7}", NewContext.PrimaryCrashProperties.EngineVersion) + " Path=" + NewContext.CrashDirectory); NewContext.PrimaryCrashProperties.ProcessorFailedMessage = "No callstack or error message. Diagnostics missing or failed."; } Stopwatch WaitSW = Stopwatch.StartNew(); // Wait for previous task, should not really happen. int AddReportTaskSlot = WaitForFreeAddReportTask(); CrashReporterProcessServicer.WriteEvent(string.Format("PROC-{0} ", ProcessorIndex) + string.Format("Starting AddReportTask running on slot {0} of {1} ({2} active)", AddReportTaskSlot, Config.Default.AddReportsPerProcessor, GetActiveAddReportTasks())); double WaitTime = WaitSW.Elapsed.TotalSeconds; //bool bAdded = AddReport(DirInfo, NewContext, LogFileName, DumpFileName, VideoFileName ); // Save/update crash context to the file. NewContext.ToFile(); AddReportTasks[AddReportTaskSlot] = Task.Factory.StartNew(() => { bool bAdded = AddReport( DirInfo, NewContext, LogFileName, DumpFileName, VideoFileName ); FinalizeReport( bAdded, DirInfo, NewContext ); } ); return WaitTime; } catch( Exception Ex ) { CrashReporterProcessServicer.WriteException(string.Format("PROC-{0} ", ProcessorIndex) + "ProcessReport: " + NewContext.CrashDirectory + "\n\n: " + Ex.ToString()); } return 0.0; }
/// <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 var NewCrash = new CrashDescription(); NewCrash.CrashType = NewContext.PrimaryCrashProperties.GetCrashType(); NewCrash.BranchName = EngineVersion.GetCleanedBranch(); NewCrash.GameName = NewContext.PrimaryCrashProperties.GameName; NewCrash.Platform = NewContext.PrimaryCrashProperties.PlatformFullName; NewCrash.EngineMode = NewContext.PrimaryCrashProperties.EngineMode; NewCrash.EngineVersion = EngineVersion.VersionNumber; NewCrash.BuildVersion = NewContext.PrimaryCrashProperties.BuildVersion; NewCrash.CommandLine = NewContext.PrimaryCrashProperties.CommandLine; NewCrash.BaseDir = NewContext.PrimaryCrashProperties.BaseDir; NewCrash.bProcessorFailed = !string.IsNullOrWhiteSpace(NewContext.PrimaryCrashProperties.ProcessorFailedMessage); 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(); NewCrash.UserActivityHint = NewContext.PrimaryCrashProperties.UserActivityHint; NewCrash.CrashGUID = NewContext.PrimaryCrashProperties.CrashGUID; // 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.WriteEvent(string.Format("PROC-{0} ", ProcessorIndex) + "! BadStack: BuiltFromCL=" + string.Format( "{0,7}", NewContext.PrimaryCrashProperties.EngineVersion ) + " Path=" + NewContext.CrashDirectory ); NewContext.PrimaryCrashProperties.ProcessorFailedMessage = string.Format("Callstack was too small. {0} lines (minimum {1})", NewCrash.CallStack.Length, CrashReporterConstants.MinCallstackDepth); NewContext.ToFile(); } XmlPayload = XmlHandler.ToXmlString<CrashDescription>( NewCrash ); } catch (Exception Ex) { CrashReporterProcessServicer.WriteException(string.Format("PROC-{0} ", ProcessorIndex) + "CreateCrash: " + Ex.ToString()); } return XmlPayload; }