public static ElasticSDResult FromResult(SDResult result, BundleMetainfo bundleInfo, DumpMetainfo dumpInfo, PathHelper pathHelper) { if (result == null) { throw new ArgumentNullException("result"); } var eResult = new ElasticSDResult() { BundleId = dumpInfo.BundleId, DumpId = dumpInfo.DumpId, Timestamp = dumpInfo.Created, Type = dumpInfo.DumpType.ToString(), Executable = (result.SystemContext as SDCDSystemContext)?.FileName ?? "", IsManaged = result.IsManagedProcess, ProcessArchitecture = result.SystemContext?.ProcessArchitecture, SystemArchitecture = result.SystemContext?.SystemArchitecture, NrThreads = result.ThreadInformation != null ? result.ThreadInformation.Count : 0, LastEventDescription = result.LastEvent?.Description, LoadedModules = result.SystemContext?.DistinctModules().Select(m => m.FileName).Aggregate("", (m1, m2) => m1 + " " + m2), LoadedModulesVersioned = result.SystemContext?.DistinctModules().Select(m => $"{m.FileName}:{m.Version ?? "-"}").Aggregate("", (m1, m2) => m1 + " " + m2), DynatraceLoadedModulesVersioned = result.SystemContext?.DistinctModules().Where(m => m.Tags.Contains(SDTag.DynatraceAgentTag)).Select(m => $"{m.FileName}:{m.Version ?? "-"}").Aggregate("", (m1, m2) => m1 + " " + m2), ExitType = result.LastEvent?.Type ?? "" }; bundleInfo.CustomProperties.TryGetValue("ref", out string reference); eResult.Reference = reference; bundleInfo.CustomProperties.TryGetValue("tenantId", out string tenantId); eResult.TenantId = tenantId; eResult.FaultingStacktrace = result.GetErrorOrLastExecutingThread()?.ToText(); eResult.Stacktraces = ""; // TODO if (dumpInfo.Finished != null && dumpInfo.Started != null) { int durationSecs = (int)dumpInfo.Finished.Subtract(dumpInfo.Started).TotalSeconds; if (durationSecs > 0) { // Only if a valid duration is present eResult.AnalyzationDuration = durationSecs; } } long dumpSize = ComputeDumpFileSizeKb(bundleInfo, dumpInfo, pathHelper); if (dumpSize >= 0) { eResult.DumpSizeKb = dumpSize; } return(eResult); }
private static double?CalculateStacktraceSimilarity(SDResult resultA, SDResult resultB) { var errorThreadA = resultA.GetErrorOrLastExecutingThread(); var errorThreadB = resultB.GetErrorOrLastExecutingThread(); if (errorThreadA == null && errorThreadB == null) { return(null); // no value in comparing if there are none } if (errorThreadA == null ^ errorThreadB == null) { return(0); // one result has an error thread, while the other one does not. inequal. } // approach 1: iterate over the top X stracktraces and compare each frame for similarity // CN -> not sure about this algorithm. there are cases where some frames differ while it's the same root cause. // maybe just generally looking how many frames appear in the other stack might be ok. //int take = 15; //int count = 0; //double methodsSimilarCount = 0; //double modulesSimilarCount = 0; //using (var iter1 = t1.StackTrace.GetEnumerator()) //using (var iter2 = t2.StackTrace.GetEnumerator()) { // // iterate while both stacktraces still have elements // while (take-- > 0 && iter1.MoveNext() && iter2.MoveNext()) { // count++; // methodsSimilarCount += iter1.Current.MethodName.Equals(iter2.Current.MethodName, StringComparison.OrdinalIgnoreCase) // ? 1.0 // : 0.0; // modulesSimilarCount += iter1.Current.ModuleName.Equals(iter2.Current.ModuleName, StringComparison.OrdinalIgnoreCase) // ? 1.0 // : 0.0; // } //} // approach 2: apply "weight" to each stackframe. it should represent the relevance of the frame to the crash-reason. // treat all "error"-frames as 1.0. adjacent frames get linearly decreasing weight. // TBD // approach 3: let's start with a dead-simple alg. look how many frames of stack A appear in stack B and vice versa. int AinBCount = CountAinB(errorThreadA.StackTrace, errorThreadB.StackTrace, FrameEquals); int BinACount = CountAinB(errorThreadB.StackTrace, errorThreadA.StackTrace, FrameEquals); double ainb = AinBCount / (double)errorThreadA.StackTrace.Count; double bina = BinACount / (double)errorThreadB.StackTrace.Count; return(Math.Min(ainb, bina)); }
private static double?CalculateExceptionMessageSimilarity(SDResult resultA, SDResult resultB) { var exceptionA = resultA.GetErrorOrLastExecutingThread()?.LastException; var exceptionB = resultB.GetErrorOrLastExecutingThread()?.LastException; if (exceptionA == null && exceptionB == null) { return(null); // no value in comparing if there are none } if (exceptionA == null ^ exceptionB == null) { return(0); // one result has an error thread, while the other one does not. inequal. } return(EqualsIgnoreNonAscii(exceptionA.Type, exceptionB.Type) && EqualsIgnoreNonAscii(exceptionA.Message, exceptionB.Message) ? 1.0 : 0.0); // omit comparison of StackTrace for now. maybe implement at later point if it makes sense. }
/// <summary> /// Find the number of modules are the same in both stacks. /// /// returns a number between 0.0 and 1.0, where 1.0 is full similarity, and 0.0 is no similarity /// </summary> private static double?CalculateModulesInStacktraceSimilarity(SDResult resultA, SDResult resultB) { var errorThreadA = resultA.GetErrorOrLastExecutingThread(); var errorThreadB = resultB.GetErrorOrLastExecutingThread(); if (errorThreadA == null && errorThreadB == null) { return(null); // no value in comparing if there are none } if (errorThreadA == null ^ errorThreadB == null) { return(0); // one result has an error thread, while the other one does not. inequal. } var modulesA = errorThreadA.StackTrace.Select(x => x.ModuleName).Distinct(); var modulesB = errorThreadB.StackTrace.Select(x => x.ModuleName).Distinct(); int AinBCount = CountAinB(modulesA, modulesB, (a, b) => EqualsIgnoreNonAscii(a, b)); int BinACount = CountAinB(modulesB, modulesA, (a, b) => EqualsIgnoreNonAscii(a, b)); double ainb = AinBCount / (double)modulesA.Count(); double bina = BinACount / (double)modulesB.Count(); return(Math.Min(ainb, bina)); }
public static FaultReport CreateFaultReport(SDResult result, int maxFrames = 80) { var faultReport = new FaultReport(); // modules & stackframes var faultingThread = result.GetErrorOrLastExecutingThread(); if (faultingThread != null) { faultReport.FaultingFrames = new List <string>(); if (faultingThread.StackTrace.Count <= maxFrames) { foreach (var frame in faultingThread.StackTrace) { faultReport.FaultingFrames.Add(frame.ToString()); } } else { // makes ure extra long stacktraces (stack overflows) are serialized in a human readable way // add only the first X, then "...", then the last X foreach (var frame in faultingThread.StackTrace.Take(maxFrames / 2)) { faultReport.FaultingFrames.Add(frame.ToString()); } faultReport.FaultingFrames.Add("..."); foreach (var frame in faultingThread.StackTrace.TakeLast(maxFrames / 2)) { faultReport.FaultingFrames.Add(frame.ToString()); } } } var faultReasonSb = new StringBuilder(); // lastevent if (result.LastEvent != null) { if (result.LastEvent.Description.StartsWith("Break instruction exception")) { // "break instruction" as a lastevent is so generic, it's practically useless. treat it as if there was no information at all. } else { if (!string.IsNullOrEmpty(result.LastEvent.Type)) { faultReasonSb.Append(result.LastEvent.Type); } if (!string.IsNullOrEmpty(result.LastEvent.Description)) { if (faultReasonSb.Length > 0) { faultReasonSb.Append(", "); } faultReasonSb.Append(result.LastEvent.Description); } } } // exception var exception = result.GetErrorOrLastExecutingThread()?.LastException; if (exception != null) { if (!string.IsNullOrEmpty(exception.Type)) { if (faultReasonSb.Length > 0) { faultReasonSb.Append(", "); } faultReasonSb.Append(exception.Type); } if (!string.IsNullOrEmpty(exception.Message)) { if (faultReasonSb.Length > 0) { faultReasonSb.Append(", "); } faultReasonSb.Append(exception.Message); } } faultReport.FaultReason = faultReasonSb.ToString(); return(faultReport); }