using HslCommunication.Core;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace HslCommunication.LogNet
{
///
/// 日志存储类的基类,提供一些基础的服务
///
public abstract class LogNetBase : IDisposable
{
#region 私有字段
private HslMessageDegree m_messageDegree = HslMessageDegree.DEBUG;
private Queue m_WaitForSave = new Queue();
private SimpleHybirdLock m_simpleHybirdLock = new SimpleHybirdLock();
///
/// 文件读写锁
///
protected SimpleHybirdLock m_fileSaveLock = new SimpleHybirdLock();
private int m_SaveStatus = 0;
#endregion
#region 事件存储处
///
/// 在存储到文件的时候将会触发的事件
///
public event EventHandler BeforeSaveToFile = null;
private void OnBeforeSaveToFile(HslEventArgs args)
{
BeforeSaveToFile?.Invoke(this, args);
}
#endregion
#region 公开的属性
///
/// 日志存储模式,1:单文件,2:按大小存储,3:按时间存储
///
public int LogSaveMode { get; protected set; }
#endregion
#region 消息记录方法
///
/// 写入一条调试信息
///
///
public void WriteDebug(string text)
{
RecordMessage(HslMessageDegree.DEBUG, text);
}
///
/// 写入一条调试信息
///
/// 关键字
/// 文本内容
public void WriteDebug(string keyWord, string text)
{
if (string.IsNullOrEmpty(keyWord))
{
WriteDebug(text);
}
else
{
WriteDebug(keyWord + " : " + text);
}
}
///
/// 写入一条普通信息
///
/// 文本内容
public void WriteInfo(string text)
{
RecordMessage(HslMessageDegree.INFO, text);
}
///
/// 写入一条普通信息
///
/// 关键字
/// 文本内容
public void WriteInfo(string keyWord, string text)
{
if (string.IsNullOrEmpty(keyWord))
{
WriteInfo(text);
}
else
{
WriteInfo(keyWord + " : " + text);
}
}
///
/// 写入一条警告信息
///
/// 文本内容
public void WriteWarn(string text)
{
RecordMessage(HslMessageDegree.WARN, text);
}
///
/// 写入一条警告信息
///
/// 关键字
/// 文本内容
public void WriteWarn(string keyWord, string text)
{
if (string.IsNullOrEmpty(keyWord))
{
WriteWarn(text);
}
else
{
WriteWarn(keyWord + " : " + text);
}
}
///
/// 写入一条错误消息
///
/// 文本内容
public void WriteError(string text)
{
RecordMessage(HslMessageDegree.ERROR, text);
}
///
/// 写入一条错误消息
///
/// 关键字
/// 文本内容
public void WriteError(string keyWord, string text)
{
if (string.IsNullOrEmpty(keyWord))
{
WriteError(text);
}
else
{
WriteError(keyWord + " : " + text);
}
}
///
/// 写入一条致命错误信息
///
/// 文本内容
public void WriteFatal(string text)
{
RecordMessage(HslMessageDegree.FATAL, text);
}
///
/// 写入一条致命错误信息
///
/// 关键字
/// 文本内容
public void WriteFatal(string keyWord, string text)
{
if (string.IsNullOrEmpty(keyWord))
{
WriteFatal(text);
}
else
{
WriteFatal(keyWord + " : " + text);
}
}
///
/// 写入一条异常信息
///
/// 关键字
///
public void WriteException(string keyWord, Exception ex)
{
RecordMessage(HslMessageDegree.FATAL, LogNetManagment.GetSaveStringFromException(keyWord, ex));
}
///
/// 写入一条异常信息
///
/// 关键字
/// 内容
/// 异常
public void WriteException(string keyWord, string text, Exception ex)
{
if (string.IsNullOrEmpty(keyWord))
{
WriteException(text, ex);
}
else
{
WriteException(keyWord + " : " + text, ex);
}
}
///
/// 记录一条自定义的消息
///
///
///
public void RecordMessage(HslMessageDegree degree, string text)
{
WriteToFile(degree, text);
}
///
/// 写入一条解释性的消息,不需要带有回车键
///
///
public void WriteDescrition(string description)
{
if (string.IsNullOrEmpty(description)) return;
// 和上面的文本之间追加一行空行
StringBuilder stringBuilder = new StringBuilder("\u0002");
stringBuilder.Append(Environment.NewLine);
stringBuilder.Append("\u0002/");
int count = 118 - CalculateStringOccupyLength(description);
if (count >= 8)
{
int count_1 = (count - 8) / 2;
AppendCharToStringBuilder(stringBuilder, '*', count_1);
stringBuilder.Append(" ");
stringBuilder.Append(description);
stringBuilder.Append(" ");
if (count % 2 == 0)
{
AppendCharToStringBuilder(stringBuilder, '*', count_1);
}
else
{
AppendCharToStringBuilder(stringBuilder, '*', count_1 + 1);
}
}
else if (count >= 2)
{
int count_1 = (count - 2) / 2;
AppendCharToStringBuilder(stringBuilder, '*', count_1);
stringBuilder.Append(description);
if (count % 2 == 0)
{
AppendCharToStringBuilder(stringBuilder, '*', count_1);
}
else
{
AppendCharToStringBuilder(stringBuilder, '*', count_1 + 1);
}
}
else
{
stringBuilder.Append(description);
}
stringBuilder.Append("/");
stringBuilder.Append(Environment.NewLine);
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPoolSaveText), stringBuilder.ToString());
}
///
/// 写入一条换行符
///
public void WriteNewLine()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPoolSaveText), "\u0002" + Environment.NewLine);
}
///
/// 设置日志的存储等级,高于该等级的才会被存储
///
///
public void SetMessageDegree(HslMessageDegree degree)
{
m_messageDegree = degree;
}
#endregion
#region 文件读写块
private void WriteToFile(HslMessageDegree degree, string text)
{
// 过滤事件
if (degree <= m_messageDegree)
{
// 需要记录数据
HslMessageItem item = GetHslMessageItem(degree, text);
AddItemToCache(item);
}
}
private void AddItemToCache(HslMessageItem item)
{
m_simpleHybirdLock.Enter();
m_WaitForSave.Enqueue(item);
m_simpleHybirdLock.Leave();
StartSaveFile();
}
private void StartSaveFile()
{
if (Interlocked.CompareExchange(ref m_SaveStatus, 1, 0) == 0)
{
//启动存储
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPoolSaveFile), null);
}
}
private HslMessageItem GetAndRemoveLogItem()
{
HslMessageItem result = null;
m_simpleHybirdLock.Enter();
result = m_WaitForSave.Count > 0 ? m_WaitForSave.Dequeue() : null;
m_simpleHybirdLock.Leave();
return result;
}
private void ThreadPoolSaveFile(object obj)
{
// 获取需要存储的日志
HslMessageItem current = GetAndRemoveLogItem();
// 进入文件操作的锁
m_fileSaveLock.Enter();
// 获取要存储的文件名称
string LogSaveFileName = GetFileSaveName();
if (!string.IsNullOrEmpty(LogSaveFileName))
{
// 保存
StreamWriter sw = null;
try
{
sw = new StreamWriter(LogSaveFileName, true, Encoding.UTF8);
while (current != null)
{
// 触发事件
OnBeforeSaveToFile( new HslEventArgs( ) { HslMessage = current } );
sw.Write(HslMessageFormate(current));
sw.Write(Environment.NewLine);
current = GetAndRemoveLogItem();
}
}
catch (Exception ex)
{
AddItemToCache(current);
AddItemToCache(new HslMessageItem()
{
Degree = HslMessageDegree.FATAL,
Text = LogNetManagment.GetSaveStringFromException("LogNetSelf", ex),
});
}
finally
{
sw?.Dispose();
}
}
// 释放锁
m_fileSaveLock.Leave();
Interlocked.Exchange(ref m_SaveStatus, 0);
// 再次检测锁是否释放完成
if (m_WaitForSave.Count > 0)
{
StartSaveFile();
}
}
private string HslMessageFormate(HslMessageItem hslMessage)
{
StringBuilder stringBuilder = new StringBuilder("\u0002");
stringBuilder.Append("[");
stringBuilder.Append(LogNetManagment.GetDegreeDescription(hslMessage.Degree));
stringBuilder.Append("] ");
stringBuilder.Append(hslMessage.Time.ToString("yyyy-MM-dd HH:mm:ss.fff"));
stringBuilder.Append(" thread:[");
stringBuilder.Append(hslMessage.ThreadId.ToString("D2"));
stringBuilder.Append("] ");
stringBuilder.Append(hslMessage.Text);
return stringBuilder.ToString();
}
private void ThreadPoolSaveText(object obj)
{
// 进入文件操作的锁
m_fileSaveLock.Enter();
//获取要存储的文件名称
string LogSaveFileName = GetFileSaveName();
if (!string.IsNullOrEmpty(LogSaveFileName))
{
// 保存
StreamWriter sw = null;
try
{
sw = new StreamWriter(LogSaveFileName, true, Encoding.UTF8);
string str = obj as string;
sw.Write(str);
}
catch (Exception ex)
{
AddItemToCache(new HslMessageItem()
{
Degree = HslMessageDegree.FATAL,
Text = LogNetManagment.GetSaveStringFromException("LogNetSelf", ex),
});
}
finally
{
sw?.Dispose();
}
}
// 释放锁
m_fileSaveLock.Leave();
}
#endregion
#region 辅助方法
///
/// 获取要存储的文件的名称
///
///
protected virtual string GetFileSaveName()
{
return string.Empty;
}
///
/// 返回检查的路径名称,将会包含反斜杠
///
///
///
protected string CheckPathEndWithSprit(string filePath)
{
if (!string.IsNullOrEmpty(filePath))
{
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
if (!filePath.EndsWith(@"\"))
{
return filePath + @"\";
}
}
return filePath;
}
private HslMessageItem GetHslMessageItem(HslMessageDegree degree, string text)
{
return new HslMessageItem()
{
Degree = degree,
Text = text,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Time = DateTime.Now,
};
}
private int CalculateStringOccupyLength(string str)
{
if (string.IsNullOrEmpty(str)) return 0;
int result = 0;
for (int i = 0; i < str.Length; i++)
{
if (str[i] >= 0x4e00 && str[i] <= 0x9fbb)
{
result += 2;
}
else
{
result += 1;
}
}
return result;
}
private void AppendCharToStringBuilder(StringBuilder sb, char c, int count)
{
for (int i = 0; i < count; i++)
{
sb.Append(c);
}
}
#endregion
#region IDisposable Support
private bool disposedValue = false; // 要检测冗余调用
///
/// 释放资源
///
///
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: 释放托管状态(托管对象)。
m_simpleHybirdLock.Dispose();
m_WaitForSave.Clear();
m_fileSaveLock.Dispose();
}
// TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
// TODO: 将大型字段设置为 null。
m_simpleHybirdLock = null;
m_WaitForSave = null;
m_fileSaveLock = null;
disposedValue = true;
}
}
// TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
// ~LogNetBase() {
// // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
// Dispose(false);
// }
// 添加此代码以正确实现可处置模式。
///
/// 释放资源
///
public void Dispose()
{
// 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
Dispose(true);
// TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
// GC.SuppressFinalize(this);
}
#endregion
}
}