解决多线程模式下日志记录
1.日志功能类,记录方法只实现了Info与Warning,其它自行加上即可运行。
public class LogDemo
{
private static Lazy<LogDemo> _logDemo = new Lazy<LogDemo>(() => new LogDemo());
private static object _locker = new object();
private const int _fileSize = 0xB71B00;// 10MB
private ConcurrentDictionary<string, string> _logKey = new ConcurrentDictionary<string, string>();
private LogDemo() { }
public static LogDemo Instance => _logDemo.Value;
private void CreateFilePath(string path)
{
string fp = Path.GetDirectoryName(path);
// 判断文件夹是否存在
if (!Directory.Exists(fp))
Directory.CreateDirectory(fp);
// 文件是否存在
if (!File.Exists(path))
{
using (var file = File.Create(path)) ;
}
}
private bool WirteIn(string log, string path, LogType logType, Exception exception = null)
{
lock (_locker)
{
if (string.IsNullOrEmpty(log))
throw new ArgumentNullException(nameof(log));
if (_logKey.ContainsKey(path))
path = _logKey[path];
CreateFilePath(path);
using (FileStream fs = new FileStream(path, FileMode.Append))
{
if (fs.Length > _fileSize)// 文件大了重新创建
{
string oldPath = path;
foreach (var item in _logKey)
{
if (item.Value == path)
oldPath = item.Key;
}
string path2 = Path.Combine(Path.GetDirectoryName(oldPath), Path.GetFileNameWithoutExtension(oldPath) + "-" + DateTime.Now.ToString("yyyyMMddHHmmssffff") + Path.GetExtension(oldPath));
_logKey.AddOrUpdate(oldPath, path2, (oldPath, path2) => path2);
WirteIn(log, path2, logType, exception);
return true;
}
using (StreamWriter sw = new StreamWriter(fs))
{
string txt = $"{logType.ToString()} {DateTime.Now.ToString("yyyy年MM月dd日 HH:mm:ss.ffff")}:{log}";
if (exception != null)
txt += "\r\n" + ExceptionToString(exception);
sw.WriteLine(txt);
}
}
return true;
}
}
public void Info(string log, string path)
{
WirteIn(log, path, LogType.Info);
}
public void Warning(string log, string path)
{
WirteIn(log, path, LogType.Warning);
}
public void Error(string log, string path, Exception ex)
{
WirteIn(log, path, LogType.Error, ex);
}
private string ExceptionToString(Exception ex)
{
if (ex.InnerException == null)
{
return GetExceptionMessage(ex);
}
return GetExceptionMessage(ex) + "\r\n***\r\n" + ExceptionToString(ex.InnerException);
}
private string GetExceptionMessage(Exception ex)
{
string message = "", source = "", stackTrace = "", targetSite = "", helpLink = "";
if (ex.Message != null)
{
message = ex.Message;
}
if (ex.Source != null)
{
source = ex.Source;
}
if (ex.StackTrace != null)
{
stackTrace = ex.StackTrace;
}
if (ex.TargetSite != null)
{
targetSite = ex.TargetSite.ToString();
}
if (ex.HelpLink != null)
{
helpLink = ex.HelpLink;
}
return message + "\r\n" + source + "\r\n" + stackTrace + "\r\n" + targetSite + helpLink;
}
}
2.枚举
public enum LogType
{
Info,
Warning,
Error,
Fatal,
Debug,
Trace
}
3.工厂
/// <summary>
/// 用作创建多个文件
/// </summary>
public class LogDemoFactory
{
public static readonly LogDemoFactory logDemoFactory1;
public static readonly LogDemoFactory logDemoFactory2;
public static readonly LogDemoFactory logDemoFactory3;
static LogDemoFactory()
{
logDemoFactory1=new LogDemoFactory("E:\\"+Guid.NewGuid().ToString()+".txt");
logDemoFactory2 = new LogDemoFactory("E:\\" + Guid.NewGuid().ToString() + ".txt");
logDemoFactory3 = new LogDemoFactory("E:\\" + Guid.NewGuid().ToString() + ".txt");
}
private string _filePath;
private LogDemo _logDemo;
private LogDemoFactory(string filePath)
{
_filePath = filePath;
_logDemo = LogDemo.Instance;
}
public void Info(string log)
{
_logDemo.Info(log, _filePath);
}
public void Warning(string log)
{
_logDemo.Warning(log, _filePath);
}
}
4.多线程测试
for (int j = 0; j < 10; j++)
{
int n = 100;
int m = n + 2;
Task[] tasks = new Task[m];
for (int i = 0; i < n; i++)
{
tasks[i] = Task.Factory.StartNew(() =>
{
LogDemoFactory.logDemoFactory1.Info("你好,阿泽!");
});
tasks[i + 1] = Task.Factory.StartNew(() =>
{
LogDemoFactory.logDemoFactory2.Info("你好,阿泽!");
});
tasks[i + 2] = Task.Factory.StartNew(() =>
{
LogDemoFactory.logDemoFactory3.Info("你好,阿泽!");
});
}
await Task.WhenAll(tasks);
}
5. 单线程测试
while (true)
{
LogDemoFactory.logDemoFactory1.Info("你好,阿泽!");
LogDemoFactory.logDemoFactory2.Info("你好,阿泽!");
LogDemoFactory.logDemoFactory3.Info("你好,阿泽!");
Thread.Sleep(100);
}
6.完毕。