改进的日志记录类
Posted 淺笑嫣然
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了改进的日志记录类相关的知识,希望对你有一定的参考价值。
相对之前发的日志记录来说,此类将程序记录处理与写磁盘操作分离,用户代码部分,将日志放到队列,并通知线程将日志写到文件:
1.公共类:
using System;
using System.IO;
using System.Collections.Generic;
using static System.Console;
using System.Text;
using System.Diagnostics;
namespace LogWriter
{
/// <summary>
/// 日志类型
/// </summary>
public enum LogType
{
Error,
Info,
Waring,
Success,
Failure
}
/// <summary>
/// 日志参数信息
/// </summary>
internal struct LogInfo
{
internal string FileName { get; set; }
internal string MethodName { get; set; }
internal int Line { get; set; }
internal int Column { get; set; }
internal string LogType { get; set; }
}
/// <summary>
/// 公共日之类
/// </summary>
internal class LogCommon
{
static System.Threading.ReaderWriterLockSlim Slim = new System.Threading.ReaderWriterLockSlim(System.Threading.LockRecursionPolicy.SupportsRecursion);
/// <summary>
/// 获取日志参数信息
/// </summary>
/// <param name="type">类型</param>
/// <returns></returns>
internal static LogInfo GetLog(LogType type)
{
StackTrace st = new StackTrace(2, true);
StackFrame sf = st.GetFrame(0);
LogInfo li = new LogInfo()
{
FileName = sf.GetFileName(),
MethodName = sf.GetMethod().Name,
Line = sf.GetFileLineNumber(),
Column = sf.GetFileColumnNumber(),
};
string logType = "-Error";
switch (type)
{
case LogType.Error:
logType = "-Error";
break;
case LogType.Info:
logType = "-Info";
break;
case LogType.Waring:
logType = "-Waring";
break;
case LogType.Success:
logType = "-Success";
break;
case LogType.Failure:
logType = "-Failure";
break;
default:
logType = "-Error";
break;
}
li.LogType = logType;
return li;
}
/// <summary>
/// 写入以小时分割的日志文件
/// </summary>
/// <param name="Msg">要记录的消息</param>
/// <param name="li">日志信息类</param>
/// <param name="LogPath">日志所在文件夹</param>
/// <returns></returns>
internal static string WriteLineToTimeFile(string Msg, LogInfo li,string LogPath)
{
if (string.IsNullOrEmpty(Msg))
{
return "输入参数Msg为null或者值为空不符合记录要求!";
}
StreamWriter sw = null;
try
{
Slim.EnterWriteLock();
//string Dir = System.Windows.Forms.Application.StartupPath + @"\\GLogs\\" + DateTime.Now.ToString("yyyy年MM月dd日");
checkLog(LogPath);
string file = DateTime.Now.ToString("yyyy年MM月dd日HH时") + ".log";
checkfile(LogPath, file);
string fileName = LogPath + "\\\\" + file;
sw = File.AppendText(fileName);
sw.WriteLine("日志时间:" + DateTime.Now.ToString() + ",文件名:" + li.FileName + ",方法名:" + li.MethodName + "行号:" + li.Line + ",列:" + li.Column + ",日志类型:" + li.LogType);
sw.WriteLine("日志内容:" + Msg);
return nameof(WriteLineToTimeFile) + "日志记录操作成功!";
}
catch (Exception ex)
{
return nameof(WriteLineToTimeFile) + "日志记录发生错误:" + ex.Message;
}
finally
{
sw.Close();
Slim.ExitWriteLock();
}
}
/// <summary>
/// 检查日志目录是否存在,不存在则创建
/// </summary>
/// <param name="Path">文件夹</param>
internal static void checkLog(string Path)
{
if (!Directory.Exists(Path))
{
Directory.CreateDirectory(Path);
}
}
/// <summary>
/// 传入路径名称和文件名称,创建日志文件
/// </summary>
/// <param name="DirName">文件夹</param>
/// <param name="FileName">文件名</param>
internal static void checkfile(string DirName, string FileName)
{
if (!File.Exists(DirName + @"\\" + FileName))
{
File.Create(DirName + @"\\" + FileName).Close();
}
}
}
}
2.gLog类:
using System;
using System.IO;
using System.Collections.Generic;
using static System.Console;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace LogWriter
{
/// <summary>
/// 通过队列缓存来提高日志记录速度
/// </summary>
public class GLog
{
readonly object lockobj = new object();
TimerCallback tc;
Timer timer;
Queue<LogQueueStruct> LogList = new Queue<LogQueueStruct>();
public string LogPath { get; set; } = System.Windows.Forms.Application.StartupPath + @"\\Logs\\" + DateTime.Now.ToString("yyyy年MM月dd日");
public void RecordLog(LogType type,string msg)
{
LogQueueStruct log = new LogQueueStruct()
{
info = LogCommon.GetLog(type),
Msg=msg
};
lock (lockobj)
{
LogList.Enqueue(log);
}
timer.Change(0, Timeout.Infinite);
}
public void RegiestLog()
{
//开启一个线程用以将队列中的日志记录到文件
tc = new TimerCallback((o) =>
{
timer.Change(Timeout.Infinite, Timeout.Infinite);
lock (lockobj)
{
if (LogList.Count > 0)
{
LogQueueStruct log = LogList.Dequeue();
LogCommon.WriteLineToTimeFile(log.Msg, log.info,LogPath);
}
}
});
timer = new Timer(tc, null, Timeout.Infinite, Timeout.Infinite);
}
public int LogListCount => LogList.Count;
}
internal class LogQueueStruct
{
internal LogInfo info { get; set; }
internal string Msg { get; set; }
}
}
3.调用:
GLog log = new GLog();
log.RegiestLog();//初始化记录线程(定时器)
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
for(int i = 0; i++ < 1000;)
{
log.RecordLog(LogType.Info, $"日志记录测试数据{i}");
}
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed.TotalSeconds);
Console.WriteLine("程序部分操作完成!");
Console.ReadLine();
相比较TxtLog:
TxtLog log = TxtLog.Instance;
//初始化记录线程(定时器)
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
for(int i = 0; i++ < 1000;)
{
log.WriteLineToFile($"日志记录测试数据{i}", LogType.Info);
}
stopwatch.Stop();
Console.WriteLine($"调用{nameof(TxtLog)}耗时:{stopwatch.Elapsed.TotalSeconds}");
Console.WriteLine("程序部分操作完成!");
Console.ReadLine();
程序操作时间相差数倍!这就体现了用户调用部分和后台写磁盘文件部分,分离的好处!
以上是关于改进的日志记录类的主要内容,如果未能解决你的问题,请参考以下文章
使用Line Pos Info 和 Modern C++ 改进打印日志记录