错误处理机制。
面对多个web服务器,多线程处理,我们想把错误信息记录到一个txt文档中。
但是把错误信息写到内存是很快。写到硬盘上就有一堆的问题。比如说读写慢、并发问题。
今天我们就利用这个实现错误处理 此文以MVC为例
1、首先要在 golable 文件的 protected void Application_Start()
注册一个错误处理机制。
MVC中自带一个 过滤器
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
这里面 我们看到这个过滤器
2、其实就是在 app_Start文件夹下面 的 FilterConfig.cs 文件
3、 打开FilterConfig.cs文件
就写了一个注册事件。我们看得到 这个是对错误处理机制
(当然 ,你们看到的是 HandleErrorAttribute 这个类)
4、所以你们可能觉得奇怪,我们来查看MyExceptionAttribut的定义看一下
继承了HandleErrorAttribute
这里我把这个类的代码贴一下
public class MyExceptionAttribute : HandleErrorAttribute
{
// private static object obj = new object();
public static ConcurrentQueue<Exception> ExceptionQueue = new ConcurrentQueue<Exception>();//定义队列
/// <summary>
/// 在该方法中捕获异常。
/// </summary>
/// <param name="filterContext"></param>
public override void OnException(ExceptionContext filterContext)
{
base.OnException(filterContext);
Exception ex = filterContext.Exception;//捕获异常信息。
//将异常信息写到队列中。
ExceptionQueue.Enqueue(ex);
//跳转到错误页面.
filterContext.HttpContext.Response.Redirect("/Error.html");
}
}
主要是定义一个静态 队列 ConcurrentQueue
(当然你也可以用 Queue。但是微软说 这个ConcurrentQueue 比 Queue 安全。好像是线程安全的,一堆堆的理论,说白了就是用ConcurrentQueue 更安全)
这样所有的错误就都在这个队列里面了。(就是内存)
这样总不行吧。内存 断电就没有了的啊。
所以我们要想把资料存到 硬盘中。
5、现在又要在
golable 文件的 protected void Application_Start()
中注册一个消费线程(这句话后面会解释,看不懂就继续)就是在 protected void Application_Start()中加入这些代码,最好放最前面。
内容就是线程池开启一个线程 从刚刚定义的 MyExceptionAttribute的 ExceptionQueue队列里面取出项来。
将错误信息最加到文件后面。如果队列为空,就线程停留3秒。
string filePath = Server.MapPath("/Log/");
ThreadPool.QueueUserWorkItem((a) =>
{
while (true)//注意:线程不能结束。后面写到队列中的数据没法处理。
{
// 这里可以加一条 if (MyExceptionAttribute.ExceptionQueue.Count() > 0)
//{ 发送邮件到管理员}
if (MyExceptionAttribute.ExceptionQueue.Count() > 0)
{
// Exception ex= MyExceptionAttribute.ExceptionQueue.Dequeue();//从队列中取出数据.
Exception ex = null;
bool isResult = MyExceptionAttribute.ExceptionQueue.TryDequeue(out ex);
if (ex != null && isResult)
{
string fullPath = filePath + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
File.AppendAllText(fullPath, ex.ToString());
// ILog logger = LogManager.GetLogger("errorMsg");
// logger.Error(ex.ToString());
}
else
{
Thread.Sleep(3000);
}
}
else
{
Thread.Sleep(3000);//避免造成CPU的空转。
}
}
}, filePath);
6、总结。
这个就是一个生产者消费者的模式。
生产者就是 产生错误的源头。 消费者就是注册保存日志的方法。
中间有一个仓库就是 那个静态错误队列。
可以看到 系统产生的错误临时存放于内存中。然后一个新的线程 去读写静态错误队列。
正常情况 需要在错误队列里面加一个错误队列数字大于1000条的时候 发警告到邮箱的功能。那样感觉有点问题复杂化了,毕竟这里只是讲错误处理。
7、log4net 我前面讲过的一个开源框架 记录错误很好。
这里提供一个连接 log4net配置方法你可以把那个一起并到这里。那么就会有
把protected void Application_Start()中添加 的代码
改成。注意是改成:
log4net.Config.XmlConfigurator.Configure();
//开始一个线程,查看异常队列
string filePath = Server.MapPath("/Log/");
ThreadPool.QueueUserWorkItem((a) =>
{
while (true)//注意:线程不能结束。后面写到队列中的数据没法处理。
{
if (MyExceptionAttribute.ExceptionQueue.Count() > 0)
{
// Exception ex= MyExceptionAttribute.ExceptionQueue.Dequeue();//从队列中取出数据.
Exception ex = null;
bool isResult = MyExceptionAttribute.ExceptionQueue.TryDequeue(out ex);
if (ex != null && isResult)
{
string fullPath = filePath + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
//File.AppendAllText(fullPath, ex.ToString());
ILog logger = LogManager.GetLogger("errorMsg");
logger.Error(ex.ToString());
}
else
{
Thread.Sleep(3000);
}
}
else
{
Thread.Sleep(3000);//避免造成CPU的空转。
}
}
}, filePath);
这样就会按照你的要求把错误日志记录到
app_data文件夹下面。(前提是你有未处理的错误 。呵呵)
看到下图就成功了
题外话(
没有就自己创一个 var s=3/0;
这样就可以了。
)