优点:懒加载模式,IO流不会重复实例化使用,多线程安全。
日志基类接口
/// <summary>
/// 日志基类接口
/// </summary>
public interface LogBase:IDisposable
{
/// <summary>
/// 记录信息
/// </summary>
/// <param name="message">消息内容</param>
void LogInfo(string message);
/// <summary>
/// 记录警告信息
/// </summary>
/// <param name="message">消息内容</param>
void LogWarning(string message);
/// <summary>
/// 记录错误信息
/// </summary>
/// <param name="message">消息内容</param>
void LogError(string message);
}
FileLogger文件日志类实现LogBase接口
public class FileLogger<T> : LogBase where T : class, new()
{
private StreamWriter streamWriter;
private string _filePath;
private bool _disposed;
private string _className;
private static Lazy<FileLogger<T>> lazy;
private Object writerLock = new Object();
private FileLogger(string filePath, string className)
{
if (string.IsNullOrEmpty(filePath))
return;
_filePath = filePath;
_className = className;
string path = Path.GetDirectoryName(filePath);
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
// 不覆盖
streamWriter = new StreamWriter(filePath,true);
}
public static FileLogger<T> GetInstance(string path = null)
{
if (path == null)
path = System.Environment.CurrentDirectory + "\\Log\\"+ DateTime.Now.ToString("yyyyMMdd")+"\\" + DateTime.Now.ToString("yyyyMMddHH") + ".txt";
lazy = new Lazy<FileLogger<T>>(() =>
{
return new FileLogger<T>(path, typeof(T).Name);
});
return lazy.Value;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
lock (writerLock)
{
if (!_disposed)
{
if (disposing)
{
// Release managed resources
_filePath = null;
_className = null;
}
// Release unmanaged resources
streamWriter.Close();
streamWriter.Dispose();
_disposed = true;
}
}
}
public void LogInfo(string message)
{
Write("LogInfo", message, _className);
}
public void LogWarning(string message)
{
Write("LogWarning", message, _className);
}
public void LogError(string message)
{
Write("LogError", message, _className);
}
/// <summary>
/// 写入消息方法
/// </summary>
/// <param name="mesType">消息类型</param>
/// <param name="message">消息内容</param>
/// <param name="className">类名</param>
private void Write(string mesType, string message, string className)
{
lock (writerLock)
{
StringBuilder stringBuilder = new StringBuilder(mesType);
stringBuilder.Append("\t");
stringBuilder.Append(className);
stringBuilder.Append("\t");
stringBuilder.Append(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
stringBuilder.Append("\t");
stringBuilder.Append(message);
streamWriter.WriteLine(stringBuilder.ToString());
stringBuilder.Clear();
streamWriter.Flush();
}
}
~FileLogger()
{
Dispose(false);
}
}
其它类型实现:
/// <summary>
/// 事件日志实现类
/// </summary>
/// <typeparam name="T"></typeparam>
internal class EventLogger<T> : LogBase where T : class, new()
{
private readonly Object lockObj=new object();
public void Dispose()
{
throw new NotImplementedException();
}
public void LogError(string message)
{
throw new NotImplementedException();
}
public void LogInfo(string message)
{
lock (lockObj)
{
}
}
public void LogWarning(string message)
{
throw new NotImplementedException();
}
}
/// <summary>
/// 数据库实现类
/// </summary>
/// <typeparam name="T"></typeparam>
internal class DBLogger<T> : LogBase where T : class, new()
{
public void Dispose()
{
throw new NotImplementedException();
}
public void LogError(string message)
{
throw new NotImplementedException();
}
public void LogInfo(string message)
{
throw new NotImplementedException();
}
public void LogWarning(string message)
{
throw new NotImplementedException();
}
}
数据库与事件日志文件没有具体实现,需要的话自行实现。
/// <summary>
/// 日志可以输出到目标地点
/// </summary>
public enum LogTarget
{
/// <summary>
/// txt文件
/// </summary>
FILE,
/// <summary>
/// 数据库
/// </summary>
DATABASE,
/// <summary>
/// 事件日志
/// </summary>
EVENTLOG
}
看日志工厂:
/// <summary>
/// 日志工厂
/// </summary>
/// <typeparam name="T"></typeparam>
public class LogFactory<T> where T : class, new()
{
/// <summary>
/// 工厂方法
/// 如果是非文件日志,不必传参fileName与path
/// </summary>
/// <param name="target">默认文件</param>
/// <param name="fileName">默认以时间格式命名</param>
/// <param name="path">默认当前项目路径</param>
/// <returns></returns>
public static LogBase InstanceLog(LogTarget target = LogTarget.FILE, string fileName = null, string path = null)
{
LogBase logBase = null;
switch (target)
{
case LogTarget.FILE:
if (fileName == null)
fileName = DateTime.Now.ToString("yyyyMMddHH") + ".txt";
if (path == null)
path = System.Environment.CurrentDirectory + "\\Log\\"+ DateTime.Now.ToString("yyyyMMdd");
logBase = FileLogger<T>.GetInstance(Path.Combine(path, fileName));
break;
case LogTarget.DATABASE:
logBase = new DBLogger<T>();
break;
case LogTarget.EVENTLOG:
logBase = new EventLogger<T>();
break;
}
return logBase;
}
}
调用
LogBase log = LogFactory<Program>.InstanceLog();
for (int i = 0; i < 10000; i++)
{
log.LogInfo("ddd");
log.LogError("sss");
log.LogWarning("qqq");
}
for (int i = 0; i < 10000; i++)
{
new Task(() =>
{
log.LogInfo("ddd");
log.LogError("sss");
log.LogWarning("qqq");
}).Start();
}
int n = 0;
while (true)
{
if (n >= 1000)
break;
new Task(() =>
{
log.LogInfo("ddd");
log.LogError("sss");
log.LogWarning("qqq");
}).Start();
n++;
}
log.LogInfo($"ddd");
log.Dispose();
log.Dispose();如果就当前函数使用的话就手动调用释放资源,如果全局使用就不需要调用,能手动的尽量手动(比如窗体关闭closed事件调用),不调用的也没事,等待GC调用,不过GC调用不会及时的。