Files
hjha-server/MrWu/Debug/LogPool.cs
xiaoou e9616125ce feat: initial commit - HJHA game server full source
6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) +
game logic (GameFix/GameDAL/ServerData) +
network layer (NetWorkMessage) +
data layer (ObjectModel) +
utilities (MrWu/Core/Config/CloudAPI/dll) +
adapters (zyxAdapter/base)

.NET 8.0 C# solution, 16 projects, 958 source files
2026-07-07 12:02:15 +08:00

873 lines
30 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************
*
* 作者:吴隆健
* 创建时间: 2019-06-09 10:31:40
*
********************************/
using MrWu.Time;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MrWu.Debug
{
/// <summary>
/// 日志池
/// </summary>
public class LogPool : IDebug
{
private LogPool(LogConfig config) {
this.config = config;
var now = DateTime.Now;
//if(!string.IsNullOrEmpty(config.logpath)) {
logWriter = GetWriter(now);
//}
// 下一版再启用
var dueTime = (int)(now.Date.AddDays(1) - now).TotalMilliseconds;
//var dueTime = (int)(now.AddMinutes(1) - now).TotalMilliseconds; //测试
var period = (int)TimeSpan.FromDays(1).TotalMilliseconds;
this.logTaskTimer = new Timer(ZeroTask, null, dueTime, period);
}
/// <summary>
/// 零时任务
/// </summary>
/// <param name="obj"></param>
void ZeroTask(object obj) {
var now = DateTime.Now;
SwitchWriter(now);
DeleteOutdateLogFiles(now);
}
/// <summary>
/// 更换 logWriter
/// </summary>
/// <param name="now">当前时间</param>
void SwitchWriter(DateTime now) {
using (var oldWriter = this.logWriter) {
var newWriter = GetWriter(now);
this.logWriter = newWriter;
oldWriter.Flush();
}
}
/// <summary>
/// 删除过期日志文件
/// </summary>
/// <param name="now">当前时间</param>
void DeleteOutdateLogFiles(DateTime now) {
var logFiles = new DirectoryInfo(Directory.GetCurrentDirectory() + "/logs").GetFiles("*.log");
var outDateLogs = logFiles.Where(p => p.CreationTime.AddDays(config.remainDays) < now).ToList();
outDateLogs.ForEach(p => {
try {
p.Delete();
} catch (Exception ex) {
AddLog($"删除过时日志文件时发生异常!\t{ex.Message}", DebugLevel.Warning);
}
});
}
StreamWriter GetWriter(DateTime dateTime) {
string path = Directory.GetCurrentDirectory() + "/logs";
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
return new StreamWriter(path + "/" + getLogFileName(dateTime)/*, false, Encoding.UTF8, 300 * 1024*/);
}
/// <summary>
/// 定时任务 Timer
/// </summary>
Timer logTaskTimer {
get;
}
string getLogFileName(DateTime curDatetime) {
return curDatetime.TimeToString(TimeStyle.MMddhhmmss, string.Empty, string.Empty, string.Empty) + ".log";
}
/// <summary>
/// 实例
/// </summary>
private static LogPool instance;
/// <summary>
/// 启动
/// </summary>
/// <param name="config"></param>
public static void Start(LogConfig config) {
if (config != null) {
instance = new LogPool(config);
saveLevel = config.saveLevel;
Debug.Start(instance, config.logLevel);
}
}
/// <summary>
/// 日志流
/// </summary>
private StreamWriter logWriter {
get; set;
}
/// <summary>
/// 配置
/// </summary>
public readonly LogConfig config;
/// <summary>
/// 日志
/// </summary>
// private readonly List<LogMessage> logs = new List<LogMessage>();
private readonly Queue<LogMessage> logs = new Queue<LogMessage>();
/// <summary>
/// 重要信息
/// </summary>
private readonly Queue<LogMessage> Infos = new Queue<LogMessage>();
/// <summary>
/// 警告
/// </summary>
private readonly Queue<LogMessage> warnings = new Queue<LogMessage>();
/// <summary>
/// 重要日志
/// </summary>
private readonly Queue<LogMessage> ImportantLogs = new Queue<LogMessage>();
/// <summary>
/// 错误
/// </summary>
private readonly Queue<LogMessage> errors = new Queue<LogMessage>();
/// <summary>
/// 致命的错误
/// </summary>
private readonly Queue<LogMessage> Fatals = new Queue<LogMessage>();
private readonly object logidLock = new object();
private ulong _logid = 0;
private ulong logid {
get {
ulong value;
lock (logidLock) {
_logid++;
value = _logid;
}
return value;
}
}
private ulong GetLogId() {
lock (logidLock) {
return _logid;
}
}
/// <summary>
/// 日志缓存数量
/// </summary>
public int logCacheCount => config.logCacheCount;
/// <summary>
/// 信息缓存数量
/// </summary>
public int InfoCacheCount => config.InfoCacheCount;
/// <summary>
/// 警告缓存数量
/// </summary>
public int warningCacheCount => config.warningCacheCount;
/// <summary>
/// 重要日志数量
/// </summary>
public int ImportantLogCaheCount => config.ImportantLogCacheCount;
/// <summary>
/// 错误数量
/// </summary>
public int errorCacheCount => config.errorCacheCount;
/// <summary>
/// 致命错误
/// </summary>
public int FatalCacheCount => config.FatalCacheCount;
private static ulong _logCount;
/// <summary>
/// 日志数量
/// </summary>
public static ulong logCount {
get {
return _logCount;
}
private set {
_logCount = value;
}
}
private static ulong _InfoCount;
/// <summary>
/// 信息数量
/// </summary>
public static ulong InfoCount {
get {
return _InfoCount;
}
private set {
_InfoCount = value;
}
}
private static ulong _warningCount;
/// <summary>
/// 警告数量
/// </summary>
public static ulong warningCount {
get => _warningCount;
private set {
_warningCount = value;
}
}
private static ulong _ImportantlogCount;
/// <summary>
/// 重要日志数量
/// </summary>
public static ulong ImportantlogCount {
get => _ImportantlogCount;
private set {
_ImportantlogCount = value;
}
}
private static ulong _errorCount;
/// <summary>
/// 错误总数量
/// </summary>
public static ulong errorCount {
get => _errorCount;
private set {
_errorCount = value;
}
}
private static ulong _fatalCount;
/// <summary>
/// 致命错误数量
/// </summary>
public static ulong fatalCount {
get => _fatalCount;
private set {
_fatalCount = value;
}
}
/// <summary>
/// 锁定物体
/// </summary>
private readonly object lockObj = new object();
/// <summary>
/// 锁写日志
/// </summary>
private readonly object lockWrite = new object();
/// <summary>
/// 锁定日志临时缓存
/// </summary>
private readonly object locktmpCache = new object();
/// <summary>
/// 临时缓存日志
/// </summary>
private Queue<LogMessage> tmpCachelog = new Queue<LogMessage>();
/// <summary>
/// 保存日志
/// </summary>
public static DebugLevel saveLevel {
get {
return m_saveLevel;
}
set {
m_saveLevel = value;
if(SaveLevelChange != null)
SaveLevelChange(m_saveLevel);
}
}
private static DebugLevel m_saveLevel;
/// <summary>
/// 保存日志的等级变化事件
/// </summary>
public static event Action<DebugLevel> SaveLevelChange;
/// <summary>
/// 手动刷新日志文本
/// </summary>
public static void Flush() {
if (instance != null) {
instance.FlushFile();
}
}
/// <summary>
/// 刷新日志文件
/// </summary>
private void FlushFile() {
var writer = this.logWriter;
if (writer != null) {
lock (lockWrite) {
writer.Flush();
}
}
}
/// <summary>
/// 接收到日志
/// </summary>
/// <param name="str">日志内容</param>
/// <param name="level">日志等级 1 普通日志 5警告 10错误日志</param>
public void AddLog(string str, DebugLevel level) {
LogMessage msg = new LogMessage(logid, level, str);
var writer = this.logWriter;
if (writer != null && ((level & saveLevel) != 0)) {
lock (lockWrite) {
writer.WriteLine(msg.logstr);
writer.Flush();
}
}
//Task.Factory.StartNew(
// () => {
//下一版再启用! 挪到外部处理走事件
//CollectLoggings.Enqueue(msg);
//if (CollectLoggings.Count > 500000) {
// //暂存周期为5分钟日志容器容量为150000预估最大日志量3000条 / 每分钟, 足够容纳10个周期的日志量超期的将不会提交到日志收集模块而被丢弃但本地保存
// CollectLoggings.TryDequeue(out var _);
//}
lock (locktmpCache) {
tmpCachelog.Enqueue(msg);
}
lock (lockObj) {
switch (level) { //设置日志数量
case DebugLevel.Log:
logCount++;
ReleaseFrist(logs, msg, logCacheCount);
break;
case DebugLevel.Info:
logCount++;
ReleaseFrist(Infos, msg, InfoCacheCount);
break;
case DebugLevel.Warning:
warningCount++;
ReleaseFrist(warnings, msg, warningCacheCount);
break;
case DebugLevel.ImportantLog:
ImportantlogCount++;
ReleaseFrist(ImportantLogs, msg, ImportantLogCaheCount);
break;
case DebugLevel.Error:
errorCount++;
ReleaseFrist(errors, msg, errorCacheCount);
break;
case DebugLevel.Fatal:
fatalCount++;
ReleaseFrist(Fatals, msg, FatalCacheCount);
break;
}
}
// }
//);
}
/*
/// <summary>
/// 如果超过限制,移除并释放第一个
/// </summary>
/// <param name="list"></param>
/// <param name="newLog"></param>
/// <param name="limit"></param>
void ReleaseFrist(List<LogMessage> list, LogMessage newLog, int limit) {
list.Add(newLog);
if (list.Count > limit) {
//var log = list[0];
list.RemoveAt(0);
}
}
*/
/// <summary>
/// 如果超过限制,移除并释放第一个
/// </summary>
/// <param name="list"></param>
/// <param name="newLog"></param>
/// <param name="limit"></param>
void ReleaseFrist(Queue<LogMessage> list, LogMessage newLog, int limit) {
list.Enqueue(newLog);
if (list.Count > limit) {
//var log = list[0];
list.Dequeue();
}
}
/// <summary>
/// 上次获取日志的等级
/// </summary>
private DebugLevel lastGetLevel = (DebugLevel)(-1);
/// <summary>
/// 日志id
/// </summary>
private ulong log_id = 0;
private ulong Info_id = 0;
/// <summary>
/// 警告id
/// </summary>
private ulong warning_id = 0;
/// <summary>
/// 重要日志
/// </summary>
private ulong ImportantLog_id = 0;
/// <summary>
/// 错误id
/// </summary>
private ulong error_id = 0;
/// <summary>
/// 致命的id
/// </summary>
private ulong fatal_id = 0;
/// <summary>
/// 获取这段时间的日志
/// </summary>
/// <param name="tmplogs"></param>
/// <param name="tmpinfos"></param>
/// <param name="tmpwarnings"></param>
/// <param name="tmpimportantLogs"></param>
/// <param name="tmperrors"></param>
/// <param name="tmpfatal"></param>
/// <param name="level"></param>
/// <returns></returns>
private string ResetlogStrs(List<LogMessage> tmplogs, List<LogMessage> tmpinfos, List<LogMessage> tmpwarnings, List<LogMessage> tmpimportantLogs, List<LogMessage> tmperrors, List<LogMessage> tmpfatal, DebugLevel level) {
void setlogsId(List<LogMessage> _logs, List<LogMessage> _infos, List<LogMessage> _warnings,
List<LogMessage> _importantLogs, List<LogMessage> _errors, List<LogMessage> _fatals) {
if (_logs.Count == 0)
log_id = 0;
else
log_id = _logs[_logs.Count - 1].logid;
if (_infos.Count == 0)
Info_id = 0;
else
Info_id = _infos[_infos.Count - 1].logid;
if (_warnings.Count == 0)
warning_id = 0;
else
warning_id = _warnings[_warnings.Count - 1].logid;
if (_importantLogs.Count == 0)
ImportantLog_id = 0;
else
ImportantLog_id = _importantLogs[_importantLogs.Count - 1].logid;
if (_errors.Count == 0)
error_id = 0;
else
error_id = _errors[_errors.Count - 1].logid;
if (_fatals.Count == 0)
fatal_id = 0;
else
fatal_id = _fatals[_fatals.Count - 1].logid;
}
StringBuilder logStrs = new StringBuilder();
lastGetLevel = level;
bool islog = (tmplogs.Count > 0) && ((lastGetLevel & DebugLevel.Log) != 0);
bool isInfo = (tmpinfos.Count > 0) && ((lastGetLevel & DebugLevel.Info) != 0);
bool isWarning = (tmpwarnings.Count > 0) && ((lastGetLevel & DebugLevel.Warning) != 0);
bool isImportantLog = (tmpimportantLogs.Count > 0) && ((lastGetLevel & DebugLevel.ImportantLog) != 0);
bool isError = (tmperrors.Count > 0) && ((lastGetLevel & DebugLevel.Error) != 0);
bool isFatal = (tmpfatal.Count > 0) && ((lastGetLevel & DebugLevel.Fatal) != 0);
int logidx = 0;
int infoIdx = 0;
int warningidx = 0;
int ImportantLogIdx = 0;
int erroridx = 0;
int fatalIdx = 0;
DebugLevel mingDebugLevel = (DebugLevel)0;
ulong minlogidValue = ulong.MaxValue;
while (true) {
if (islog) {
if (tmplogs[logidx].logid < minlogidValue) {
minlogidValue = tmplogs[logidx].logid;
mingDebugLevel = DebugLevel.Log;
}
}
if (isInfo) {
if (tmpinfos[infoIdx].logid < minlogidValue) {
minlogidValue = tmpinfos[infoIdx].logid;
mingDebugLevel = DebugLevel.Info;
}
}
if (isWarning) {
if (tmpwarnings[warningidx].logid < minlogidValue) {
minlogidValue = tmpwarnings[warningidx].logid;
mingDebugLevel = DebugLevel.Warning;
}
}
if (isImportantLog) {
if (tmpimportantLogs[ImportantLogIdx].logid < minlogidValue) {
minlogidValue = tmpimportantLogs[ImportantLogIdx].logid;
mingDebugLevel = DebugLevel.ImportantLog;
}
}
if (isError) {
if (tmperrors[erroridx].logid < minlogidValue) {
minlogidValue = tmperrors[erroridx].logid;
mingDebugLevel = DebugLevel.Error;
}
}
if (isFatal) {
if (tmpfatal[fatalIdx].logid < minlogidValue) {
minlogidValue = tmpfatal[fatalIdx].logid;
mingDebugLevel = DebugLevel.Fatal;
}
}
switch (mingDebugLevel) {
case DebugLevel.Log:
logStrs.AppendLine(tmplogs[logidx++].logstr);
break;
case DebugLevel.Info:
logStrs.AppendLine(tmpinfos[infoIdx++].logstr);
break;
case DebugLevel.Warning:
logStrs.AppendLine(tmpwarnings[warningidx++].logstr);
break;
case DebugLevel.ImportantLog:
logStrs.AppendLine(tmpimportantLogs[ImportantLogIdx++].logstr);
break;
case DebugLevel.Error:
logStrs.AppendLine(tmperrors[erroridx++].logstr);
break;
case DebugLevel.Fatal:
logStrs.AppendLine(tmpfatal[fatalIdx++].logstr);
break;
}
if (logidx >= tmplogs.Count)
islog = false;
if (infoIdx >= tmpinfos.Count)
isInfo = false;
if (warningidx >= tmpwarnings.Count)
isWarning = false;
if (ImportantLogIdx >= tmpimportantLogs.Count)
isImportantLog = false;
if (erroridx >= tmperrors.Count)
isError = false;
if (fatalIdx >= tmpfatal.Count)
isFatal = false;
if (!islog && !isWarning && !isError && !isInfo && !isImportantLog && !isFatal)
break;
minlogidValue = long.MaxValue;
}
setlogsId(tmplogs, tmpinfos, tmpwarnings, tmpimportantLogs, tmperrors, tmpfatal);
lock (locktmpCache) {
tmpCachelog.Clear();
}
return logStrs.ToString();
}
private StringBuilder incLogCache = new StringBuilder();
/// <summary>
/// 增量获取日志
/// </summary>
private string AddLogs() {
Queue<LogMessage> tmp;
lock (locktmpCache) {
tmp = tmpCachelog;
tmpCachelog = new Queue<LogMessage>();
}
while (tmp.Count > 0) {
incLogCache.AppendLine(tmp.Dequeue().logstr);
}
string result = incLogCache.ToString();
if (result == null)
result = string.Empty;
incLogCache.Clear();
return result;
/*
StringBuilder logStrs = new StringBuilder();
bool islog = (logs.Count > 0) && ((lastGetLevel & DebugLevel.Log) != 0);
bool isInfo = (Infos.Count > 0) && ((lastGetLevel & DebugLevel.Info) != 0);
bool isWarning = (warnings.Count > 0) && ((lastGetLevel & DebugLevel.Warning) != 0);
bool isImportantLog = (ImportantLogs.Count > 0) && ((lastGetLevel & DebugLevel.ImportantLog) != 0);
bool isError = (errors.Count > 0) && ((lastGetLevel & DebugLevel.Error) != 0);
bool isFatal = (Fatals.Count > 0) && ((lastGetLevel & DebugLevel.Fatal) != 0);
//增量如何删除
DebugLevel mingDebugLevel = (DebugLevel)0;
ulong minlogidValue = ulong.MaxValue;
int logidx = 0;
int infoidx = 0;
int warningidx = 0;
int importantIdx = 0;
int erroridx = 0;
int fatalidx = 0;
if (islog) {
for (int i = logs.Count - 1; i >= 0; i--) {
if (logs[i].logid == log_id) {
logidx = i + 1;
break;
}
}
islog = logidx < logs.Count;
}
if (isInfo) {
for (int i = Infos.Count - 1; i >= 0; i--) {
if (Infos[i].logid == Info_id) {
logidx = i + 1;
break;
}
}
isInfo = logidx < Infos.Count;
}
if (isWarning) {
for (int i = warnings.Count - 1; i >= 0; i--) {
if (warnings[i].logid == warning_id) {
warningidx = i + 1;
break;
}
}
isWarning = warningidx < warnings.Count;
}
if (isImportantLog) {
for (int i = ImportantLogs.Count - 1; i >= 0; i--) {
if (ImportantLogs[i].logid == ImportantLog_id) {
importantIdx = i + 1;
break;
}
}
isImportantLog = importantIdx < ImportantLogs.Count;
}
if (isError) {
for (int i = errors.Count - 1; i >= 0; i--) {
if (errors[i].logid == error_id) {
erroridx = i + 1;
break;
}
}
isError = erroridx < errors.Count;
}
if (isFatal) {
for (int i = Fatals.Count - 1; i >= 0; i--) {
if (Fatals[i].logid == fatal_id) {
fatalidx = i + 1;
break;
}
}
isFatal = fatalidx < Fatals.Count;
}
while (true) {
if (islog) {
if (logs[logidx].logid < minlogidValue) {
minlogidValue = logs[logidx].logid;
mingDebugLevel = DebugLevel.Log;
}
}
if (isInfo) {
if (Infos[infoidx].logid < minlogidValue) {
minlogidValue = Infos[infoidx].logid;
mingDebugLevel = DebugLevel.Info;
}
}
if (isWarning) {
if (warnings[warningidx].logid < minlogidValue) {
minlogidValue = warnings[warningidx].logid;
mingDebugLevel = DebugLevel.Warning;
}
}
if (isImportantLog) {
if (ImportantLogs[importantIdx].logid < minlogidValue) {
minlogidValue = ImportantLogs[importantIdx].logid;
mingDebugLevel = DebugLevel.ImportantLog;
}
}
if (isError) {
if (errors[erroridx].logid < minlogidValue) {
minlogidValue = errors[erroridx].logid;
mingDebugLevel = DebugLevel.Error;
}
}
if (isFatal) {
if (Fatals[fatalidx].logid < minlogidValue) {
minlogidValue = Fatals[fatalidx].logid;
mingDebugLevel = DebugLevel.Fatal;
}
}
switch (mingDebugLevel) {
case DebugLevel.Log:
logStrs.AppendLine(logs[logidx++].logstr);
break;
case DebugLevel.Info:
logStrs.AppendLine(Infos[infoidx++].logstr);
break;
case DebugLevel.Warning:
logStrs.AppendLine(warnings[warningidx++].logstr);
break;
case DebugLevel.ImportantLog:
logStrs.AppendLine(ImportantLogs[importantIdx++].logstr);
break;
case DebugLevel.Error:
logStrs.AppendLine(errors[erroridx++].logstr);
break;
case DebugLevel.Fatal:
logStrs.AppendLine(Fatals[fatalidx++].logstr);
break;
}
if (logidx >= logs.Count)
islog = false;
if (infoidx >= Infos.Count)
isInfo = false;
if (warningidx >= warnings.Count)
isWarning = false;
if (importantIdx >= ImportantLogs.Count)
isImportantLog = false;
if (erroridx >= errors.Count)
isError = false;
if (fatalidx >= Fatals.Count)
isFatal = false;
if (!islog && !isWarning && !isError && !isInfo && !isImportantLog && !isFatal)
break;
minlogidValue = long.MaxValue;
}
setlogsId();
return logStrs.ToString();
*/
}
/// <summary>
/// 获取日志_只获取增量
/// </summary>
/// <param name="level">日志等级</param>
/// <returns></returns>
public static string GetLog(DebugLevel level = DebugLevel.Log | DebugLevel.Warning | DebugLevel.Error) {
if (instance == null)
return string.Empty;
string result;
if (level != instance.lastGetLevel) {
List<LogMessage> tmplogs = null;
List<LogMessage> tmpinfos = null;
List<LogMessage> tmpwarnings = null;
List<LogMessage> tmpimportantLogs = null;
List<LogMessage> tmperrors = null;
List<LogMessage> tmpfatal = null;
lock (instance.lockObj) {
tmplogs = new List<LogMessage>(instance.logs);
tmpinfos = new List<LogMessage>(instance.Infos);
tmpwarnings = new List<LogMessage>(instance.warnings);
tmpimportantLogs = new List<LogMessage>(instance.ImportantLogs);
tmperrors = new List<LogMessage>(instance.errors);
tmpfatal = new List<LogMessage>(instance.Fatals);
}
result = instance.ResetlogStrs(tmplogs, tmpinfos, tmpwarnings, tmpimportantLogs, tmperrors, tmpfatal, level);
} else {
result = instance.AddLogs();
}
return result;
}
/*
/// <summary>
/// GetLoggings
/// </summary>
/// <param name="currentSeq">当前日志序号</param>
/// <returns></returns>
public static LogMessage[] GetLoggings(out ulong currentSeq) {
currentSeq = instance.GetLogId();
var seq = currentSeq;
return CollectLoggings.Where(p => p.logid <= seq).ToArray();
}
/// <summary>
/// 日志暂存容器,
/// </summary>
static ConcurrentQueue<LogMessage> CollectLoggings { get; } = new ConcurrentQueue<LogMessage>();
static ConcurrentDictionary<ulong, LogMessage> msgs { get; } = new ConcurrentDictionary<ulong, LogMessage>();
/// <summary>
/// ClearLogging
/// </summary>
/// <param name="currentSeq">日志序号</param>
public static void ClearLogging(ulong currentSeq) {
while (CollectLoggings.Count > 0) {
if (CollectLoggings.TryPeek(out var log)) {
if (log.logid <= currentSeq) {
CollectLoggings.TryDequeue(out log);
} else {
break;
}
} else {
break;
}
}
}
*/
}
}