最近项目上线后遇到exception没有堆栈信息。所以跟踪一下 源码,其中主要的code如下:

        // Returns the stack trace as a string.  If no stack trace is
// available, null is returned.
public virtual String StackTrace
{
#if FEATURE_CORECLR
[System.Security.SecuritySafeCritical]
#endif
get
{
// By default attempt to include file and line number info
return GetStackTrace(true);
}
} // Computes and returns the stack trace as a string
// Attempts to get source file and line number information if needFileInfo
// is true. Note that this requires FileIOPermission(PathDiscovery), and so
// will usually fail in CoreCLR. To avoid the demand and resulting
// SecurityException we can explicitly not even try to get fileinfo.
#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
#endif
private string GetStackTrace(bool needFileInfo)
{
string stackTraceString = _stackTraceString;
string remoteStackTraceString = _remoteStackTraceString; #if !FEATURE_CORECLR
if (!needFileInfo)
{
// Filter out file names/paths and line numbers from _stackTraceString and _remoteStackTraceString.
// This is used only when generating stack trace for Watson where the strings must be PII-free.
stackTraceString = StripFileInfo(stackTraceString, false);
remoteStackTraceString = StripFileInfo(remoteStackTraceString, true);
}
#endif // !FEATURE_CORECLR // if no stack trace, try to get one
if (stackTraceString != null)
{
return remoteStackTraceString + stackTraceString;
}
if (_stackTrace == null)
{
return remoteStackTraceString;
} // Obtain the stack trace string. Note that since Environment.GetStackTrace
// will add the path to the source file if the PDB is present and a demand
// for FileIOPermission(PathDiscovery) succeeds, we need to make sure we
// don't store the stack trace string in the _stackTraceString member variable.
String tempStackTraceString = Environment.GetStackTrace(this, needFileInfo);
return remoteStackTraceString + tempStackTraceString;
} #if FEATURE_CORECLR
[System.Security.SecuritySafeCritical]
#endif
public override String ToString()
{
return ToString(true, true);
} #if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
#endif
private String ToString(bool needFileLineInfo, bool needMessage) {
String message = (needMessage ? Message : null);
String s; if (message == null || message.Length <= ) {
s = GetClassName();
}
else {
s = GetClassName() + ": " + message;
} if (_innerException!=null) {
s = s + " ---> " + _innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine +
" " + Environment.GetResourceString("Exception_EndOfInnerExceptionStack"); } string stackTrace = GetStackTrace(needFileLineInfo);
if (stackTrace != null)
{
s += Environment.NewLine + stackTrace;
} return s;
}

Exception的StackTrace属性只返回当前对象的站信息,toString方法首先需要获取当前的Message,然后获取内部exception的tostring方法,最后获取 GetStackTrace方法的返回值,该方法主要内容来源于 Environment.GetStackTrace方法,其实现code如下:

        internal static String GetStackTrace(Exception e, bool needFileInfo)
{
// Note: Setting needFileInfo to true will start up COM and set our
// apartment state. Try to not call this when passing "true"
// before the EE's ExecuteMainMethod has had a chance to set up the
// apartment state. --
StackTrace st;
if (e == null)
st = new StackTrace(needFileInfo);
else
st = new StackTrace(e, needFileInfo); // Do no include a trailing newline for backwards compatibility
return st.ToString( System.Diagnostics.StackTrace.TraceFormat.Normal );
}

