之前我转载了一篇“C#使用Log4Net记录日志”,但如果是错误日志,则没必要在每个方法里面捕获异常再记录日志,这时我们写一个全局的错误日志记录方法就行了,但这全局到底应该写在哪呢?
不同的项目写的地方是不一样的:WinForm、ASP.NET、MVC
WinForm:在Program.cs文件里
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
//处理未捕获的异常
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
//处理UI线程异常
Application.ThreadException += Application_ThreadException;
//处理非UI线程异常
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
#region 应用程序的主入口点
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
#endregion
}
//处理UI线程异常
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
Exception error = e.Exception as Exception;
//记录日志
}
//处理非UI线程异常
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception error = e.ExceptionObject as Exception;
//记录日志
}
ASP.NET:在Global.asax.cs文件里
void Application_Error(object sender, EventArgs e)
{
// 在出现未处理的错误时运行的代码
Exception error = Server.GetLastError().GetBaseException();
//记录日志
}
MVC:需要写一个继承HandleErrorAttribute的类,然后在文件FilterConfig.cs里添加过滤器
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
//默认注册全局的错误处理的过滤器。
filters.Add(new MyExceptionFilterAttribute());
}
}
/// <summary>
/// 自定义错误处理类
/// </summary>
public class MyExceptionFilterAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
base.OnException(filterContext);
//处理错误消息
Exception error = filterContext.Exception;
//记录日志
}
}
最后,我们就可以自己写一个方法,用Log4Net组件记录错误日志。
由于采用全局记录日志,一般我们只创建一个log4net.ILog实例,因此在记录日志过于频繁的时候,应该要考虑实例被其它线程占用时无法记录的问题。解决方法如下:
1、单线程中用锁。这种方法容易造成锁等待从而造成资源浪费。
2、在每个配置文件每个appender节点里面添加
<!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
3、把多线程转为单线程:采用数据库队列。先把日志记录进数据库队列,再每隔一段时间把队列的信息记录成文件,记录后清空队列