使用StackTrace堆栈跟踪记录详细日志(可获取行号)
上一篇我们提到使用.NET自带的TraceSource实现简单的日志,具体请看《轻松背后的N+疲惫——系统日志》,这一篇注意想讲的是日志的详细记录,包含请求开始到结束的过程中调用的方法链以及记录日志那一刻的类名,方法名,行号等。
其实也就是堆栈的跟踪了,微软为我们提供了一个对堆栈跟踪的对象StackTrace,具体信息请看 MSDN-StackTrace类.
下面是对TraceSourceLogger类的改进:
public sealed class TraceSourceLogger
:ILogger
{ TraceSource _source; public TraceSourceLogger()
{
_source = new TraceSource("Bulrush");
} public void Fatal(string message, params object[] args)
{
if (String.IsNullOrWhiteSpace(message))
return; string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
TraceStack(TraceEventType.Critical, messageToTrace);
} public void Fatal(string message, Exception exception, params object[] args)
{
if (String.IsNullOrWhiteSpace(message) || exception == null)
return; string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
TraceException(TraceEventType.Critical, exception, messageToTrace);
} public void Infomation(string message, params object[] args)
{
if (String.IsNullOrWhiteSpace(message))
return; string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
Trace(TraceEventType.Information, messageToTrace);
} public void Warning(string message, params object[] args)
{
if (String.IsNullOrWhiteSpace(message))
return; string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
Trace(TraceEventType.Warning, messageToTrace);
} public void Error(string message, params object[] args)
{
if (String.IsNullOrWhiteSpace(message))
return; string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
TraceStack(TraceEventType.Error, messageToTrace);
} public void Error(string message, Exception exception, params object[] args)
{
if (String.IsNullOrWhiteSpace(message) || exception == null)
return; string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
TraceException(TraceEventType.Error, exception, messageToTrace);
} void Trace(TraceEventType eventType, string message)
{
if (_source != null)
{
try
{
_source.TraceEvent(eventType, (int)eventType, message);
}
catch (SecurityException)
{
//这里处理写入是出现的安全问题,如文件没有写入权限。
}
}
} void TraceStack(TraceEventType eventType, string message)
{
string stackMessage = BuildStackTraceMessage();
string messageToTrace = message + Environment.NewLine + Environment.NewLine + stackMessage; Trace(eventType, messageToTrace);
} void TraceException(TraceEventType eventType, Exception ex, string message)
{
StringBuilder builder = new StringBuilder();
builder.AppendFormat("错误信息:{0}", message).AppendLine();
builder.AppendFormat("异常信息:{0}", ex.Message).AppendLine();
builder.AppendFormat("异常类型:{0}", ex.GetType().Name).AppendLine(); string stackMessage = BuildStackTraceMessage();
builder.Append(stackMessage); Trace(eventType, builder.ToString());
} string BuildStackTraceMessage()
{
StackTrace trace = new StackTrace(true);
return BuildStackTraceMessage(trace);
} string BuildStackTraceMessage(StackTrace stackTrace)
{
if (stackTrace != null)
{
var frameList = stackTrace.GetFrames();
var realFrameList = frameList.Where(i => i.GetMethod().DeclaringType != this.GetType() && i.GetFileLineNumber() > );
if (realFrameList.Any())
{
StringBuilder builder = new StringBuilder();
realFrameList = realFrameList.Reverse();
var lastFrame = realFrameList.Last();
builder.AppendFormat("源文件:{0}", lastFrame.GetFileName()).AppendLine();
builder.AppendFormat("行号:{0}", lastFrame.GetFileLineNumber()).AppendLine();
builder.AppendFormat("方法名:{0}", lastFrame.GetMethod().ToString()).AppendLine();
builder.AppendLine("堆栈跟踪:");
builder.AppendLine("================================================================="); MethodBase method;
foreach (var frame in realFrameList)
{
method = frame.GetMethod();
builder.AppendFormat("> {0} 类下的第{1}行 {2} 方法", method.DeclaringType.ToString(), frame.GetFileLineNumber(), method.ToString()).AppendLine();
}
builder.AppendLine("=================================================================");
return builder.ToString();
}
}
return "没有堆栈信息";
}
}
最主要的部分在于BuildStackTraceMessage这个方法
string BuildStackTraceMessage(StackTrace stackTrace)
{
if (stackTrace != null)
{
var frameList = stackTrace.GetFrames();
var realFrameList = frameList.Where(i => i.GetMethod().DeclaringType != this.GetType() && i.GetFileLineNumber() > );
if (realFrameList.Any())
{
StringBuilder builder = new StringBuilder();
realFrameList = realFrameList.Reverse();
var lastFrame = realFrameList.Last();
builder.AppendFormat("源文件:{0}", lastFrame.GetFileName()).AppendLine();
builder.AppendFormat("行号:{0}", lastFrame.GetFileLineNumber()).AppendLine();
builder.AppendFormat("方法名:{0}", lastFrame.GetMethod().ToString()).AppendLine();
builder.AppendLine("堆栈跟踪:");
builder.AppendLine("================================================================="); MethodBase method;
foreach (var frame in realFrameList)
{
method = frame.GetMethod();
builder.AppendFormat("> {0} 类下的第{1}行 {2} 方法", method.DeclaringType.ToString(), frame.GetFileLineNumber(), method.ToString()).AppendLine();
}
builder.AppendLine("=================================================================");
return builder.ToString();
}
}
return "没有堆栈信息";
}
下面这句代码是为了去除.NET FrameWork方法的堆栈跟踪和当前记录日志方法的跟踪,i.GetFileLineNumber() > 0行号大于0表示为获取当前项目方法的堆栈跟踪。
var realFrameList = frameList.Where(i => i.GetMethod().DeclaringType != this.GetType() && i.GetFileLineNumber() > );
下面我们做个测试:
[TestMethod]
public void TestTraceSourceLogger()
{
GetMyNumber();
} private int GetMyNumber()
{
ILoggerFactory factory = new TraceSourceLoggerFactory();
LoggerContext.SetCurrent(factory); try
{
var number = int.Parse("我要转成Int32类型");
return number;
}
catch (FormatException)
{
LoggerContext.CreateLog().Error("字符串无法转换为Int32类型");
}
return ;
}
日志的记录结果如下:

当然也可以将异常的直接扔到StackTrace中,获取详细的堆栈,但是这样无法获取从请求那一刻开始的方法链的跟踪。
还有一个是乎无法解决的问题,就是获取详细的代码行,估计微软也是为了确保程序的安全性吧,要是一不小心显示出关键代码被人拿走了就糟糕了,如果有哪位大牛知道怎么获取的话,麻烦指点指点!!
使用StackTrace堆栈跟踪记录详细日志(可获取行号)的更多相关文章
- StackTrace堆栈跟踪记录详细日志
使用StackTrace堆栈跟踪记录详细日志(可获取行号) 2014-04-25 22:30 by 螺丝钉想要螺丝帽, 350 阅读, 3 评论, 收藏, 编辑 上一篇我们提到使用.NET自带的Tra ...
- 【C# 异常处理】StackTrace 堆栈跟踪
作用 在使用.NET编写的代码在debug时很容易进行排查和定位问题,一旦项目上线并出现问题的话那么只能依靠系统日志来进行问题排查和定位,但当项目复杂时,即各种方法间相互调用将导致要获取具体的出错方法 ...
- go包之logrus显示日志文件与行号
前言: logrus是go中比较好的一个log模块.github上的很多开源项目都在使用这个模块, 我在写这个博文时, github上的logrus的stars数已经有8214了.最近在用这个模块时, ...
- 如何跟踪sharepoint详细日志
PS C:\Users\setup.moss> Set-SPLogLevel -TraceSeverity verboseexPS C:\Users\setup.moss> New-SPL ...
- log4j日志文件名与行号显示乱码? 问号? 参数问号? 日志问号?【转】【补】
log4j本来设置了要打印行号与文件名的,结果有的能打印出来,有的却是乱码,查了些文档之后才发现,原来打印问题是因为编绎时没有编绎进去调试信息,所以没办法打印,好像有的系统又会显示(Unknown S ...
- C#获取堆栈信息,输出文件名、行号、函数名、列号等
命名空间:System.Diagnostics 得到相关信息: StackTrace st = new StackTrace(new StackFrame(true));StackFrame sf = ...
- 异常 Exception 堆栈跟踪 异常捕获 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- ASP.NET Core使用Elasticsearch记录NLog日志
ASP.NET Core使用Elasticsearch记录NLog日志 1.新建一个 ASP.NET Core项目 2.安装Nuge包 运行:Install-Package NLog.Web.AspN ...
- Qt5 调试之详细日志文件输出(qInstallMessageHandler)
注明:以下方法仅适用于 Qt5 及以上版本 函数说明: QtMessageHandler qInstallMessageHandler(QtMessageHandler handler) 此函数在使 ...
随机推荐
- [c language] getopt
getopt(分析命令行参数) 相关函数表头文件 #include<unistd.h>定义函数 int getopt(int argc,char * ...
- ububru下 redmine安装教程
1.安装之前确认你已经安装好了mysql 2.连接mysql创建数据库 mysql -u root –p CREATE DATABASE redmine CHARACTER SET utf8; CRE ...
- CentOS6下编译安装Python2.7.6方法
关于在CentOS6下编译安装Python2.7.6的方法非常的多了,小编以前也介绍过相关的文章了,下面一聚教程小编再来为各位介绍一下吧,希望文章能帮助到各位. CentOS下面Python在升级 ...
- iOS开发多线程-多线程技术1
一.基本概念 1.什么是进程 进程就是指在系统中正在运行的一个应用程序 每个应用之间是相互独立的 每个进程都运行在其专有的并且受保护的内存空间内. 2.什么是线程 一个进程想要执行程序,就必须需要一个 ...
- I2C串行总线标准驱动程序(C51)-万能程序
#include "reg51.h" #include "intrins.h" unsigned char SystemError; sbit SCL= P1^ ...
- Keil C51 与 ARM 并存方法
第一:先安装keil C51 V4.01(如果先安装ARM的话还没有试过,应该也是可以的)到文件夹keil C51,运行破解补丁,选择C51版本,RealView MDK Professional进行 ...
- LeeCode-Remove Duplicates from Sorted List
Given a sorted linked list, delete all duplicates such that each element appear only once. For examp ...
- bash及其特性(笔记)
bash及其特性:shell: 外壳GUI:Gnome, KDE, XfceCLI: sh, csh, ksh, bash, tcsh, zsh root, student程序:进程 进程:在每个进程 ...
- MySql 取一天的开始时间和结束时间
-- 取一开的开始时间 SELECT str_to_date(DATE_FORMAT(NOW(),'%Y-%m-%d'),'%Y-%m-%d %H:%i:%s'); -- 取第二天的开始时间 sele ...
- 表格td标签在不添加多余标签的情况下实现文本内容单行显示,多余部分省略号表示的方法
#table { table-layout: fixed; } .content { white-space: nowrap; text-overflow: ellipsis; -o-text-ove ...