一说到写日志,大家可能推荐一堆的开源日志框架,如:Log4Net、NLog,这些日志框架确实也不错,比较强大也比较灵活,但也正因为又强大又灵活,导致我们使用他们时需要引用一些DLL,同时还要学习各种用法及配置文件,这对于有些小工具、小程序、小网站来说,有点“杀鸡焉俺用牛刀”的感觉,而且如果对这些日志框架不了解,可能输出来的日志性能或效果未毕是与自己所想的,鉴于这几个原因,我自己重复造轮子,编写了一个轻量级的异步写日志的实用工具类(LogAsyncWriter),这个类还是比较简单的,实现思路也很简单,就是把消息日志先入内存队列,然后由异步监听线程从队列中取出日志并批量输出到本地文件中,同时参照各大日志框架,对单个文件过大采取分割生成多个日志文件。
经测试发现性能非常不错,先看示例使用代码:(采取并发多线程同时写入1000000万条日志)
Task.Factory.StartNew(() =>
{
DateTime startTime = DateTime.Now;
int logCount = 1000000;
Parallel.For(1, logCount, (i) =>
{
if (i % 2 == 0)
{
LogAsyncWriter.Default.Error("测试并发写错误日志-" + i.ToString(), "TestClass.TestLog", i.ToString());
}
else
{
LogAsyncWriter.Default.Info("测试并发写普通日志-" + i.ToString(), "TestClass.TestLog", i.ToString());
}
});
this.Invoke(new MethodInvoker(() =>
{
MessageBox.Show(DateTime.Now.ToString() + "," + logCount + "条日志写完了!,耗时:" + (DateTime.Now - startTime).TotalMilliseconds + "ms");
}));
});
MessageBox.Show(DateTime.Now.ToString() + ",同步方法已结束");
}
执行效果如下图示:

因为采用异步,故方法先走到结尾,输出了同步的MsgBox,随后弹出的是100W日志输出到文件后的耗时MsgBox,从截图可以看出,不足1S(当然这里的1S不是真实的输出到本地方件,而是把所有的日志推到了Queue中而矣,但不影响不阻塞业务处理),而本地日志文件的大小达到了263MB(设置最大值的MaxSizeBackup,使其不滚动备份),由此看性能是不错的;

因为是异步延迟输出到本地日志文件,故大家在代码中任意地方,比如:循环中都可以使用它,不用担心会影响你的正常的业务逻辑的执行效率;
如果采取滚动备份(设置MaxSizeBackup为一个合理值,默认为10MB),则生成的日志文件形式如下:(超过最大容量则生成同名文件+2位序号),超过一个月则会自动清除

打开日志文件会看到所有的日志内容:

有些人可能要问,输出格式是固定的吗?能否自定义布局,告诉你是可以的,我考虑到每个人对日志输出的格式都有严格的要求,故可以通过设置:LineLayoutRenderFormat属性来设置每条日志输出的格式内容
好了,介绍了使用功能及效果、性能,下面贴出源代码:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
namespace Zuowj.Common
{
/// <summary&g'7fffffV&2fW'&G&r7G&6R7G&FWF&6R7G7G"7GТffffffffТffffffffffff6fTrW'&fVr6RFWF&6R##"#2ТfffffffffТffffffffV&2fW'&6WF7G&6R7G7G"7GТffffffffТffffffffffff6fTrW'&fVW76vR6RW6G&6R##"#2ТfffffffffТfffffffft7&FW"ТffffffffТffffffffffff7G2ТfffffffffТffffУFcУ>zx+УYNzxz^[k9^XZ^XxУsiz^[hhkhh#ЦSiz^[yIK^iz^[yKY:KK{K~yIZKk9^Y#ЦWF&6Siz^[h8^njKhniz^[X[~KyNK#ЦbFW##"#3ZH~yJiz^[jXhZ^h8^Xk^yX[>KNZh.^X~ ~i{nz#ЧbWfViz^[hK[I{~Xn[yJyNX>{>fiz^[h&Yiz^[h&I[hУj[jhx^[ikk9^x~yJY{Y
z^[h~>iiz^[hiz^[i{n{N{NNh^n)KhxCjiz^[z>Xk>KniyNYXiiz^[k9^
hXiXNZYZXNh8^Xk^Уx~yJXK[>zKjKyJi{nKY
.jyY
xiKn[NyJX[>z{nX yzXyY
X~XyN{yYzУn[K{~Z^h;>hnh;>iK
NhHnKzk>KZHNXhX{.
.У^K[i{XiKKxN[jXiiz^[ZJ[z^X[~{t7&FW.NXh^ZiNZIX[>K{Xi[jXiiz^[X[~{yNXNiik:zKX[nZX[>ih~z |