上一篇我们提到使用.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中,获取详细的堆栈,但是这样无法获取从请求那一刻开始的方法链的跟踪。
还有一个是乎无法解决的问题,就是获取详细的代码行,估计微软也是为了确保程序的安全性吧,要是一不小心显示出关键代码被人拿走了就糟糕了,如果有哪位大牛知道怎么获取的话,麻烦指点指点!!