可替代log4j日志的c#简单日志类队列实现类代码分享
using system;
using system.collections.generic;
using system.globalization;
using system.io;
using system.linq;
using system.text;
using system.threading;
namespace logistrac
{
/// <summary>
/// 日志类
/// 队列 可年/月/周/日/大小分割
/// 调用方法:
/// log.instance.logdirectory=@"c:\"; 默认为程序运行目录
/// log.instance.filenameprefix="cxd";默认为log_
/// log.instance.currentmsgtype = msglevel.debug;默认为error
/// log.instance.logfilesplit = logfilesplit.daily; 日志拆分类型logfilesplit.sizely 大小
/// log.instance.maxfilesize = 5; 默认大小为2m,只有logfilesplit.sizely的时候配置有效
/// log.instance.logwrite("aa");
/// log.instance.logwrite("aa", msglevel.debug);
/// </summary>
public class log : idisposable
{
private static log _instance = null;
private static readonly object _synobject = new object();
/// <summary>
///单例
/// </summary>
public static log instance
{
get
{
if (null == _instance)
{
lock (_synobject)
{
if (null == _instance)
{
_instance = new log();
}
}
}
return _instance;
}
}
/// <summary>
/// 日志对象的缓存队列
/// </summary>
private static queue<msg> _msgs;
/// <summary>
/// 日志写入线程的控制标记 ture写中|false没有写
/// </summary>
private bool _state;
private string _logdirectory = appdomain.currentdomain.basedirectory;
/// <summary>
/// 日志文件存放目录
/// </summary>
public string logdirectory
{
get { return _logdirectory; }
set { _logdirectory = value; }
}
private logfilesplit _logfilesplit = logfilesplit.sizely;
/// <summary>
/// 日志拆分类型
/// </summary>
public logfilesplit logfilesplit
{
get { return _logfilesplit; }
set { _logfilesplit = value; }
}
private msglevel _currentloglevel = msglevel.error;
/// <summary>
/// 当前日志记录等级
/// </summary>
public msglevel currentmsgtype
{
get { return _currentloglevel; }
set { _currentloglevel = value; }
}
/// <summary>
/// 当前负责记录日志文件的名称
/// </summary>
private string _currentfilename="1.log";
private string _filenameprefix = "log_";
/// <summary>
/// 日志的前缀名称,默认为log_
/// </summary>
public string filenameprefix
{
get { return _filenameprefix; }
set { _filenameprefix = value; }
}
/// <summary>
/// 日志文件生命周期的时间标记
/// </summary>
private datetime _currentfiletimesign = new datetime();
private int _maxfilesize = 2;
/// <summary>
/// 单个日志文件默认大小(单位:兆)
/// </summary>
public int maxfilesize
{
get { return _maxfilesize; }
set { _maxfilesize = value; }
}
/// <summary>
/// 文件后缀号
/// </summary>
private int _filesymbol = 0;
/// <summary>
/// 当前文件大小(单位:b)
/// </summary>
private long _filesize = 0;
/// <summary>
/// 日志文件写入流对象
/// </summary>
private streamwriter _writer;
/// <summary>
/// 创建日志对象的新实例,根据指定的日志文件路径和指定的日志文件创建类型
/// </summary>
private log()
{
if (_msgs == null)
{
getcurrentfilename();
_state = true;
_msgs = new queue<msg>();
thread thread = new thread(work);
thread.start();
}
}
//日志文件写入线程执行的方法
private void work()
{
while (true)
{
//判断队列中是否存在待写入的日志
if (_msgs.count > 0)
{
msg msg = null;
lock (_msgs)
{
msg = _msgs.dequeue();
if (msg != null)
{
filewrite(msg);
}
}
}
else
{
//判断是否已经发出终止日志并关闭的消息
if (_state)
{
thread.sleep(1);
}
else
{
fileclose();
}
}
}
}
/// <summary>
/// 根据日志类型获取日志文件名,并同时创建文件到期的时间标记
/// 通过判断文件的到期时间标记将决定是否创建新文件。
/// </summary>
/// <returns></returns>
private
void getcurrentfilename()
{
datetime now = datetime.now;
string format = "";
switch (_logfilesplit)
{
case logfilesplit.daily:
_currentfiletimesign = new datetime(now.year, now.month, now.day);
_currentfiletimesign = _currentfiletimesign.adddays(1);
format = now.tostring("yyyymmdd'.log'");
break;
case logfilesplit.weekly:
_currentfiletimesign = new datetime(now.year, now.month, now.day);
_currentfiletimesign = _currentfiletimesign.adddays(7);
format = now.tostring("yyyymmdd'.log'");
break;
case logfilesplit.monthly:
_currentfiletimesign = new datetime(now.year, now.month, 1);
_currentfiletimesign = _currentfiletimesign.addmonths(1);
format = now.tostring("yyyymm'.log'");
break;
case logfilesplit.annually:
_currentfiletimesign = new datetime(now.year, 1, 1);
_currentfiletimesign = _currentfiletimesign.addyears(1);
format = now.tostring("yyyy'.log'");
break;
default:
_filesymbol++;
format = _filesymbol.tostring() + ".log";
break;
}
if (file.exists(path.combine(logdirectory, _currentfilename)))
{
_filesize = new fileinfo(path.combine(logdirectory, _currentfilename)).length;
}
else
{
_filesize = 0;
}
_currentfilename=_filenameprefix + format.trim();
}
//写入日志文本到文件的方法
private void filewrite(msg msg)
{
try
{
if (_writer == null)
{
fileopen();
}
if (_writer != null)
{
//判断文件到期标志,如果当前文件到期则关闭当前文件创建新的日志文件
if ((_logfilesplit != logfilesplit.sizely && datetime.now >= _currentfiletimesign)||
(_logfilesplit == logfilesplit.sizely && ((double)_filesize / 1048576) > _maxfilesize))
{
getcurrentfilename();
fileclose();
fileopen();
}
_writer.write(msg.datetime);
_writer.write('\t');
_writer.write(msg.type);
_writer.write('\t');
_writer.writeline(msg.text);
_filesize+=system.text.encoding.utf8.getbytes(msg.tostring()).length;
_writer.flush();
}
}
catch (exception e)
{
console.out.write(e);
}
}
//打开文件准备写入
private void fileopen()
{
_writer = new streamwriter(logdirectory + _currentfilename, true, encoding.utf8);
}
//关闭打开的日志文件
private void fileclose()
{
if (_writer != null)
{
_writer.flush();
_writer.close();
_writer.dispose();
_writer = null;
}
}
/// <summary>
/// 写入新日志,根据指定的日志对象msg
/// </summary>
/// <param name="msg">日志内容对象</param>
private void logwrite(msg msg)
{
if (msg.type < currentmsgtype)
return;
if (_msgs != null)
{
lock (_msgs)
{
_msgs.enqueue(msg);
}
}
}
/// <summary>
/// 写入新日志,根据指定的日志内容和信息类型,采用当前时间为日志时间写入新日志
/// </summary>
/// <param name="text">日志内容</param>
/// <param name="type">信息类型</param>
public void logwrite(string text, msglevel type)
{
logwrite(new msg(text, type));
}
/// <summary>
/// 写入新日志,根据指定的日志内容
/// </summary>
/// <param name="text">日志内容</param>
public void logwrite(string text)
{
logwrite(text, msglevel.debug);
}
/// <summary>
/// 写入新日志,根据指定的日志时间、日志内容和信息类型写入新日志
/// </summary>
/// <param name="dt">日志时间</param>
/// <param name="text">日志内容</param>
/// <param name="type">信息类型</param>
public void logwrite(datetime dt, string text, msglevel type)
{
logwrite(new msg(dt, text, type));
}
/// <summary>
/// 写入新日志,根据指定的异常类和信息类型写入新日志
/// </summary>
/// <param name="e">异常对象</param>
/// <param name="type">信息类型</param>
public void logwrite(exception e)
{
logwrite(new msg(e.message, msglevel.error));
}
/// <summary>
/// 销毁日志对象
/// </summary>
public void dispose()
{
_state = false;
}
}
/// <summary>
/// 一个日志记录的对象
/// </summary>
public class msg
{
/// <summary>
/// 创建新的日志记录实例;日志记录的内容为空,消息类型为msgtype.unknown,日志时间为当前时间
/// </summary>
public msg()
: this("", msglevel.debug)
{
}
/// <summary>
/// 创建新的日志记录实例;日志事件为当前时间
/// </summary>
/// <param name="t">日志记录的文本内容</param>
/// <param name="p">日志记录的消息类型</param>
public msg(string t, msglevel p)
: this(datetime.now, t, p)
{
}
/// <summary>
/// 创建新的日志记录实例;
/// </summary>
/// <param name="dt">日志记录的时间</param>
/// <param name="t">日志记录的文本内容</param>
/// <param name="p">日志记录的消息类型</param>
public msg(datetime dt, string t, msglevel p)
{
datetime = dt;
type = p;
text = t;
}
/// <summary>
/// 日志记录的时间
/// </summary>
public datetime datetime { get; set; }
/// <summary>
///日志记录的内容
/// </summary>
public string text { get; set; }
/// <summary>
/// 日志等级
/// </summary>
public msglevel type { get; set; }
public new string tostring()
{
return datetime.tostring(cultureinfo.invariantculture) + "\t" + text + "\n";
}
}
/// <summary>
/// 日志文件拆分的枚举
/// </summary>
/// <remarks>日志类型枚举指示日志文件创建的方式,如果日志比较多可考虑每天创建一个日志文件
/// 如果日志量比较小可考虑每周、每月或每年创建一个日志文件</remarks>
public enum logfilesplit
{
/// <summary>
/// 此枚举指示每天创建一个新的日志文件
/// </summary>
daily,
/// <summary>
/// 此枚举指示每周创建一个新的日志文件
/// </summary>
weekly,
/// <summary>
/// 此枚举指示每月创建一个新的日志文件
/// </summary>
monthly,
/// <summary>
/// 此枚举指示每年创建一个新的日志文件
/// </summary>
annually,
/// <summary>
/// 日志文件大小超过指定的创建一个新的日志文件,maxfilesize指定大小
/// </summary>
sizely
}
/// <summary>
/// 日志等级类型 debug=0 infor warn error
/// </summary>
public enum msglevel
{
/// <summary>
/// 调试信息
/// </summary>
debug = 0,
/// <summary>
/// 指示普通信息类型的日志记录
/// </summary>
infor,
/// <summary>
/// 指示警告信息类型的日志记录
/// </summary>
warn,
/// <summary>
/// 指示错误信息类型的日志记录
/// </summary>
error
}
}
上一篇: C#自动给文章关键字加链接实现代码
下一篇: c# yield提高代码性能和可读性