Udp服务端:
cs
复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.IO;
using Notify.Log;
namespace UdpSer
{
public class UdpServer
{
// 创建UDP端点,并绑定到本地端口
IPEndPoint localEndPoint;
// 创建UDP套接字
private UdpClient udpServer = new UdpClient();
private volatile bool runing = false;
private byte[] receiveBytes = new byte[2048];
private byte[] sendBytes = new byte[2048];
private Queue<LogContentV2> logBuffer = new Queue<LogContentV2>();
private Thread listenThread;
public int LogBufferCount { get { return this.logBuffer.Count; } }
public LogContentV2 Log { get { return this.logBuffer.Dequeue(); } }
public UdpServer()
{
// 创建UDP端点,并绑定到本地端口
localEndPoint = new IPEndPoint(IPAddress.Any, 8421);
// 创建UDP套接字
udpServer = new UdpClient(localEndPoint);
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer default constructed."));
}
public UdpServer(int port = 8421)
{
// 创建UDP端点,并绑定到本地端口
localEndPoint = new IPEndPoint(IPAddress.Any, port);
// 创建UDP套接字
udpServer = new UdpClient(localEndPoint);
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer constructed."));
}
public void Startup()
{
this.localEndPoint = new IPEndPoint(IPAddress.Any, 8421);
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
switch (listenThread.ThreadState)
{
case System.Threading.ThreadState.Unstarted:
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.StopRequested:
case System.Threading.ThreadState.AbortRequested:
case System.Threading.ThreadState.Aborted:
case System.Threading.ThreadState.Stopped:
case System.Threading.ThreadState.Suspended:
case System.Threading.ThreadState.SuspendRequested:
this.listenThread.Abort();
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.Running:
runing = true;
break;
}
}
public void Startup(int port)
{
this.localEndPoint = new IPEndPoint(IPAddress.Any, port);
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
switch (listenThread.ThreadState)
{
case System.Threading.ThreadState.Unstarted:
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.StopRequested:
case System.Threading.ThreadState.AbortRequested:
case System.Threading.ThreadState.Aborted:
case System.Threading.ThreadState.Stopped:
case System.Threading.ThreadState.Suspended:
case System.Threading.ThreadState.SuspendRequested:
this.listenThread.Abort();
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.Running:
runing = true;
break;
}
}
public void Startup(string ipaddr, int port)
{
this.localEndPoint = new IPEndPoint(IPAddress.Parse(ipaddr), port);
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
switch (listenThread.ThreadState)
{
case System.Threading.ThreadState.Unstarted:
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.StopRequested:
case System.Threading.ThreadState.AbortRequested:
case System.Threading.ThreadState.Aborted:
case System.Threading.ThreadState.Stopped:
case System.Threading.ThreadState.Suspended:
case System.Threading.ThreadState.SuspendRequested:
this.listenThread.Abort();
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.Running:
runing = true;
break;
}
}
public void Stop()
{
try
{
this.runing = false;
switch (listenThread.ThreadState)
{
case System.Threading.ThreadState.Unstarted:
case System.Threading.ThreadState.Aborted:
case System.Threading.ThreadState.Stopped:
break;
case System.Threading.ThreadState.StopRequested:
case System.Threading.ThreadState.AbortRequested:
Thread.Sleep(2000); // 让线程工作一段时间
break;
case System.Threading.ThreadState.Suspended:
case System.Threading.ThreadState.SuspendRequested:
this.listenThread.Abort();
break;
case System.Threading.ThreadState.Background:
case System.Threading.ThreadState.Running:
this.listenThread.Join();
break;
}
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer Stop Called."));
}
catch (Exception e)
{
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Error, "UdpServer Stop Exception.", e));
}
System.GC.Collect();
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer Stoped Called System.GC.Collect."));
}
private void TaskRunning()
{
Task.Run(() =>
{
try
{
while (runing)
{
// 接收数据
this.receiveBytes = udpServer.Receive(ref localEndPoint);
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"Received {receiveBytes.Length} Bytes."));
//处理数据
HandleReceiveResposoneModel();
// 响应数据
if (sendBytes.Length > 0)
{
udpServer.Send(sendBytes, sendBytes.Length, localEndPoint);
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"Sented {receiveBytes.Length} Bytes."));
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Error, "Task.Run Receive Exception.", e));
}
});
}
private void HandleReceiveResposoneModel()
{
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"HandleReceiveResposoneModel"));
//this.receiveBytes;
//this.sendBytes;
string sendMessage = "Message received";
sendBytes = Encoding.UTF8.GetBytes(sendMessage);
}
}
internal class Program
{
static void Main(string[] args)
{
UdpServer udpServer = new UdpServer();
udpServer.Startup("127.0.0.1",8421);
Console.WriteLine("Press any key to stop the server");
Console.ReadKey();
udpServer.Stop();
}
}
}
namespace Notify.Log
{
public enum LogLevel
{
Trace = 0,
Debug = 1,
Information = 2,
Statistic = 3,
Warning = 4,
Mistake = 6, //轻微错误
Exception = 5,
Error = 7, //逻辑错误
Critical = 8, //严重错误
Fault = 9 //致命错误
}
public enum LogLevelV2
{
Infor = 2,
Excep = 5,
Error = 7,
}
//临时日志是写文本文件,这种操作在高并发程序里会造成程序崩溃
public class TempLog
{
//注意只有一个线程写,不能多个线程同时写文件。
static public void logging(List<NtLog> logbuf, string filepath = "./NotifyLog.log")
{
// 确保日志文件的目录存在
Directory.CreateDirectory(Path.GetDirectoryName(filepath));
// 使用StreamWriter写入日志
using (StreamWriter writer = new StreamWriter(filepath, true)) // true表示追加模式
{
//writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
// 这里可以添加更多的日志写入操作
//foreach (NtLog log in logbuf)
//{
// writer.WriteLine(log.ToString());
// 移除已经写了的缓存
// logbuf.Remove(log);//迭代器安全问题
//}
for (int i = 0; i < logbuf.Count; i++)
{
//#if DEBUG
// Console.WriteLine(logbuf[i].ToString());
//#endif
writer.WriteLine(logbuf[i].ToString());
logbuf.RemoveAt(i);
}
}
}
static public void logging(List<NtLog> logbuf)
{
string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"
string fullPath = Path.Combine("./logs", fileName);
// 确保日志文件的目录存在
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// 使用StreamWriter写入日志
using (StreamWriter writer = new StreamWriter(fullPath, true)) // true表示追加模式
{
//writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
// 这里可以添加更多的日志写入操作
//foreach (NtLog log in logbuf)
//{
// writer.WriteLine(log.ToString());
// 移除已经写了的缓存
// logbuf.Remove(log);//迭代器安全问题
//}
for (int i = 0; i < logbuf.Count; i++)
{
#if DEBUG
Console.WriteLine(logbuf[i].ToString());
#endif
writer.WriteLine(logbuf[i].ToString());
logbuf.RemoveAt(i);
}
}
}
static public void logging(string message, string logpath)
{
using (StreamWriter writer = new StreamWriter(logpath, true)) // true表示追加模式
{
//string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"
string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
writer.WriteLine(content);
}
}
static public void logging(string message)
{
string path = AppDomain.CurrentDomain.BaseDirectory;
using (StreamWriter writer = new StreamWriter(path + "//TempLog.log", true)) // true表示追加模式
{
//string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"
string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
writer.WriteLine(content);
}
}
}
public class LogContentV2
{
public DateTime Occurrence { get; set; }
public LogLevelV2 LevelV2 { get; set; }
public StackTrace Trace { get; set; }
public string Message { get; set; }
public LogContentV2() { }
public LogContentV2(LogLevelV2 level, string message)
{
this.Occurrence = DateTime.Now;
this.LevelV2 = level;
this.Trace = new StackTrace(true);//捕捉当前堆栈
this.Message = message;
}
public LogContentV2(LogLevelV2 level, string message, Exception e)
{
this.Occurrence = DateTime.Now;
this.LevelV2 = level;
this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
this.Message = message;
}
public override string ToString()
{
return $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.ffff")} {LevelV2.ToString()}:{Message}";//因为ffff会确保输出始终是4位数字,不足的部分用零填充。
}
}
public class LogContent
{
public DateTime Occurrence { get; set; }
public LogLevel Level { get; set; }
public StackTrace Trace { get; set; }
public string Message { get; set; }
public LogContent() { }
public LogContent(LogLevel level, string message)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(true);//捕捉当前堆栈
this.Message = message;
}
public LogContent(LogLevel level, string message, Exception e)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
this.Message = message;
}
public override string ToString()
{
//string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
//string tmp = $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF")} {Level.ToString()} {Message}";
//return tmp;
return $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF")} {Level.ToString()}:{Message}";
}
}
public class LogContentX
{
public DateTime Occurrence { get; set; }
public LogLevel Level { get; set; }
public StackTrace Trace { get; set; }
public string Message { get; set; }
public LogContentX() { }
public LogContentX(LogLevel level, string message) { this.SetLog(level, message); }
public LogContentX(LogLevel level, string message, Exception e) { this.SetLog(level, message, e); }
public void SetLog(LogLevel level, string message)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(true);//捕捉当前堆栈
this.Message = message;
}
public void SetLog(LogLevel level, string message, Exception e)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
this.Message = message;
}
public override string ToString()
{
string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
return tmp;
}
public string TraceDetail()
{
string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
tmp += this.Trace.ToString() + "\r\n";
//StackFrame sf = Trace.GetFrame(0);
//tmp += $" Method: {sf.GetMethod()}\r\n";
//$" File: {sf.GetFileName()}\r\n" +
//$" Line Number: {sf.GetFileLineNumber()}\r\n";
return tmp;
}
public static string TraceDetail(LogContent log)
{
string tmp = log.Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + " " + log.Level.ToString() + ":" + log.Message + "\n";
tmp += log.Trace.ToString() + "\r\n";
//StackFrame sf = Trace.GetFrame(0);
//tmp += $" Method: {sf.GetMethod()}\r\n";
//$" File: {sf.GetFileName()}\r\n" +
//$" Line Number: {sf.GetFileLineNumber()}\r\n";
return tmp;
}
public string TraceTopFrame()
{
return this.Trace.GetFrame(0).ToString();
}
public StackFrame TraceTopStackFrame()
{
return Trace.GetFrame(0);
}
public StackFrame TraceBottomStackFrame()
{
return Trace.GetFrame(this.Trace.FrameCount - 1);
}
public int GetSize()
{
//在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
// Each character in a string is 2 bytes (UTF-16 encoding).
int total = sizeof(LogLevel) + this.Message.Length * 2 + 8;
for (int i = 0; i < this.Trace.FrameCount; i++)
{
StackFrame sf = this.Trace.GetFrame(i);
//sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name;
total += sf.ToString().Length * 2;
}
return total;
}
public static int GetSize(LogContent log)
{
//在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
// Each character in a string is 2 bytes (UTF-16 encoding).
int total = sizeof(LogLevel) + log.Message.Length * 2 + 8;
for (int i = 0; i < log.Trace.FrameCount; i++)
{
StackFrame sf = log.Trace.GetFrame(i);
//sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name;
total += sf.ToString().Length * 2;
}
return total;
}
}
public class LogBuffer
{
protected List<LogContent> buf = new List<LogContent>();
public List<LogContent> Buffer { get { return buf; } }
public LogBuffer()
{
buf = new List<LogContent>();
}
public LogBuffer(List<LogContent> buf)
{
this.buf = buf;
}
public void Insert(LogContent log)
{
this.buf.Add(log);
}
public void Insert(LogBuffer log)
{
foreach (var item in log.Buffer)
{
this.buf.Add(item);
}
}
public int LogSize()
{
int size = 0;
foreach (LogContent cnt in this.buf)
{
size += LogContentX.GetSize(cnt);
}
return size;
}
}
public class LogBufQuery
{
public List<LogContent> Buffer { get; set; }
public void TimeOrderAsc()
{
Buffer.Sort((x, y) => x.Occurrence.CompareTo(y.Occurrence));
}
public void TimeOrderDsc()
{
Buffer.Sort((x, y) => y.Occurrence.CompareTo(x.Occurrence));
}
public List<LogContent> FilterByLoglevel(LogLevel loglevel)
{
return Buffer.FindAll(log => log.Level == loglevel);
}
}
public struct logstatics
{
public string item;
public string value;
public long Timestamp;
// 将 UNIX 时间戳转换为 DateTime
//DateTime dateTime = DateTimeOffset.FromUnixTimeSeconds(Timestamp).DateTime;
public DateTime FromUnixTime()
{
return DateTimeOffset.FromUnixTimeSeconds(Timestamp).DateTime;
}
}
public class TotalAccessSattistic
{
private ulong totalAccess;
/// <summary>
/// 总访问量
/// </summary>
public ulong TotalAccess
{
get
{
return this.totalAccess;
}
}
private void Reset()
{ this.totalAccess = 0; }
public void StasticAccess(List<LogContent> buf, string flagstr = "HandleClientComm")
{
foreach (var cnt in buf)
{
if (cnt.Message == flagstr)
this.totalAccess++;
}
}
}
//将日志写成文本文件,注意在多线程环境下要排除线程互斥。
public class NtLog
{
//private Queue<LogBuffer> Buff = new Queue<LogBuffer>();
private Queue<LogContent> buffer = new Queue<LogContent>();
public string LogPath { get; }
private string curfilepath = string.Empty;
private string errorLgFile = string.Empty; //定义从Exception到Fault这5个层级为Error
private Task task; //不要删除,多线程写日志时会用到
private Stopwatch watcher = new Stopwatch();
private long maxms, minms, lastms;
private volatile bool IsWriting = false;
public bool Writing { get { return IsWriting; } }
/// <summary>
/// 平均耗时
/// </summary>
public long AverageConsum
{
get
{
return (maxms + minms + lastms) / 3;
}
}
public NtLog()
{
this.LogPath = AppDomain.CurrentDomain.BaseDirectory;
创建日志文件夹
this.LogPath = CreateLogDirectory();
MakeLogFileName();
maxms = minms = lastms = 0;
}
public void Enqueue(LogContent log)
{
this.buffer.Enqueue(log);
}
public void Enqueue(List<LogContent> logs)
{
foreach (LogContent log in logs)
{
this.buffer.Enqueue(log);
}
}
public void Enqueue(LogBuffer logbuf)
{
foreach (LogContent log in logbuf.Buffer)
{
this.buffer.Enqueue(log);
}
}
public void OnLogging(List<LogContent> logs)
{
//#if DEBUG
// TempLog.logging($"查看原始数据。{logs.Count} ");//{logs.First().Message}
//#endif
//this.Buff.Enqueue(new LogBuffer(logs));
this.Enqueue(logs);
this.UpdatePathFileName();
if (this.IsWriting == false && this.buffer.Count > 0)
{
//LogBuffer Temp = this.Buff.Dequeue();
//while (this.Buff.Count > 0)
//{
// Temp.Insert(this.Buff.Dequeue());
//}
WriteLogByThreadV4(this.buffer);
}
}
public void OnLogging(Queue<LogContent> logs)
{
for (int i = 0; i < logs.Count; i++)
{
this.buffer.Enqueue(logs.Dequeue());
}
this.UpdatePathFileName();
if (this.IsWriting == false && this.buffer.Count > 0)
{
//LogBuffer Temp = this.Buff.Dequeue();
//while (this.Buff.Count > 0)
//{
// Temp.Insert(this.Buff.Dequeue());
//}
WriteLogByThreadV4(this.buffer);
}
}
public static string CreateLogDirectory()
{
string path = AppDomain.CurrentDomain.BaseDirectory;
// 获取当前应用程序域的名称(通常是程序集名称)
string assemblyName = AppDomain.CurrentDomain.FriendlyName;
// 去掉路径和扩展名,只保留文件名
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
// 组合成完整的路径
path = System.IO.Path.Combine(path, assemblyName + "Log");
//TempLog.logging(path);
//创建日志文件夹
Directory.CreateDirectory(path);
return path;
}
public void UpdatePathFileName()
{
string path = AppDomain.CurrentDomain.BaseDirectory;
// 获取当前应用程序域的名称(通常是程序集名称)
string assemblyName = AppDomain.CurrentDomain.FriendlyName;
// 去掉路径和扩展名,只保留文件名
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
// 组合成完整的路径
path = System.IO.Path.Combine(path, assemblyName + "Log");
//TempLog.logging(path);
//创建日志文件夹
Directory.CreateDirectory(path);
string dn = DateTime.Now.ToString("yyyy-MM-dd");
this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
}
public void MakeLogFileName()
{
// 获取当前应用程序域的名称(通常是程序集名称)
string assemblyName = AppDomain.CurrentDomain.FriendlyName;
// 去掉路径和扩展名,只保留文件名
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
string dn = DateTime.Now.ToString("yyyy-MM-dd");
this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
}
public void WriteLogFile()
{
using (StreamWriter writer = new StreamWriter(this.curfilepath, true)) // true表示追加模式
{
foreach (var cnt in this.buffer)
{
writer.WriteLine(cnt.ToString());
}
}
}
public void WriteErrorLog()
{
using (StreamWriter writer = new StreamWriter(this.errorLgFile, true)) // true表示追加模式
{
foreach (var cnt in this.buffer)
{
if (cnt.Level >= LogLevel.Warning)
writer.WriteLine(LogContentX.TraceDetail(cnt));
}
}
}
//发现它仍然阻塞主线程
//注意只有一个线程写,不能多个线程同时写文件。
//请注意,Buffer.Remove(cnt) 在循环中可能会导致问题,因为从集合中移除元素会改变集合的大小,从而可能导致迭代器失效。为了避免这个问题,可以先收集需要删除的元素,然后在循环结束后统一删除它们。
public void WriteLogByThread(LogBuffer logs)
{
this.watcher.Start();
this.IsWriting = true;
//#if DEBUG
// TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
//#endif
//this.WriteLogFile
// 使用Task.Run在后台线程中执行文件写入操作
this.task = Task.Run(() =>
{
//FileStream可以设置成独享锁定模式,防止 线程互斥
using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None),
fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer = new StreamWriter(fs1), writer2 = new StreamWriter(fs2))
{
foreach (var cnt in logs.Buffer)
{
writer.WriteLine(cnt.ToString());
if (cnt.Level >= LogLevel.Warning)
writer2.WriteLine(LogContentX.TraceDetail(cnt));
}
}
}
//Buffer没有上锁是希望它尽快完成操作,但有风险
});
this.watcher.Stop();
this.IsWriting = false;
if (this.lastms > 0 && this.lastms > this.maxms)
{
this.maxms = this.lastms;
}
if (this.lastms > 0 && this.minms == 0)
this.minms = this.lastms;
if (this.lastms > 0 && this.lastms < this.minms)
{
this.minms = this.lastms;
}
this.lastms = watcher.ElapsedMilliseconds;
}
//如果没有errlog就不写
public void WriteLogByThreadV2(LogBuffer logs)
{
this.watcher.Start();
this.IsWriting = true;
Queue<LogContent> errlogs = new Queue<LogContent>();
//#if DEBUG
// TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
//#endif
//this.WriteLogFile
// 使用Task.Run在后台线程中执行文件写入操作
this.task = Task.Run(() =>
{
//FileStream可以设置成独享锁定模式,防止 线程互斥
using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer = new StreamWriter(fs1))
{
foreach (var cnt in logs.Buffer)
{
writer.WriteLine(cnt.ToString());
if (cnt.Level >= LogLevel.Warning)
errlogs.Enqueue(cnt);
}
}
}
if (errlogs.Count > 0)
{
using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer2 = new StreamWriter(fs2))
{
for (int i = 0; i < errlogs.Count; i++)
{
writer2.WriteLine(errlogs.Dequeue().ToString());
}
}
}
}
//Buffer没有上锁是希望它尽快完成操作,但有风险
});
this.watcher.Stop();
this.IsWriting = false;
if (this.lastms > 0 && this.lastms > this.maxms)
{
this.maxms = this.lastms;
}
if (this.lastms > 0 && this.minms == 0)
this.minms = this.lastms;
if (this.lastms > 0 && this.lastms < this.minms)
{
this.minms = this.lastms;
}
this.lastms = watcher.ElapsedMilliseconds;
}
public void WriteLogByThreadV3(Queue<LogContent> queue)
{
this.watcher.Start();
this.IsWriting = true;
Queue<LogContent> errlogs = new Queue<LogContent>();
//#if DEBUG
// TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
//#endif
//this.WriteLogFile
// 使用Task.Run在后台线程中执行文件写入操作
this.task = Task.Run(() =>
{
//FileStream可以设置成独享锁定模式,防止 线程互斥
using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer = new StreamWriter(fs1))
{
//foreach (var cnt in queue)
//{
// writer.WriteLine(cnt.ToString());
// ;
// if (cnt.Level >= LogLevel.Warning)
// errlogs.Enqueue(cnt);
//}
while (queue.Count > 0)
{
var tmp = queue.Dequeue();
writer.WriteLine(tmp.ToString());
if (tmp.Level >= LogLevel.Warning)
errlogs.Enqueue(tmp);
}
}
}
if (errlogs.Count > 0)
{
using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer2 = new StreamWriter(fs2))
{
for (int i = 0; i < errlogs.Count; i++)
{
writer2.WriteLine(errlogs.Dequeue().ToString());
}
}
}
}
//Buffer没有上锁是希望它尽快完成操作,但有风险
});
this.watcher.Stop();
this.IsWriting = false;
if (this.lastms > 0 && this.lastms > this.maxms)
{
this.maxms = this.lastms;
}
if (this.lastms > 0 && this.minms == 0)
this.minms = this.lastms;
if (this.lastms > 0 && this.lastms < this.minms)
{
this.minms = this.lastms;
}
this.lastms = watcher.ElapsedMilliseconds;
}
public void WriteLogByThreadV4(Queue<LogContent> queue)
{
this.watcher.Start();
this.IsWriting = true;
Queue<LogContent> errlogs = new Queue<LogContent>();
//#if DEBUG
// TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
//#endif
//this.WriteLogFile
// 使用Task.Run在后台线程中执行文件写入操作
this.task = Task.Run(() =>
{
//FileStream可以设置成独享锁定模式,防止 线程互斥
using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer = new StreamWriter(fs1))
{
//foreach (var cnt in queue)
//{
// writer.WriteLine(cnt.ToString());
// ;
// if (cnt.Level >= LogLevel.Warning)
// errlogs.Enqueue(cnt);
//}
while (queue.Count > 0)
{
var tmp = queue.Dequeue();
writer.WriteLine(tmp.ToString());
if (tmp.Level >= LogLevel.Warning)
errlogs.Enqueue(tmp);
}
}
}
if (errlogs.Count > 0)
{
using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer2 = new StreamWriter(fs2))
{
for (int i = 0; i < errlogs.Count; i++)
{
writer2.WriteLine(LogContentX.TraceDetail(errlogs.Dequeue()));
}
}
}
}
//Buffer没有上锁是希望它尽快完成操作,但有风险
});
this.watcher.Stop();
this.IsWriting = false;
if (this.lastms > 0 && this.lastms > this.maxms)
{
this.maxms = this.lastms;
}
if (this.lastms > 0 && this.minms == 0)
this.minms = this.lastms;
if (this.lastms > 0 && this.lastms < this.minms)
{
this.minms = this.lastms;
}
this.lastms = watcher.ElapsedMilliseconds;
}
}
}
Udp客户端:
cs
复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.IO;
using Notify.Log;
namespace UdpSer
{
public class UdpServer
{
// 创建UDP端点,并绑定到本地端口
IPEndPoint localEndPoint;
// 创建UDP套接字
private UdpClient udpServer = new UdpClient();
private volatile bool runing = false;
private byte[] receiveBytes = new byte[2048];
private byte[] sendBytes = new byte[2048];
private Queue<LogContentV2> logBuffer = new Queue<LogContentV2>();
private Thread listenThread;
public int LogBufferCount { get { return this.logBuffer.Count; } }
public LogContentV2 Log { get { return this.logBuffer.Dequeue(); } }
public UdpServer()
{
// 创建UDP端点,并绑定到本地端口
localEndPoint = new IPEndPoint(IPAddress.Any, 8421);
// 创建UDP套接字
udpServer = new UdpClient(localEndPoint);
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer default constructed."));
}
public UdpServer(int port = 8421)
{
// 创建UDP端点,并绑定到本地端口
localEndPoint = new IPEndPoint(IPAddress.Any, port);
// 创建UDP套接字
udpServer = new UdpClient(localEndPoint);
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer constructed."));
}
public void Startup()
{
this.localEndPoint = new IPEndPoint(IPAddress.Any, 8421);
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
switch (listenThread.ThreadState)
{
case System.Threading.ThreadState.Unstarted:
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.StopRequested:
case System.Threading.ThreadState.AbortRequested:
case System.Threading.ThreadState.Aborted:
case System.Threading.ThreadState.Stopped:
case System.Threading.ThreadState.Suspended:
case System.Threading.ThreadState.SuspendRequested:
this.listenThread.Abort();
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.Running:
runing = true;
break;
}
}
public void Startup(int port)
{
this.localEndPoint = new IPEndPoint(IPAddress.Any, port);
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
switch (listenThread.ThreadState)
{
case System.Threading.ThreadState.Unstarted:
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.StopRequested:
case System.Threading.ThreadState.AbortRequested:
case System.Threading.ThreadState.Aborted:
case System.Threading.ThreadState.Stopped:
case System.Threading.ThreadState.Suspended:
case System.Threading.ThreadState.SuspendRequested:
this.listenThread.Abort();
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.Running:
runing = true;
break;
}
}
public void Startup(string ipaddr, int port)
{
this.localEndPoint = new IPEndPoint(IPAddress.Parse(ipaddr), port);
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
switch (listenThread.ThreadState)
{
case System.Threading.ThreadState.Unstarted:
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.StopRequested:
case System.Threading.ThreadState.AbortRequested:
case System.Threading.ThreadState.Aborted:
case System.Threading.ThreadState.Stopped:
case System.Threading.ThreadState.Suspended:
case System.Threading.ThreadState.SuspendRequested:
this.listenThread.Abort();
this.listenThread = new Thread(new ThreadStart(TaskRunning));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.Running:
runing = true;
break;
}
}
public void Stop()
{
try
{
this.runing = false;
switch (listenThread.ThreadState)
{
case System.Threading.ThreadState.Unstarted:
case System.Threading.ThreadState.Aborted:
case System.Threading.ThreadState.Stopped:
break;
case System.Threading.ThreadState.StopRequested:
case System.Threading.ThreadState.AbortRequested:
Thread.Sleep(2000); // 让线程工作一段时间
break;
case System.Threading.ThreadState.Suspended:
case System.Threading.ThreadState.SuspendRequested:
this.listenThread.Abort();
break;
case System.Threading.ThreadState.Background:
case System.Threading.ThreadState.Running:
this.listenThread.Join();
break;
}
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer Stop Called."));
}
catch (Exception e)
{
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Error, "UdpServer Stop Exception.", e));
}
System.GC.Collect();
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, "UdpServer Stoped Called System.GC.Collect."));
}
private void TaskRunning()
{
Task.Run(() =>
{
try
{
while (runing)
{
// 接收数据
this.receiveBytes = udpServer.Receive(ref localEndPoint);
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"Received {receiveBytes.Length} Bytes."));
//处理数据
HandleReceiveResposoneModel();
// 响应数据
if (sendBytes.Length > 0)
{
udpServer.Send(sendBytes, sendBytes.Length, localEndPoint);
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"Sented {receiveBytes.Length} Bytes."));
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Error, "Task.Run Receive Exception.", e));
}
});
}
private void HandleReceiveResposoneModel()
{
logBuffer.Enqueue(new LogContentV2(LogLevelV2.Infor, $"HandleReceiveResposoneModel"));
//this.receiveBytes;
//this.sendBytes;
string sendMessage = "Message received";
sendBytes = Encoding.UTF8.GetBytes(sendMessage);
}
}
internal class Program
{
static void Main(string[] args)
{
UdpServer udpServer = new UdpServer();
udpServer.Startup("127.0.0.1",8421);
Console.WriteLine("Press any key to stop the server");
Console.ReadKey();
udpServer.Stop();
}
}
}
namespace Notify.Log
{
public enum LogLevel
{
Trace = 0,
Debug = 1,
Information = 2,
Statistic = 3,
Warning = 4,
Mistake = 6, //轻微错误
Exception = 5,
Error = 7, //逻辑错误
Critical = 8, //严重错误
Fault = 9 //致命错误
}
public enum LogLevelV2
{
Infor = 2,
Excep = 5,
Error = 7,
}
//临时日志是写文本文件,这种操作在高并发程序里会造成程序崩溃
public class TempLog
{
//注意只有一个线程写,不能多个线程同时写文件。
static public void logging(List<NtLog> logbuf, string filepath = "./NotifyLog.log")
{
// 确保日志文件的目录存在
Directory.CreateDirectory(Path.GetDirectoryName(filepath));
// 使用StreamWriter写入日志
using (StreamWriter writer = new StreamWriter(filepath, true)) // true表示追加模式
{
//writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
// 这里可以添加更多的日志写入操作
//foreach (NtLog log in logbuf)
//{
// writer.WriteLine(log.ToString());
// 移除已经写了的缓存
// logbuf.Remove(log);//迭代器安全问题
//}
for (int i = 0; i < logbuf.Count; i++)
{
//#if DEBUG
// Console.WriteLine(logbuf[i].ToString());
//#endif
writer.WriteLine(logbuf[i].ToString());
logbuf.RemoveAt(i);
}
}
}
static public void logging(List<NtLog> logbuf)
{
string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"
string fullPath = Path.Combine("./logs", fileName);
// 确保日志文件的目录存在
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// 使用StreamWriter写入日志
using (StreamWriter writer = new StreamWriter(fullPath, true)) // true表示追加模式
{
//writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
// 这里可以添加更多的日志写入操作
//foreach (NtLog log in logbuf)
//{
// writer.WriteLine(log.ToString());
// 移除已经写了的缓存
// logbuf.Remove(log);//迭代器安全问题
//}
for (int i = 0; i < logbuf.Count; i++)
{
#if DEBUG
Console.WriteLine(logbuf[i].ToString());
#endif
writer.WriteLine(logbuf[i].ToString());
logbuf.RemoveAt(i);
}
}
}
static public void logging(string message, string logpath)
{
using (StreamWriter writer = new StreamWriter(logpath, true)) // true表示追加模式
{
//string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"
string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
writer.WriteLine(content);
}
}
static public void logging(string message)
{
string path = AppDomain.CurrentDomain.BaseDirectory;
using (StreamWriter writer = new StreamWriter(path + "//TempLog.log", true)) // true表示追加模式
{
//string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"
string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
writer.WriteLine(content);
}
}
}
public class LogContentV2
{
public DateTime Occurrence { get; set; }
public LogLevelV2 LevelV2 { get; set; }
public StackTrace Trace { get; set; }
public string Message { get; set; }
public LogContentV2() { }
public LogContentV2(LogLevelV2 level, string message)
{
this.Occurrence = DateTime.Now;
this.LevelV2 = level;
this.Trace = new StackTrace(true);//捕捉当前堆栈
this.Message = message;
}
public LogContentV2(LogLevelV2 level, string message, Exception e)
{
this.Occurrence = DateTime.Now;
this.LevelV2 = level;
this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
this.Message = message;
}
public override string ToString()
{
return $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.ffff")} {LevelV2.ToString()}:{Message}";//因为ffff会确保输出始终是4位数字,不足的部分用零填充。
}
}
public class LogContent
{
public DateTime Occurrence { get; set; }
public LogLevel Level { get; set; }
public StackTrace Trace { get; set; }
public string Message { get; set; }
public LogContent() { }
public LogContent(LogLevel level, string message)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(true);//捕捉当前堆栈
this.Message = message;
}
public LogContent(LogLevel level, string message, Exception e)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
this.Message = message;
}
public override string ToString()
{
//string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
//string tmp = $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF")} {Level.ToString()} {Message}";
//return tmp;
return $"{Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF")} {Level.ToString()}:{Message}";
}
}
public class LogContentX
{
public DateTime Occurrence { get; set; }
public LogLevel Level { get; set; }
public StackTrace Trace { get; set; }
public string Message { get; set; }
public LogContentX() { }
public LogContentX(LogLevel level, string message) { this.SetLog(level, message); }
public LogContentX(LogLevel level, string message, Exception e) { this.SetLog(level, message, e); }
public void SetLog(LogLevel level, string message)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(true);//捕捉当前堆栈
this.Message = message;
}
public void SetLog(LogLevel level, string message, Exception e)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
this.Message = message;
}
public override string ToString()
{
string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
return tmp;
}
public string TraceDetail()
{
string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
tmp += this.Trace.ToString() + "\r\n";
//StackFrame sf = Trace.GetFrame(0);
//tmp += $" Method: {sf.GetMethod()}\r\n";
//$" File: {sf.GetFileName()}\r\n" +
//$" Line Number: {sf.GetFileLineNumber()}\r\n";
return tmp;
}
public static string TraceDetail(LogContent log)
{
string tmp = log.Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + " " + log.Level.ToString() + ":" + log.Message + "\n";
tmp += log.Trace.ToString() + "\r\n";
//StackFrame sf = Trace.GetFrame(0);
//tmp += $" Method: {sf.GetMethod()}\r\n";
//$" File: {sf.GetFileName()}\r\n" +
//$" Line Number: {sf.GetFileLineNumber()}\r\n";
return tmp;
}
public string TraceTopFrame()
{
return this.Trace.GetFrame(0).ToString();
}
public StackFrame TraceTopStackFrame()
{
return Trace.GetFrame(0);
}
public StackFrame TraceBottomStackFrame()
{
return Trace.GetFrame(this.Trace.FrameCount - 1);
}
public int GetSize()
{
//在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
// Each character in a string is 2 bytes (UTF-16 encoding).
int total = sizeof(LogLevel) + this.Message.Length * 2 + 8;
for (int i = 0; i < this.Trace.FrameCount; i++)
{
StackFrame sf = this.Trace.GetFrame(i);
//sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name;
total += sf.ToString().Length * 2;
}
return total;
}
public static int GetSize(LogContent log)
{
//在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
// Each character in a string is 2 bytes (UTF-16 encoding).
int total = sizeof(LogLevel) + log.Message.Length * 2 + 8;
for (int i = 0; i < log.Trace.FrameCount; i++)
{
StackFrame sf = log.Trace.GetFrame(i);
//sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name;
total += sf.ToString().Length * 2;
}
return total;
}
}
public class LogBuffer
{
protected List<LogContent> buf = new List<LogContent>();
public List<LogContent> Buffer { get { return buf; } }
public LogBuffer()
{
buf = new List<LogContent>();
}
public LogBuffer(List<LogContent> buf)
{
this.buf = buf;
}
public void Insert(LogContent log)
{
this.buf.Add(log);
}
public void Insert(LogBuffer log)
{
foreach (var item in log.Buffer)
{
this.buf.Add(item);
}
}
public int LogSize()
{
int size = 0;
foreach (LogContent cnt in this.buf)
{
size += LogContentX.GetSize(cnt);
}
return size;
}
}
public class LogBufQuery
{
public List<LogContent> Buffer { get; set; }
public void TimeOrderAsc()
{
Buffer.Sort((x, y) => x.Occurrence.CompareTo(y.Occurrence));
}
public void TimeOrderDsc()
{
Buffer.Sort((x, y) => y.Occurrence.CompareTo(x.Occurrence));
}
public List<LogContent> FilterByLoglevel(LogLevel loglevel)
{
return Buffer.FindAll(log => log.Level == loglevel);
}
}
public struct logstatics
{
public string item;
public string value;
public long Timestamp;
// 将 UNIX 时间戳转换为 DateTime
//DateTime dateTime = DateTimeOffset.FromUnixTimeSeconds(Timestamp).DateTime;
public DateTime FromUnixTime()
{
return DateTimeOffset.FromUnixTimeSeconds(Timestamp).DateTime;
}
}
public class TotalAccessSattistic
{
private ulong totalAccess;
/// <summary>
/// 总访问量
/// </summary>
public ulong TotalAccess
{
get
{
return this.totalAccess;
}
}
private void Reset()
{ this.totalAccess = 0; }
public void StasticAccess(List<LogContent> buf, string flagstr = "HandleClientComm")
{
foreach (var cnt in buf)
{
if (cnt.Message == flagstr)
this.totalAccess++;
}
}
}
//将日志写成文本文件,注意在多线程环境下要排除线程互斥。
public class NtLog
{
//private Queue<LogBuffer> Buff = new Queue<LogBuffer>();
private Queue<LogContent> buffer = new Queue<LogContent>();
public string LogPath { get; }
private string curfilepath = string.Empty;
private string errorLgFile = string.Empty; //定义从Exception到Fault这5个层级为Error
private Task task; //不要删除,多线程写日志时会用到
private Stopwatch watcher = new Stopwatch();
private long maxms, minms, lastms;
private volatile bool IsWriting = false;
public bool Writing { get { return IsWriting; } }
/// <summary>
/// 平均耗时
/// </summary>
public long AverageConsum
{
get
{
return (maxms + minms + lastms) / 3;
}
}
public NtLog()
{
this.LogPath = AppDomain.CurrentDomain.BaseDirectory;
创建日志文件夹
this.LogPath = CreateLogDirectory();
MakeLogFileName();
maxms = minms = lastms = 0;
}
public void Enqueue(LogContent log)
{
this.buffer.Enqueue(log);
}
public void Enqueue(List<LogContent> logs)
{
foreach (LogContent log in logs)
{
this.buffer.Enqueue(log);
}
}
public void Enqueue(LogBuffer logbuf)
{
foreach (LogContent log in logbuf.Buffer)
{
this.buffer.Enqueue(log);
}
}
public void OnLogging(List<LogContent> logs)
{
//#if DEBUG
// TempLog.logging($"查看原始数据。{logs.Count} ");//{logs.First().Message}
//#endif
//this.Buff.Enqueue(new LogBuffer(logs));
this.Enqueue(logs);
this.UpdatePathFileName();
if (this.IsWriting == false && this.buffer.Count > 0)
{
//LogBuffer Temp = this.Buff.Dequeue();
//while (this.Buff.Count > 0)
//{
// Temp.Insert(this.Buff.Dequeue());
//}
WriteLogByThreadV4(this.buffer);
}
}
public void OnLogging(Queue<LogContent> logs)
{
for (int i = 0; i < logs.Count; i++)
{
this.buffer.Enqueue(logs.Dequeue());
}
this.UpdatePathFileName();
if (this.IsWriting == false && this.buffer.Count > 0)
{
//LogBuffer Temp = this.Buff.Dequeue();
//while (this.Buff.Count > 0)
//{
// Temp.Insert(this.Buff.Dequeue());
//}
WriteLogByThreadV4(this.buffer);
}
}
public static string CreateLogDirectory()
{
string path = AppDomain.CurrentDomain.BaseDirectory;
// 获取当前应用程序域的名称(通常是程序集名称)
string assemblyName = AppDomain.CurrentDomain.FriendlyName;
// 去掉路径和扩展名,只保留文件名
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
// 组合成完整的路径
path = System.IO.Path.Combine(path, assemblyName + "Log");
//TempLog.logging(path);
//创建日志文件夹
Directory.CreateDirectory(path);
return path;
}
public void UpdatePathFileName()
{
string path = AppDomain.CurrentDomain.BaseDirectory;
// 获取当前应用程序域的名称(通常是程序集名称)
string assemblyName = AppDomain.CurrentDomain.FriendlyName;
// 去掉路径和扩展名,只保留文件名
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
// 组合成完整的路径
path = System.IO.Path.Combine(path, assemblyName + "Log");
//TempLog.logging(path);
//创建日志文件夹
Directory.CreateDirectory(path);
string dn = DateTime.Now.ToString("yyyy-MM-dd");
this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
}
public void MakeLogFileName()
{
// 获取当前应用程序域的名称(通常是程序集名称)
string assemblyName = AppDomain.CurrentDomain.FriendlyName;
// 去掉路径和扩展名,只保留文件名
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
string dn = DateTime.Now.ToString("yyyy-MM-dd");
this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
}
public void WriteLogFile()
{
using (StreamWriter writer = new StreamWriter(this.curfilepath, true)) // true表示追加模式
{
foreach (var cnt in this.buffer)
{
writer.WriteLine(cnt.ToString());
}
}
}
public void WriteErrorLog()
{
using (StreamWriter writer = new StreamWriter(this.errorLgFile, true)) // true表示追加模式
{
foreach (var cnt in this.buffer)
{
if (cnt.Level >= LogLevel.Warning)
writer.WriteLine(LogContentX.TraceDetail(cnt));
}
}
}
//发现它仍然阻塞主线程
//注意只有一个线程写,不能多个线程同时写文件。
//请注意,Buffer.Remove(cnt) 在循环中可能会导致问题,因为从集合中移除元素会改变集合的大小,从而可能导致迭代器失效。为了避免这个问题,可以先收集需要删除的元素,然后在循环结束后统一删除它们。
public void WriteLogByThread(LogBuffer logs)
{
this.watcher.Start();
this.IsWriting = true;
//#if DEBUG
// TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
//#endif
//this.WriteLogFile
// 使用Task.Run在后台线程中执行文件写入操作
this.task = Task.Run(() =>
{
//FileStream可以设置成独享锁定模式,防止 线程互斥
using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None),
fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer = new StreamWriter(fs1), writer2 = new StreamWriter(fs2))
{
foreach (var cnt in logs.Buffer)
{
writer.WriteLine(cnt.ToString());
if (cnt.Level >= LogLevel.Warning)
writer2.WriteLine(LogContentX.TraceDetail(cnt));
}
}
}
//Buffer没有上锁是希望它尽快完成操作,但有风险
});
this.watcher.Stop();
this.IsWriting = false;
if (this.lastms > 0 && this.lastms > this.maxms)
{
this.maxms = this.lastms;
}
if (this.lastms > 0 && this.minms == 0)
this.minms = this.lastms;
if (this.lastms > 0 && this.lastms < this.minms)
{
this.minms = this.lastms;
}
this.lastms = watcher.ElapsedMilliseconds;
}
//如果没有errlog就不写
public void WriteLogByThreadV2(LogBuffer logs)
{
this.watcher.Start();
this.IsWriting = true;
Queue<LogContent> errlogs = new Queue<LogContent>();
//#if DEBUG
// TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
//#endif
//this.WriteLogFile
// 使用Task.Run在后台线程中执行文件写入操作
this.task = Task.Run(() =>
{
//FileStream可以设置成独享锁定模式,防止 线程互斥
using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer = new StreamWriter(fs1))
{
foreach (var cnt in logs.Buffer)
{
writer.WriteLine(cnt.ToString());
if (cnt.Level >= LogLevel.Warning)
errlogs.Enqueue(cnt);
}
}
}
if (errlogs.Count > 0)
{
using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer2 = new StreamWriter(fs2))
{
for (int i = 0; i < errlogs.Count; i++)
{
writer2.WriteLine(errlogs.Dequeue().ToString());
}
}
}
}
//Buffer没有上锁是希望它尽快完成操作,但有风险
});
this.watcher.Stop();
this.IsWriting = false;
if (this.lastms > 0 && this.lastms > this.maxms)
{
this.maxms = this.lastms;
}
if (this.lastms > 0 && this.minms == 0)
this.minms = this.lastms;
if (this.lastms > 0 && this.lastms < this.minms)
{
this.minms = this.lastms;
}
this.lastms = watcher.ElapsedMilliseconds;
}
public void WriteLogByThreadV3(Queue<LogContent> queue)
{
this.watcher.Start();
this.IsWriting = true;
Queue<LogContent> errlogs = new Queue<LogContent>();
//#if DEBUG
// TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
//#endif
//this.WriteLogFile
// 使用Task.Run在后台线程中执行文件写入操作
this.task = Task.Run(() =>
{
//FileStream可以设置成独享锁定模式,防止 线程互斥
using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer = new StreamWriter(fs1))
{
//foreach (var cnt in queue)
//{
// writer.WriteLine(cnt.ToString());
// ;
// if (cnt.Level >= LogLevel.Warning)
// errlogs.Enqueue(cnt);
//}
while (queue.Count > 0)
{
var tmp = queue.Dequeue();
writer.WriteLine(tmp.ToString());
if (tmp.Level >= LogLevel.Warning)
errlogs.Enqueue(tmp);
}
}
}
if (errlogs.Count > 0)
{
using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer2 = new StreamWriter(fs2))
{
for (int i = 0; i < errlogs.Count; i++)
{
writer2.WriteLine(errlogs.Dequeue().ToString());
}
}
}
}
//Buffer没有上锁是希望它尽快完成操作,但有风险
});
this.watcher.Stop();
this.IsWriting = false;
if (this.lastms > 0 && this.lastms > this.maxms)
{
this.maxms = this.lastms;
}
if (this.lastms > 0 && this.minms == 0)
this.minms = this.lastms;
if (this.lastms > 0 && this.lastms < this.minms)
{
this.minms = this.lastms;
}
this.lastms = watcher.ElapsedMilliseconds;
}
public void WriteLogByThreadV4(Queue<LogContent> queue)
{
this.watcher.Start();
this.IsWriting = true;
Queue<LogContent> errlogs = new Queue<LogContent>();
//#if DEBUG
// TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
//#endif
//this.WriteLogFile
// 使用Task.Run在后台线程中执行文件写入操作
this.task = Task.Run(() =>
{
//FileStream可以设置成独享锁定模式,防止 线程互斥
using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer = new StreamWriter(fs1))
{
//foreach (var cnt in queue)
//{
// writer.WriteLine(cnt.ToString());
// ;
// if (cnt.Level >= LogLevel.Warning)
// errlogs.Enqueue(cnt);
//}
while (queue.Count > 0)
{
var tmp = queue.Dequeue();
writer.WriteLine(tmp.ToString());
if (tmp.Level >= LogLevel.Warning)
errlogs.Enqueue(tmp);
}
}
}
if (errlogs.Count > 0)
{
using (FileStream fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer2 = new StreamWriter(fs2))
{
for (int i = 0; i < errlogs.Count; i++)
{
writer2.WriteLine(LogContentX.TraceDetail(errlogs.Dequeue()));
}
}
}
}
//Buffer没有上锁是希望它尽快完成操作,但有风险
});
this.watcher.Stop();
this.IsWriting = false;
if (this.lastms > 0 && this.lastms > this.maxms)
{
this.maxms = this.lastms;
}
if (this.lastms > 0 && this.minms == 0)
this.minms = this.lastms;
if (this.lastms > 0 && this.lastms < this.minms)
{
this.minms = this.lastms;
}
this.lastms = watcher.ElapsedMilliseconds;
}
}
}