调用的是StackTrace的tostring方法,其实现如下:

  internal String ToString(TraceFormat traceFormat)
{
bool displayFilenames = true; // we'll try, but demand may fail
String word_At = "at";
String inFileLineNum = "in {0}:line {1}"; if(traceFormat != TraceFormat.NoResourceLookup)
{
word_At = Environment.GetResourceString("Word_At");
inFileLineNum = Environment.GetResourceString("StackTrace_InFileLineNumber");
} bool fFirstFrame = true;
StringBuilder sb = new StringBuilder();
for (int iFrameIndex = ; iFrameIndex < m_iNumOfFrames; iFrameIndex++)
{
StackFrame sf = GetFrame(iFrameIndex);
MethodBase mb = sf.GetMethod();
if (mb != null)
{
// We want a newline at the end of every line except for the last
if (fFirstFrame)
fFirstFrame = false;
else
sb.Append(Environment.NewLine); sb.AppendFormat(CultureInfo.InvariantCulture, " {0} ", word_At); Type t = mb.DeclaringType;
// if there is a type (non global method) print it
if (t != null)
{
sb.Append(t.FullName.Replace('+', '.'));
sb.Append(".");
}
sb.Append(mb.Name); // deal with the generic portion of the method
if (mb is MethodInfo && ((MethodInfo)mb).IsGenericMethod)
{
Type[] typars = ((MethodInfo)mb).GetGenericArguments();
sb.Append("[");
int k=;
bool fFirstTyParam = true;
while (k < typars.Length)
{
if (fFirstTyParam == false)
sb.Append(",");
else
fFirstTyParam = false; sb.Append(typars[k].Name);
k++;
}
sb.Append("]");
} // arguments printing
sb.Append("(");
ParameterInfo[] pi = mb.GetParameters();
bool fFirstParam = true;
for (int j = ; j < pi.Length; j++)
{
if (fFirstParam == false)
sb.Append(", ");
else
fFirstParam = false; String typeName = "<UnknownType>";
if (pi[j].ParameterType != null)
typeName = pi[j].ParameterType.Name;
sb.Append(typeName + " " + pi[j].Name);
}
sb.Append(")"); // source location printing
if (displayFilenames && (sf.GetILOffset() != -))
{
// If we don't have a PDB or PDB-reading is disabled for the module,
// then the file name will be null.
String fileName = null; // Getting the filename from a StackFrame is a privileged operation - we won't want
// to disclose full path names to arbitrarily untrusted code. Rather than just omit
// this we could probably trim to just the filename so it's still mostly usefull.
try
{
fileName = sf.GetFileName();
}
#if FEATURE_CAS_POLICY
catch (NotSupportedException)
{
// Having a deprecated stack modifier on the callstack (such as Deny) will cause
// a NotSupportedException to be thrown. Since we don't know if the app can
// access the file names, we'll conservatively hide them.
displayFilenames = false;
}
#endif // FEATURE_CAS_POLICY
catch (SecurityException)
{
// If the demand for displaying filenames fails, then it won't
// succeed later in the loop. Avoid repeated exceptions by not trying again.
displayFilenames = false;
} if (fileName != null)
{
// tack on " in c:\tmp\MyFile.cs:line 5"
sb.Append(' ');
sb.AppendFormat(CultureInfo.InvariantCulture, inFileLineNum, fileName, sf.GetFileLineNumber());
}
} #if FEATURE_EXCEPTIONDISPATCHINFO
if (sf.GetIsLastFrameFromForeignExceptionStackTrace())
{
sb.Append(Environment.NewLine);
sb.Append(Environment.GetResourceString("Exception_EndStackTraceFromPreviousThrow"));
}
#endif // FEATURE_EXCEPTIONDISPATCHINFO
}
} if(traceFormat == TraceFormat.TrailingNewLine)
sb.Append(Environment.NewLine); return sb.ToString();
}

这个方法最主要的还是   StackFrame sf = GetFrame(iFrameIndex);   它返回跟踪栈的信息。跟踪栈的信息主要来源于StackTrace的构造函数

  public StackTrace(Exception e, bool fNeedFileInfo)
{
if (e == null)
throw new ArgumentNullException("e");
Contract.EndContractBlock(); m_iNumOfFrames = ;
m_iMethodsToSkip = ;
CaptureStackTrace(METHODS_TO_SKIP, fNeedFileInfo, null, e);
}

核心实现CaptureStackTrace code如下:

  private void CaptureStackTrace(int iSkip, bool fNeedFileInfo, Thread targetThread,
Exception e)
{
m_iMethodsToSkip += iSkip; StackFrameHelper StackF = new StackFrameHelper(fNeedFileInfo, targetThread); GetStackFramesInternal(StackF, , e); m_iNumOfFrames = StackF.GetNumberOfFrames(); if (m_iMethodsToSkip > m_iNumOfFrames)
m_iMethodsToSkip = m_iNumOfFrames; if (m_iNumOfFrames != )
{
frames = new StackFrame[m_iNumOfFrames]; for (int i = ; i < m_iNumOfFrames; i++)
{
bool fDummy1 = true;
bool fDummy2 = true;
StackFrame sfTemp = new StackFrame(fDummy1, fDummy2); sfTemp.SetMethodBase(StackF.GetMethodBase(i));
sfTemp.SetOffset(StackF.GetOffset(i));
sfTemp.SetILOffset(StackF.GetILOffset(i)); #if FEATURE_EXCEPTIONDISPATCHINFO
sfTemp.SetIsLastFrameFromForeignExceptionStackTrace(StackF.IsLastFrameFromForeignExceptionStackTrace(i));
#endif // FEATURE_EXCEPTIONDISPATCHINFO if (fNeedFileInfo)
{
sfTemp.SetFileName(StackF.GetFilename (i));
sfTemp.SetLineNumber(StackF.GetLineNumber(i));
sfTemp.SetColumnNumber(StackF.GetColumnNumber(i));
} frames[i] = sfTemp;
} // CalculateFramesToSkip skips all frames in the System.Diagnostics namespace,
// but this is not desired if building a stack trace from an exception.
if (e == null)
m_iMethodsToSkip += CalculateFramesToSkip(StackF, m_iNumOfFrames); m_iNumOfFrames -= m_iMethodsToSkip;
if (m_iNumOfFrames < )
{
m_iNumOfFrames = ;
}
} // In case this is the same object being re-used, set frames to null
else
frames = null;
}

