You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
9.7 KiB
344 lines
9.7 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.IO;
|
|
|
|
|
|
namespace Sog.Log
|
|
{
|
|
internal class LogWriteRecord
|
|
{
|
|
public string FilePathName;
|
|
public string LogMessage;
|
|
public bool ShiftFile;
|
|
}
|
|
|
|
internal class LogFileCache
|
|
{
|
|
public bool OpenFailed;
|
|
public string FilePathName;
|
|
public long FileLength;
|
|
public long LastWriteTime;
|
|
public StreamWriter Writer;
|
|
}
|
|
|
|
internal class LogWriteThread : Singleton<LogWriteThread> , IDisposable
|
|
{
|
|
/// <summary>
|
|
/// 写队列
|
|
/// 线程安全锁,注意,log本身是IO操作,比较费时间
|
|
/// 优化:开启单独线程写log,其他线程写log先写到内存队列,写log线程取出写磁盘
|
|
/// 这么做唯一的缺点是如果程序core了,有可能部分log写磁盘不成功,不过C#不容易整个进程挂掉,似乎可行
|
|
/// </summary>
|
|
private Queue<LogWriteRecord> m_logQueue = new Queue<LogWriteRecord>();
|
|
|
|
//写文件的cache
|
|
//filePathName ,LogFileCache
|
|
private Dictionary<string, LogFileCache> m_fileCache = new Dictionary<string, LogFileCache>();
|
|
|
|
private Thread m_writeThread;
|
|
|
|
private long m_lastCheckTimeoutTime;
|
|
|
|
private bool m_isClosed = false;
|
|
|
|
private object locker = new object();
|
|
|
|
/// <summary>
|
|
/// 等所有文件写完后释放
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
ForceClose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 开启
|
|
/// </summary>
|
|
public void Start()
|
|
{
|
|
m_isClosed = false;
|
|
|
|
if (m_writeThread == null)
|
|
{
|
|
m_writeThread = new Thread(this.WorkThreadFun);
|
|
//设置成后台线程,如果不是后台线程,线程不是主动关闭,则会一直运行,那怕进程主线程退出也没用
|
|
m_writeThread.IsBackground = true;
|
|
m_writeThread.Start();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 强制关闭,一般用不到
|
|
/// </summary>
|
|
public void ForceClose()
|
|
{
|
|
m_isClosed = true;
|
|
|
|
if (m_writeThread == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
while(m_writeThread.IsAlive)
|
|
{
|
|
Thread.Sleep(1);
|
|
}
|
|
|
|
m_writeThread = null;
|
|
|
|
WriteAllLogInQueue();
|
|
|
|
CloseAllFile();
|
|
}
|
|
|
|
public void WriteLog(string filepathname, string message, bool shiftFile)
|
|
{
|
|
//有可能没开启
|
|
//有可能关闭了
|
|
if(m_isClosed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LogWriteRecord record = new LogWriteRecord();
|
|
record.FilePathName = filepathname;
|
|
record.LogMessage = message;
|
|
record.ShiftFile = shiftFile;
|
|
|
|
lock (locker)
|
|
{
|
|
m_logQueue.Enqueue(record);
|
|
}
|
|
}
|
|
|
|
private void WorkThreadFun()
|
|
{
|
|
while (!m_isClosed)
|
|
{
|
|
try
|
|
{
|
|
//写文件
|
|
int iCount = WriteAllLogInQueue();
|
|
if(iCount == 0)
|
|
{
|
|
Thread.Sleep(10);
|
|
//continue;
|
|
}
|
|
|
|
//关闭长时间不写的文件
|
|
TickCloseTimeoutFile();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
private int WriteAllLogInQueue()
|
|
{
|
|
int writeRecordCount = 0;
|
|
|
|
while(m_logQueue.Count > 0)
|
|
{
|
|
LogWriteRecord record;
|
|
lock (locker)
|
|
{
|
|
record = m_logQueue.Dequeue();
|
|
}
|
|
|
|
writeRecordCount++;
|
|
|
|
WriteLogRecord(record);
|
|
|
|
}
|
|
|
|
return writeRecordCount;
|
|
}
|
|
|
|
private void WriteLogRecord(LogWriteRecord record)
|
|
{
|
|
LogFileCache fileCache;
|
|
if(false == m_fileCache.TryGetValue(record.FilePathName, out fileCache))
|
|
{
|
|
fileCache = new LogFileCache();
|
|
fileCache.FilePathName = record.FilePathName;
|
|
fileCache.FileLength = 0;
|
|
fileCache.OpenFailed = false;
|
|
|
|
m_fileCache.Add(record.FilePathName, fileCache);
|
|
}
|
|
|
|
OpenFile(fileCache);
|
|
if(record.ShiftFile)
|
|
{
|
|
ShiftFile(fileCache);
|
|
}
|
|
|
|
if(fileCache.Writer != null)
|
|
{
|
|
fileCache.Writer.Write(record.LogMessage);
|
|
fileCache.FileLength += record.LogMessage.Length;
|
|
|
|
//flush可以优化吗
|
|
fileCache.Writer.Flush();
|
|
fileCache.LastWriteTime = AppTime.GetNowSysSecond();
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 打开文件,有可能失败
|
|
/// </summary>
|
|
/// <param name="fileCache"></param>
|
|
private void OpenFile(LogFileCache fileCache)
|
|
{
|
|
if (fileCache.OpenFailed == false && fileCache.Writer == null)
|
|
{
|
|
if (! File.Exists(fileCache.FilePathName))
|
|
{
|
|
// Create a file to write to.
|
|
using (File.Create(fileCache.FilePathName))
|
|
{
|
|
}
|
|
}
|
|
|
|
FileStream fileStream = new FileStream(fileCache.FilePathName, FileMode.Append, FileAccess.Write, FileShare.Read);
|
|
fileCache.Writer = new StreamWriter(fileStream);
|
|
FileInfo fileinfo = new FileInfo(fileCache.FilePathName);
|
|
fileCache.FileLength = fileinfo.Length;
|
|
|
|
if (fileCache.Writer == null)
|
|
{
|
|
fileCache.OpenFailed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// shift to multi file
|
|
/// 滚动文件
|
|
/// </summary>
|
|
private void ShiftFile(LogFileCache fileCache)
|
|
{
|
|
if (fileCache.OpenFailed == true || fileCache.Writer == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//为0表示关闭shift功能
|
|
if (LogDefaultParam.ShiftFileSize == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
if (fileCache.FileLength > LogDefaultParam.ShiftFileSize)
|
|
{
|
|
//先关闭文件
|
|
fileCache.Writer.Dispose();
|
|
fileCache.Writer = null;
|
|
//
|
|
try
|
|
{
|
|
for (int i = LogDefaultParam.ShiftFileCount; i > 0; i--)
|
|
{
|
|
string shiftDst = fileCache.FilePathName;
|
|
if (i > 0 && i < 10)
|
|
{
|
|
shiftDst += ".0" + i.ToString();
|
|
}
|
|
else
|
|
{
|
|
shiftDst += "." + i.ToString();
|
|
}
|
|
string shiftSrc = fileCache.FilePathName;
|
|
int srcIndex = i - 1;
|
|
if (srcIndex > 0 && srcIndex < 10)
|
|
{
|
|
shiftSrc += ".0" + srcIndex.ToString();
|
|
}
|
|
else if(srcIndex >= 10)
|
|
{
|
|
shiftSrc += "." + srcIndex.ToString();
|
|
}
|
|
if (File.Exists(shiftSrc))
|
|
{
|
|
if (File.Exists(shiftDst))
|
|
{
|
|
File.Delete(shiftDst);
|
|
}
|
|
File.Move(shiftSrc, shiftDst);
|
|
}
|
|
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
fileCache.FileLength = 0;
|
|
OpenFile(fileCache);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 关闭超时文件
|
|
/// </summary>
|
|
private void TickCloseTimeoutFile()
|
|
{
|
|
long nowSecond = AppTime.GetNowSysSecond();
|
|
|
|
//一分钟检查一次
|
|
if(nowSecond - m_lastCheckTimeoutTime < 60)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_lastCheckTimeoutTime = nowSecond;
|
|
|
|
List<string> needCloseFile = new List<string>();
|
|
foreach(var item in m_fileCache.Values)
|
|
{
|
|
//5分钟超时
|
|
if (nowSecond - item.LastWriteTime >= LogDefaultParam.CloseTimeoutLogFileTime)
|
|
{
|
|
if (item.Writer != null)
|
|
{
|
|
item.Writer.Flush();
|
|
item.Writer.Dispose();
|
|
}
|
|
|
|
item.Writer = null;
|
|
|
|
needCloseFile.Add(item.FilePathName);
|
|
}
|
|
}
|
|
|
|
if(needCloseFile.Count > 0)
|
|
{
|
|
foreach(var filename in needCloseFile)
|
|
{
|
|
m_fileCache.Remove(filename);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CloseAllFile()
|
|
{
|
|
foreach (var item in m_fileCache.Values)
|
|
{
|
|
if (item.Writer != null)
|
|
{
|
|
item.Writer.Flush();
|
|
item.Writer.Dispose();
|
|
item.Writer = null;
|
|
}
|
|
}
|
|
|
|
m_fileCache.Clear();
|
|
}
|
|
}
|
|
}
|
|
|