/// <summary> /// Returns a hash that represents the results of a role. Should be 0 if no fatal errors or ensures /// </summary> /// <param name="InArtifacts"></param> /// <returns></returns> protected virtual string GetRoleResultHash(UnrealRoleArtifacts InArtifacts) { const int MaxCallstackLines = 10; UnrealLogParser.LogSummary LogSummary = InArtifacts.LogSummary; string TotalString = ""; //Func<int, string> ComputeHash = (string Str) => { return Hasher.ComputeHash(Encoding.UTF8.GetBytes(Str)); }; if (LogSummary.FatalError != null) { TotalString += string.Join("\n", InArtifacts.LogSummary.FatalError.Callstack.Take(MaxCallstackLines)); TotalString += "\n"; } foreach (var Ensure in LogSummary.Ensures) { TotalString += string.Join("\n", Ensure.Callstack.Take(MaxCallstackLines)); TotalString += "\n"; } string Hash = Hasher.ComputeHash(TotalString); return(Hash); }
/// <summary> /// Parses the output of an application to try and determine a failure cause (if one exists). Returns /// 0 for graceful shutdown /// </summary> /// <param name="Prefix"></param> /// <param name="App"></param> /// <returns></returns> protected virtual int GetRoleSummary(UnrealRoleArtifacts InArtifacts, out string Summary) { const int MaxLogLines = 10; const int MaxCallstackLines = 20; UnrealLogParser.LogSummary LogSummary = InArtifacts.LogSummary; string ExitReason = "Unknown"; int ExitCode = GetExitCodeAndReason(InArtifacts, out ExitReason); MarkdownBuilder MB = new MarkdownBuilder(); MB.H3(string.Format("Role: {0} ({1} {2})", InArtifacts.SessionRole.RoleType, InArtifacts.SessionRole.Platform, InArtifacts.SessionRole.Configuration)); if (ExitCode != 0) { MB.H4(string.Format("Result: Abnormal Exit: {0}", ExitReason)); } else { MB.H4(string.Format("Result: {0}", ExitReason)); } int FatalErrors = LogSummary.FatalError != null ? 1 : 0; if (LogSummary.FatalError != null) { MB.H4(string.Format("Fatal Error: {0}", LogSummary.FatalError.Message)); MB.UnorderedList(InArtifacts.LogSummary.FatalError.Callstack.Take(MaxCallstackLines)); if (InArtifacts.LogSummary.FatalError.Callstack.Count() > MaxCallstackLines) { MB.Paragraph("See log for full callstack"); } } if (LogSummary.Ensures.Count() > 0) { foreach (var Ensure in LogSummary.Ensures) { MB.H4(string.Format("Ensure: {0}", Ensure.Message)); MB.UnorderedList(Ensure.Callstack.Take(MaxCallstackLines)); if (Ensure.Callstack.Count() > MaxCallstackLines) { MB.Paragraph("See log for full callstack"); } } } MB.Paragraph(string.Format("FatalErrors: {0}, Ensures: {1}, Errors: {2}, Warnings: {3}", FatalErrors, LogSummary.Ensures.Count(), LogSummary.Errors.Count(), LogSummary.Warnings.Count())); if (GetConfiguration().ShowErrorsInSummary&& InArtifacts.LogSummary.Errors.Count() > 0) { MB.H4("Errors"); MB.UnorderedList(LogSummary.Errors.Take(MaxLogLines)); if (LogSummary.Errors.Count() > MaxLogLines) { MB.Paragraph(string.Format("(First {0} of {1} errors)", MaxLogLines, LogSummary.Errors.Count())); } } if (GetConfiguration().ShowWarningsInSummary&& InArtifacts.LogSummary.Warnings.Count() > 0) { MB.H4("Warnings"); MB.UnorderedList(LogSummary.Warnings.Take(MaxLogLines)); if (LogSummary.Warnings.Count() > MaxLogLines) { MB.Paragraph(string.Format("(First {0} of {1} warnings)", MaxLogLines, LogSummary.Warnings.Count())); } } MB.H4("Artifacts"); MB.Paragraph(string.Format("Log: {0}", InArtifacts.LogPath)); MB.Paragraph(string.Format("Commandline: {0}", InArtifacts.AppInstance.CommandLine)); MB.Paragraph(InArtifacts.ArtifactPath); Summary = MB.ToString(); return(ExitCode); }
/// <summary> /// Parses the provided artifacts to determine the cause of an exit and whether it was abnormal /// </summary> /// <param name="InArtifacts"></param> /// <param name="Reason"></param> /// <param name="WasAbnormal"></param> /// <returns></returns> protected virtual int GetExitCodeAndReason(UnrealRoleArtifacts InArtifacts, out string ExitReason) { UnrealLogParser.LogSummary LogSummary = InArtifacts.LogSummary; // Assume failure! int ExitCode = -1; ExitReason = "Unknown"; if (LogSummary.FatalError != null) { ExitReason = "Process encountered fatal error"; } else if (LogSummary.Ensures.Count() > 0 && CachedConfig.FailOnEnsures) { ExitReason = string.Format("Process encountered {0} Ensures", LogSummary.Ensures.Count()); } else if (InArtifacts.AppInstance.WasKilled) { ExitReason = "Process was killed"; } else if (LogSummary.HasTestExitCode) { if (LogSummary.TestExitCode == 0) { ExitReason = "Process exited with code 0"; } else { ExitReason = string.Format("Process exited with error code {0}", LogSummary.TestExitCode); } ExitCode = LogSummary.TestExitCode; } else if (LogSummary.RequestedExit) { ExitReason = string.Format("Process requested exit with no fatal errors"); ExitCode = 0; } else { // ok, process appears to have exited for no good reason so try to divine a result... if (LogSummary.HasTestExitCode == false && InArtifacts.SessionRole.CommandLine.ToLower().Contains("-gauntlet")) { Log.Verbose("Role {0} had 0 exit code but used Gauntlet and no TestExitCode was found. Assuming failure", InArtifacts.SessionRole.RoleType); ExitCode = -1; ExitReason = "No test result from Gauntlet controller"; } } // Normal exits from server are not ok if we had clients running! if (ExitCode == 0 && InArtifacts.SessionRole.RoleType.IsServer()) { bool ClientsKilled = SessionArtifacts.Any(A => A.AppInstance.WasKilled && A.SessionRole.RoleType.IsClient()); if (ClientsKilled) { ExitCode = -1; ExitReason = "Server exited while clients were running"; } } if (ExitCode == -1 && string.IsNullOrEmpty(ExitReason)) { ExitReason = "Process exited with no indication of success"; } return(ExitCode); }