private static void GetErrorMessageFromMetadata(FReportData ReportData, FGenericCrashContext CrashContext) { if (string.IsNullOrEmpty(CrashContext.PrimaryCrashProperties.ErrorMessage)) { CrashContext.PrimaryCrashProperties.ErrorMessage = string.Join("\n", ReportData.ErrorMessage); } }
// From CrashUpload.cpp /* struct FCompressedCrashFile : FNoncopyable { int32 CurrentFileIndex; // 4 bytes for file index FString Filename; // 4 bytes for length + 260 bytes for char data TArray<uint8> Filedata; // 4 bytes for length + N bytes for data } */ /// <summary> Enqueues a new crash. </summary> private bool EnqueueNewReport(string NewReportPath) { string ReportName = Path.GetFileName(NewReportPath); string CompressedReportPath = Path.Combine(NewReportPath, ReportName + ".ue4crash"); string MetadataPath = Path.Combine(NewReportPath, ReportName + ".xml"); bool bIsCompressed = File.Exists(CompressedReportPath) && File.Exists(MetadataPath); if (bIsCompressed) { FCompressedCrashInformation CompressedCrashInformation = XmlHandler.ReadXml<FCompressedCrashInformation>(MetadataPath); bool bResult = DecompressReport(CompressedReportPath, CompressedCrashInformation); if (!bResult) { ReportProcessor.MoveReportToInvalid(NewReportPath, "DECOMPRESSION_FAIL_" + DateTime.Now.Ticks + "_" + ReportName); return false; } else { // Rename metadata file to not interfere with the WERReportMetadata. File.Move(MetadataPath, Path.ChangeExtension(MetadataPath, "processed_xml")); } } // Unified crash reporting FGenericCrashContext GenericContext = FindCrashContext(NewReportPath); FGenericCrashContext Context = GenericContext; bool bContextDirty = false; WERReportMetadata MetaData = FindMetadata(NewReportPath); if (MetaData != null) { if (Context == null) { // Missing crash context FReportData ReportData = new FReportData(MetaData, NewReportPath); ConvertMetadataToCrashContext(ReportData, NewReportPath, ref Context); bContextDirty = true; } else if (!Context.HasProcessedData()) { // Missing data - try to get from WER metadata FReportData ReportData = new FReportData(MetaData, NewReportPath); GetErrorMessageFromMetadata(ReportData, Context); bContextDirty = true; } } if (Context == null) { CrashReporterProcessServicer.WriteFailure("! NoCntx : Path=" + NewReportPath); ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath)); return false; } Context.CrashDirectory = NewReportPath; Context.PrimaryCrashProperties.SetPlatformFullName(); // Added data from WER, save to the crash context file. if (bContextDirty) { Context.ToFile(); } FEngineVersion EngineVersion = new FEngineVersion(Context.PrimaryCrashProperties.EngineVersion); uint BuiltFromCL = EngineVersion.Changelist; string BranchName = EngineVersion.Branch; if (string.IsNullOrEmpty(BranchName)) { CrashReporterProcessServicer.WriteEvent("% Warning NoBranch: BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath + " EngineVersion=" + Context.PrimaryCrashProperties.EngineVersion); Context.PrimaryCrashProperties.ProcessorFailedMessage = "Engine version has no branch name. EngineVersion=" + Context.PrimaryCrashProperties.EngineVersion; Context.ToFile(); } else if (BranchName.Equals(CrashReporterConstants.LicenseeBranchName, StringComparison.InvariantCultureIgnoreCase)) { CrashReporterProcessServicer.WriteEvent("% Warning branch is UE4-QA : BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); Context.PrimaryCrashProperties.ProcessorFailedMessage = "Branch was the forbidden LicenseeBranchName=" + BranchName; Context.ToFile(); } // Look for the Diagnostics.txt, if we have a diagnostics file we can continue event if the CL is marked as broken. bool bHasDiagnostics = FindDiagnostics(NewReportPath); if (BuiltFromCL == 0 && (!bHasDiagnostics && !Context.HasProcessedData())) { // For now ignore all locally made crashes. CrashReporterProcessServicer.WriteEvent("% Warning CL=0 and no useful data : BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); Context.PrimaryCrashProperties.ProcessorFailedMessage = "Report from CL=0 has no diagnostics, callstack or error msg"; Context.ToFile(); } // Check static reports index for duplicated reports // This WILL happen when running multiple, non-mutually exclusive crash sources (e.g. Receiver + Data Router) // This can be safely discontinued when all crashes come from the same SQS // This DOES NOT scale to multiple CRP instances lock (ReportIndexLock) { if (!ReportIndex.TryAddNewReport(ReportName)) { // Crash report not accepted by index CrashReporterProcessServicer.WriteEvent(string.Format( "EnqueueNewReport: Duplicate report skipped {0} in queue {1}", NewReportPath, QueueName)); CrashReporterProcessServicer.StatusReporter.IncrementCount(StatusReportingEventNames.DuplicateRejected); ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath)); return false; } } if (ShouldDecimateNextReport()) { CrashReporterProcessServicer.WriteEvent(string.Format("EnqueueNewReport: Discarding Report due to backlog of {0} in queue {1}: Path={2}", GetTotalWaitingCount(), QueueName, NewReportPath)); CrashReporterProcessServicer.StatusReporter.IncrementCount(StatusReportingEventNames.ReportDiscarded); ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath)); return false; } lock (NewReportsLock) { NewCrashContexts.Enqueue(Context); } EnqueueCounter.AddEvent(); CrashReporterProcessServicer.StatusReporter.IncrementCount(StatusReportingEventNames.QueuedEvent); CrashReporterProcessServicer.WriteEvent("+ Enqueued: BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath); return true; }
/// <summary> Converts WER metadata xml file to the crash context. </summary> private static void ConvertMetadataToCrashContext(FReportData ReportData, string NewReportPath, ref FGenericCrashContext OutCrashContext) { if (OutCrashContext == null) { OutCrashContext = new FGenericCrashContext(); } OutCrashContext.PrimaryCrashProperties.CrashVersion = (int)ECrashDescVersions.VER_1_NewCrashFormat; //OutCrashContext.PrimaryCrashProperties.ProcessId = 0; don't overwrite valid ids, zero is default anyway OutCrashContext.PrimaryCrashProperties.CrashGUID = new DirectoryInfo(NewReportPath).Name; // OutCrashContext.PrimaryCrashProperties.IsInternalBuild // OutCrashContext.PrimaryCrashProperties.IsPerforceBuild // OutCrashContext.PrimaryCrashProperties.IsSourceDistribution // OutCrashContext.PrimaryCrashProperties.SecondsSinceStart OutCrashContext.PrimaryCrashProperties.GameName = ReportData.GameName; // OutCrashContext.PrimaryCrashProperties.ExecutableName // OutCrashContext.PrimaryCrashProperties.BuildConfiguration // OutCrashContext.PrimaryCrashProperties.PlatformName // OutCrashContext.PrimaryCrashProperties.PlatformNameIni OutCrashContext.PrimaryCrashProperties.PlatformFullName = ReportData.Platform; OutCrashContext.PrimaryCrashProperties.EngineMode = ReportData.EngineMode; OutCrashContext.PrimaryCrashProperties.EngineVersion = ReportData.GetEngineVersion(); OutCrashContext.PrimaryCrashProperties.BuildVersion = ReportData.BuildVersion; OutCrashContext.PrimaryCrashProperties.CommandLine = ReportData.CommandLine; // OutCrashContext.PrimaryCrashProperties.LanguageLCID // Create a locate and get the language. int LanguageCode = 0; int.TryParse(ReportData.Language, out LanguageCode); try { if (LanguageCode > 0) { CultureInfo LanguageCI = new CultureInfo(LanguageCode); OutCrashContext.PrimaryCrashProperties.AppDefaultLocale = LanguageCI.Name; } } catch (Exception) { OutCrashContext.PrimaryCrashProperties.AppDefaultLocale = null; } if (string.IsNullOrEmpty(OutCrashContext.PrimaryCrashProperties.AppDefaultLocale)) { // Default to en-US OutCrashContext.PrimaryCrashProperties.AppDefaultLocale = "en-US"; } // OutCrashContext.PrimaryCrashProperties.IsUE4Release string WERUserName = ReportData.UserName; if (!string.IsNullOrEmpty(WERUserName) || string.IsNullOrEmpty(OutCrashContext.PrimaryCrashProperties.UserName)) { OutCrashContext.PrimaryCrashProperties.UserName = WERUserName; } OutCrashContext.PrimaryCrashProperties.BaseDir = ReportData.BaseDir; // OutCrashContext.PrimaryCrashProperties.RootDir OutCrashContext.PrimaryCrashProperties.MachineId = ReportData.MachineId; OutCrashContext.PrimaryCrashProperties.EpicAccountId = ReportData.EpicAccountId; // OutCrashContext.PrimaryCrashProperties.CallStack // OutCrashContext.PrimaryCrashProperties.SourceContext OutCrashContext.PrimaryCrashProperties.UserDescription = string.Join("\n", ReportData.UserDescription); // OutCrashContext.PrimaryCrashProperties.CrashDumpMode // OutCrashContext.PrimaryCrashProperties.Misc.NumberOfCores // OutCrashContext.PrimaryCrashProperties.Misc.NumberOfCoresIncludingHyperthreads // OutCrashContext.PrimaryCrashProperties.Misc.Is64bitOperatingSystem // OutCrashContext.PrimaryCrashProperties.Misc.CPUVendor // OutCrashContext.PrimaryCrashProperties.Misc.CPUBrand // OutCrashContext.PrimaryCrashProperties.Misc.PrimaryGPUBrand // OutCrashContext.PrimaryCrashProperties.Misc.OSVersionMajor // OutCrashContext.PrimaryCrashProperties.Misc.OSVersionMinor // OutCrashContext.PrimaryCrashProperties.Misc.AppDiskTotalNumberOfBytes // OutCrashContext.PrimaryCrashProperties.Misc.AppDiskNumberOfFreeBytes // OutCrashContext.PrimaryCrashProperties.MemoryStats.TotalPhysical // OutCrashContext.PrimaryCrashProperties.MemoryStats.TotalVirtual // OutCrashContext.PrimaryCrashProperties.MemoryStats.PageSize // OutCrashContext.PrimaryCrashProperties.MemoryStats.TotalPhysicalGB // OutCrashContext.PrimaryCrashProperties.MemoryStats.AvailablePhysical // OutCrashContext.PrimaryCrashProperties.MemoryStats.AvailableVirtual // OutCrashContext.PrimaryCrashProperties.MemoryStats.UsedPhysical // OutCrashContext.PrimaryCrashProperties.MemoryStats.PeakUsedPhysical // OutCrashContext.PrimaryCrashProperties.MemoryStats.UsedVirtual // OutCrashContext.PrimaryCrashProperties.MemoryStats.PeakUsedVirtual // OutCrashContext.PrimaryCrashProperties.MemoryStats.bIsOOM // OutCrashContext.PrimaryCrashProperties.MemoryStats.OOMAllocationSize // OutCrashContext.PrimaryCrashProperties.MemoryStats.OOMAllocationAlignment OutCrashContext.PrimaryCrashProperties.TimeofCrash = new DateTime(ReportData.Ticks); OutCrashContext.PrimaryCrashProperties.bAllowToBeContacted = ReportData.AllowToBeContacted; OutCrashContext.PrimaryCrashProperties.DeploymentName = ReportData.DeploymentName; OutCrashContext.PrimaryCrashProperties.IsEnsure = ReportData.IsEnsure; OutCrashContext.PrimaryCrashProperties.IsAssert = ReportData.IsAssert; OutCrashContext.PrimaryCrashProperties.CrashType = ReportData.CrashType; GetErrorMessageFromMetadata(ReportData, OutCrashContext); }