最近项目上线后遇到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. border-radius在Android下的几个BUG

    图片的外层元素添加border属性, border-radius属性设置成最大 .img{width: 110px; height: 110px; border: 5px solid #ccc; bo ...

  2. 【ES】学习6-多字段搜索1

    本系列的笔记都来自:https://elasticsearch.cn/book/elasticsearch_definitive_guide_2.x/multi-field-search.html 下 ...

  3. poj2279 线性dp

    #include<iostream> #include<cstdio> #include<cstring> #define ll long long using n ...

  4. docker 运行Django项目

    一.概述 已经写好了一个Django项目,需要将这个项目用docker封装一个镜像,使用k8s发布! 在封装并运行的过程中,发现了很多问题,这里会一一介绍! 二.时区问题 采用的是镜像是 ubuntu ...

  5. Java_myeclipse添加DTD约束(框架xml只能提示功能)

    以struts2中的xml为例 struts-2.3.4-all\struts-2.3.4\src\core\src\main\resources

  6. 【C++ Primer | 19】运行类型识别

    运行类型识别 一.使用RTTI dynamic_cast运算符的调用形式如下所示: dynamic_cast<type*>(e) //e是指针 dynamic_cast<type&a ...

  7. zjoi2010基站选址

    线段树优化dp 题解: 首先dp挺简单的 f[i,k]=f[j,k-1]+solve(i+1,j-1) 然后这个是可以n^2*k搞得 然后考虑这个solve(i+1,j-1) 当i延伸了一个位置的时候 ...

  8. 【BZOJ】3123: [Sdoi2013]森林

    题解 ------------------ 我莫不是一个智障吧 我把testdata的编号 当成数据组数读进来 我简直有毒 以为哪里写错了自闭了好久 实际上这题很简单,只要愉悦地开个启发式合并,然后每 ...

  9. python全栈开发day49-jquery的位置信息、事件流、事件对象,事件委托,事件绑定和解绑

    一.昨日内容回顾    1. jQuery的属性操作 1) html属性操作:attr 2) DOM属性操作:prop 3) 类样式操作:addClass.removeClass.toggleClas ...

  10. 导出oracle序列

    set serveroutput on;spool c:\sequence_code.txt; declare  v_sequence varchar2(4000);  v_nextval numbe ...