/// <summary>
        /// Internal logic - adapted from Environment.GetStackTrace from .NET BCL.
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="ctx"></param>
        /// <param name="builder"></param>
        private static void GetExceptionReport(Exception ex, ExceptionReportingContext ctx, ref StringBuilder builder)
        {
            builder = builder ?? new StringBuilder(0xff);

            var message = ex.Message;

            builder.Append(ex.GetType().ToString());
            if (!string.IsNullOrEmpty(message))
            {
                builder.Append(": ").Append(message);
            }

            var innerEx = ex.InnerException;

            if (innerEx != null)
            {
                builder.Append(" ---> ");
                GetExceptionReport(innerEx, ctx, ref builder);
                builder.Append(Environment.NewLine).Append("   ");
                builder.Append(GetRuntimeResourceString("Exception_EndOfInnerExceptionStack") ??
                               "--- End of inner exception stack trace ---");
            }

            builder.Append(Environment.NewLine);
            GetStackTraceEx(ex, ctx, ref builder);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Produce a production style stack trace containing necessary
        /// info to recreate full line-mapping with symbols.
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        public static string GetExceptionReport(Exception ex)
        {
            StringBuilder builder = null;
            var           ctx     = new ExceptionReportingContext();

            GetExceptionReport(ex, ctx, ref builder);

            if (ctx.AssemblyInfo.Count > 0)
            {
                builder.AppendLine();
                builder.AppendLine("==========");

                var keys = new List <string>(ctx.AssemblyInfo.Keys);
                keys.Sort(StringComparer.OrdinalIgnoreCase);

                foreach (var key in keys)
                {
                    var info = ctx.AssemblyInfo[key];
                    builder.AppendFormat("MODULE: {0} => {1};", key, info.Assembly.FullName);
                    if (info.DebugInfo != null)
                    {
                        builder.AppendFormat(" G:{0:N}; A:{1}", info.DebugInfo.Guid, info.DebugInfo.Age);

                        var pdbFileName = Path.GetFileName(info.DebugInfo.Path);
                        if (!string.Equals(pdbFileName, info.ShortName + ".pdb", StringComparison.OrdinalIgnoreCase))
                        {
                            builder.Append("; F:").Append(pdbFileName);
                        }
                    }
                    builder.AppendLine();
                }
            }

            return(builder.ToString());
        }
        /// <summary>
        /// Record assembly short name, and it's associated PDB file.
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="assembly"></param>
        /// <param name="ctx"></param>
        private static void AppendAssemblyName(StringBuilder builder, Assembly assembly, ExceptionReportingContext ctx)
        {
            var assemblyName    = assembly.FullName;
            int idxShortNameEnd = assemblyName.IndexOf(",");

            if (idxShortNameEnd > 0)
            {
                assemblyName = assemblyName.Substring(0, idxShortNameEnd);
            }

            // Make sure if two assemblies have the same short name, that we differentiate
            // them using a counter (e.g. "Assembly#2")

            AssemblyReportInfo info;
            var originalAssemblyName = assemblyName;
            var counter = 1;

            while (ctx.AssemblyInfo.TryGetValue(assemblyName, out info))
            {
                if (Object.ReferenceEquals(info.Assembly, assembly))
                {
                    break;
                }
                assemblyName = string.Format(CultureInfo.InvariantCulture, "{0}#{1}", originalAssemblyName, ++counter);
            }

            builder.Append(assemblyName);

            // Read information about associated PDB file from assembly

            if (info == null)
            {
                ctx.AssemblyInfo.Add(assemblyName, info = new AssemblyReportInfo()
                {
                    Assembly = assembly, ShortName = originalAssemblyName
                });
#if !SILVERLIGHT
                info.DebugInfo = AssemblyDebugInfo.ReadAssemblyDebugInfo(assembly);
#endif
            }
        }
        /// <summary>
        /// Internal logic - adapted from Environment.GetStackTrace from .NET BCL.
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="ctx"></param>
        /// <param name="builder"></param>
        private static void GetStackTraceEx(Exception ex, ExceptionReportingContext ctx, ref StringBuilder builder)
        {
            var st    = new StackTrace(ex);
            var strAt = GetRuntimeResourceString("Word_At") ?? "at";

            bool isFirstLine = true;

            builder = builder ?? new StringBuilder(0xff);
            for (int i = 0; i < st.FrameCount; i++)
            {
                StackFrame frame  = st.GetFrame(i);
                var        method = frame.GetMethod();
                if (method != null)
                {
                    if (isFirstLine)
                    {
                        isFirstLine = false;
                    }
                    else
                    {
                        builder.Append(Environment.NewLine);
                    }
                    builder.AppendFormat(CultureInfo.InvariantCulture, "   {0} ", new object[] { strAt });
                    Type declaringType = method.DeclaringType;
                    if (declaringType != null)
                    {
                        // Output assembly short name, followed by method's metadata token,
                        // which is used to later lookup in PDB file

                        AppendAssemblyName(builder, declaringType.Assembly, ctx);
                        builder.Append("!");
                        builder.AppendFormat("0x{0:x8}", method.MetadataToken);
                        builder.Append("!");
                        builder.Append(declaringType.FullName.Replace('+', '.'));
                        builder.Append(".");
                    }
                    builder.Append(method.Name);
                    if ((method is MethodInfo) && ((MethodInfo)method).IsGenericMethod)
                    {
                        Type[] genericArguments = ((MethodInfo)method).GetGenericArguments();
                        builder.Append("[");
                        int  index    = 0;
                        bool firstArg = true;
                        while (index < genericArguments.Length)
                        {
                            if (!firstArg)
                            {
                                builder.Append(",");
                            }
                            else
                            {
                                firstArg = false;
                            }
                            builder.Append(genericArguments[index].Name);
                            index++;
                        }
                        builder.Append("]");
                    }
                    builder.Append("(");
                    ParameterInfo[] parameters = method.GetParameters();
                    bool            firstParam = true;
                    for (int j = 0; j < parameters.Length; j++)
                    {
                        if (!firstParam)
                        {
                            builder.Append(", ");
                        }
                        else
                        {
                            firstParam = false;
                        }
                        string name = "<UnknownType>";
                        if (parameters[j].ParameterType != null)
                        {
                            name = parameters[j].ParameterType.Name;
                        }
                        builder.Append(name + " " + parameters[j].Name);
                    }
                    builder.Append(")");
                    var ilOffset = frame.GetILOffset();
                    if (ilOffset != -1)
                    {
                        // Output the IL Offset, which we can later map to a filename+line,
                        // using information inside a matching PDB file

                        builder.AppendFormat(CultureInfo.InvariantCulture, " +0x{0:x}", ilOffset);
                    }
                    if (GetIsLastFrameFromForeignExceptionStackTrace(frame))
                    {
                        builder.Append(Environment.NewLine);
                        builder.Append(GetRuntimeResourceString("Exception_EndStackTraceFromPreviousThrow") ??
                                       "--- End of stack trace from previous location where exception was thrown ---");
                    }
                }
            }
        }