private static RaygunStackTraceFrame[] BuildNativeStackTrace(Dictionary <IntPtr, RaygunImageInfo> images, Exception exception) { var lines = new List <RaygunStackTraceFrame>(); var stackTrace = new StackTrace(exception, true); var frames = stackTrace.GetFrames(); foreach (StackFrame frame in frames) { if (frame.HasNativeImage()) { IntPtr nativeIP = frame.GetNativeIP(); IntPtr nativeImageBase = frame.GetNativeImageBase(); if (!images.ContainsKey(nativeImageBase)) { RaygunImageInfo imageInfo = ReadImage(nativeImageBase); images[nativeImageBase] = imageInfo; } var line = new RaygunStackTraceFrame { IP = nativeIP.ToInt64(), ImageBase = nativeImageBase.ToInt64(), Raw = frame.ToString() }; ParseRawStackTraceLine(line); lines.Add(line); } } return(lines.Count == 0 ? null : lines.ToArray()); }
private static RaygunStackTraceFrame[] BuildStackTrace(Exception exception) { var lines = new List <RaygunStackTraceFrame>(); if (exception.StackTrace != null) { char[] separators = { '\r', '\n' }; var frames = exception.StackTrace.Split(separators, StringSplitOptions.RemoveEmptyEntries); foreach (string line in frames) { // Trim the stack trace line string stackTraceLine = line.Trim(); if (stackTraceLine.StartsWith(CLASS_NAME_PREFIX)) { stackTraceLine = stackTraceLine.Substring(CLASS_NAME_PREFIX.Length); } RaygunStackTraceFrame stackTraceFrame = new RaygunStackTraceFrame { Raw = stackTraceLine }; ParseRawStackTraceLine(stackTraceFrame); lines.Add(stackTraceFrame); } } return(lines.Count == 0 ? null : lines.ToArray()); }
private static void ParseRawStackTraceLine(RaygunStackTraceFrame stackTraceFrame) { if (!string.IsNullOrWhiteSpace(stackTraceFrame.Raw)) { string stackTraceLine = stackTraceFrame.Raw; // Find the separation between class name and method name: int methodNameIndex = stackTraceLine.IndexOf("("); if (methodNameIndex > 0) { if (stackTraceLine[methodNameIndex - 1] == '>') { // The method has generic parameters, so we need to do a little more work to find the separation between class and method names methodNameIndex -= 2; // start before the angle bracket we just found int angleBracketPairing = 1; while (methodNameIndex > 0 && angleBracketPairing != 0) { char c = stackTraceLine[methodNameIndex]; if (c == '>') { angleBracketPairing++; } else if (c == '<') { angleBracketPairing--; } methodNameIndex--; } } methodNameIndex = stackTraceLine.LastIndexOf(METHOD_NAME_PREFIX, methodNameIndex); if (methodNameIndex > 0) { // After finding the separation between class name and method name, the class name is the first part of the string: stackTraceFrame.ClassName = stackTraceLine.Substring(0, methodNameIndex); // Find the separation between method name and file name: methodNameIndex += METHOD_NAME_PREFIX.Length; int fileNameIndex = stackTraceLine.IndexOf(FILE_NAME_PREFIX, methodNameIndex); if (fileNameIndex > 0) { stackTraceFrame.MethodName = stackTraceLine.Substring(methodNameIndex, fileNameIndex - methodNameIndex); // Find the separation between file name and line number: fileNameIndex += FILE_NAME_PREFIX.Length; int lineNumberIndex = stackTraceLine.IndexOf(LINE_NUMBER_PREFIX, fileNameIndex); if (lineNumberIndex > 0) { stackTraceFrame.FileName = stackTraceLine.Substring(fileNameIndex, lineNumberIndex - fileNameIndex); // Parse the line number: lineNumberIndex += LINE_NUMBER_PREFIX.Length; string lineNumberStr = stackTraceLine.Substring(lineNumberIndex); if (int.TryParse(lineNumberStr, out var lineNumber)) { stackTraceFrame.LineNumber = lineNumber; } } else { // In this case, the frame does not have a line number: stackTraceFrame.FileName = stackTraceLine.Substring(fileNameIndex); } } else { // In this case, the frame only has method and class names: stackTraceFrame.MethodName = stackTraceLine.Substring(methodNameIndex); } } } } }