最近项目上线后遇到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. SeaJS入门教程系列之SeaJS介绍(一)

    前言SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制.与jQuery等JavaScript框架不同,SeaJS不会扩展封装 ...

  2. poj3349 散列表(hash)

    就是散列表的应用,把每片哈希值相同的雪花排到一条链上去即可,每片雪花x的哈希值 hash(x)=sum(x的六角)+mul(x的六角),会爆int #include<iostream> # ...

  3. bind函数详解(转)

    var name = "The Window"; var object = { name: "My Object", getNameFunc: function ...

  4. ERP采购申请管理(三十九)

    获取当前表单在流程中的状态: /// <summary> /// 获取当前表单在流程表中的状态 /// </summary> /// <param name=" ...

  5. oneinstack如何安装ssl证书和配置Let's Encrypt免费SSL证书教程汇总(转)

    OneinStack包含以下组合:lnmp(Linux + Nginx+ MySQL+ PHP) LNMP安装SSL安全证书 部署HTTPS:https://www.gworg.com/ssl/309 ...

  6. centos7 编译安装php 5.6

    https://www.cnblogs.com/37yan/p/6879404.html

  7. jenkins X实践系列(2) —— 基于jx的DevOps实践

    jx是云原生CICD,devops的一个最佳实践之一,目前在快速的发展成熟中.最近调研了JX,这里为第2篇,使用已经安装好的jx来实践CICD,旨在让大家了解基于jx的DevOps是如何运转的,感兴趣 ...

  8. Codeforces 815C Karen and Supermarket 树形dp

    Karen and Supermarket 感觉就是很普通的树形dp. dp[ i ][ 0 ][ u ]表示在 i 这棵子树中选择 u 个且 i 不用优惠券的最小花费. dp[ i ][ 1 ][ ...

  9. FastAdmin 如何隐藏操作栏中的“删除”按钮“?

    刚刚在群里看到有人询问如何隐藏(删除)操作栏中的”删除”按钮,如下这个. 我也不会,在论坛上也没找到,但有找到一篇关于根据条件怎么隐藏按钮的问题,Karson 老大有提供的解决方法.我就照样画葫芦写了 ...

  10. 洛谷 P4779 【dijkstra】+(堆优化)+(链式前向星) (模板题)

    <题目链接> 题目描述 给定一个 N 个点, M 条有向边的带非负权图,请你计算从 S 出发,到每个点的距离. 数据保证你能从 S 出发到任意点. 输入格式: 第一行为三个正整数 N,M, ...