顺便提一下,VS在release模式下是可以调试的,也可以获取堆栈信息。

Exception的ToString()方法究竟返回的是什么的更多相关文章

  1. Object类的toString方法

          Object类是所有Java类的祖先.每个类都使用 Object 作为超类.所有对象(包括数组)都实现这个类的方法.在不明确给出超类的情况下,Java会自动把Object作为要定义类的超类 ...

  2. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  3. JS之toString方法

    1.JS中几乎每个值都有toString方法,null和undefined除外 2.对于字符串形式的值也可以使用toString()方法,返回该字符串的一个副本 3.toString(radix)方法 ...

  4. Java中的toString()方法

    Java中的toString()方法 目录 Java中的toString()方法 1.    对象的toString方法 2.    基本类型的toString方法 3.    数组的toString ...

  5. [改善Java代码]推荐覆写toString方法

    建议49: 推荐覆写toString方法 为什么要覆写toString方法,这个问题很简单,因为Java提供的默认toString方法不友好,打印出来看不懂,不覆写不行,看这样一段代码: public ...

  6. C#...何时需要重写ToString()方法?

    一般类型,都是继承自System.Object类,默认情况下,object类的ToString方法会返回当前类的类型的字符串表达形式.但也有例外!! DateTime,它就重写ToString方法,D ...

  7. 打印对象和toString方法

    JAVA对象 java对象是都是Object类的实例,都可直接调用该类中定义的方法,这些方法提供了处理java对象的通用方法. > > 6.2.1打印对象和toString方法    先看 ...

  8. Java之面向对象例子(三) 多态,重写,重载,equals()方法和toString()方法的重写

    重写(继承关系) 子类得成员方法和父类的成员方法,方法名,参数类型,参数个数完全相同,这就是子类的方法重写了父类的方法. 重载 在一个类里有两个方法,方法名是完全一样的,参数类型或参数个数不同. 例子 ...

  9. Effective Java 第三版——12. 始终重写 toString 方法

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

随机推荐

  1. python----线程进程协程

    python线程: import threading import time def show(arg): time.sleep() print('thread' + str(arg)) ): t = ...

  2. python 全栈开发,Day31(re模块)

    回顾昨天的内容 异常处理 try except 一定要在except之后写一些提示或者处理的内容 try: '''可能会出现异常的代码''' except ValueError: '''打印一些提示或 ...

  3. mysql的基本演示

    数据库需要配置 cmd打开doc窗口 net start mysql:启动数据库 net stop mysql :停止数据库 表的定义:列  行  主键

  4. 计算机编码--c语言中输出float的十六进制和二进制编码

    c语言中没有可以直接打印float类型数据的二进制或者十六进制编码的输出格式, 因此,需要单独给个函数,如下: unsigned int float2hexRepr(float* a){ unsign ...

  5. Array,ArrayList,泛型List比较

    在C#中数组Array,ArrayList,泛型List都能够存储一组对象,但是在开发中根本不知道用哪个性能最高,下面我们慢慢分析分析. 一.数组Array 数组是一个存储相同类型元素的固定大小的顺序 ...

  6. python3 使用SimpleHTTPServer搭建web服务器

    刚刚萌发了一个念头,要用python来做个web服务器,秀出自己的网页.于是,开始了我的搭建web服务器之旅. 首先,如果不想使用Apache.IIS,那就需要一个HTTP服务,而python自带了一 ...

  7. 如何批量的在django中对url进行用户登陆限制

    参考URL: https://blog.csdn.net/hanshengzhao/article/details/79540306?utm_source=blogxgwz0 1,首先定义一个内部有装 ...

  8. jQuery插件实践之轮播练习(二)

    所有文章搬运自我的个人主页:sheilasun.me 上一篇中学习了jQuery插件的写法,这篇该着手实现啦.首先明确一下轮播要具备哪些功能: 可以点击"向后"按钮向后翻页 可以点 ...

  9. python 字符串组成MySql 命令时,字符串含有单引号或者双引号导致出错解决办法

    引用自:https://blog.csdn.net/zhaoya_huangqing/article/details/48036839 一.在组成SQL语句并发送命令时完全按照Python中的样式去传 ...

  10. Storm通信机制(了解)

    Worker间的通信:经常需要通过网络跨节点进行,Storm使用ZeroMQ或Netty(0.9以后默认使用)作为进程间通信的消息框架. Worker进程内部通信:不同worker的thread通信使 ...