jiannan.guo@yingxiong.com 1 month ago
parent
commit
b0e1eafaf7
  1. 28
      server/Sog/Core/Log/BattleLogConfig.cs
  2. 149
      server/Sog/Core/Log/BattleLogger.cs
  3. 86
      server/Sog/Core/Log/LogDef.cs
  4. 344
      server/Sog/Core/Log/LogWriteThread.cs
  5. 194
      server/Sog/Core/Log/Logger.cs
  6. 339
      server/Sog/Core/Log/ServerStat.cs
  7. 343
      server/Sog/Core/Log/TraceLog.cs
  8. 24
      server/Sog/Core/Log/UserLogConfig.cs
  9. 137
      server/Sog/Core/Log/UserLogger.cs

28
server/Sog/Core/Log/BattleLogConfig.cs

@ -0,0 +1,28 @@
using System.Runtime.Serialization;
namespace Sog.Log
{
public class BattleLogConfig
{
public string logname { get; set; }
/// <summary>
/// UserLog的等级
/// </summary>
public string loglevel { get; set; }
/// <summary>
/// 是否log全部User的日志
/// </summary>
public bool userlogAll { get; set; }
/// <summary>
/// User配置数组
/// </summary>
public long[] userlogSome { get; set; }
public bool logByBattleId { get; set; }
public string logpath { get; set; }
}
}

149
server/Sog/Core/Log/BattleLogger.cs

@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
namespace Sog.Log
{
public class BattleLogger
{
private static Dictionary<long, Logger> m_allUser = new Dictionary<long, Logger>();
private static Dictionary<ulong, Logger> m_allBattle = new Dictionary<ulong, Logger>();
public int m_logLevel;
private string m_logPath;
private string m_logFileName;
// 是否log所有玩家,外网请关闭
private bool m_logAllUser;
// 这个加了后就不会删,只是占用点内存,无所谓了
private long[] m_logSomeUser;
private bool m_logByBattleId;
public void Init(string path, string filename, int logLevel,
bool logAllUser, long[] logSomeUser, bool logByBattleId)
{
m_logLevel = logLevel;
m_logPath = path;
m_logFileName = filename;
m_logAllUser = logAllUser;
m_logSomeUser = logSomeUser;
m_logByBattleId = logByBattleId;
m_allUser.Clear();
m_allBattle.Clear();
}
public int GetLogLevel()
{
return m_logLevel;
}
public bool NeedLogUser(long uid)
{
if(m_logAllUser)
{
return true;
}
if(m_logSomeUser == null)
{
return false;
}
for (int i = 0; i < m_logSomeUser.Length; i++)
{
if (m_logSomeUser[i] == uid)
{
return true;
}
}
return false;
}
public void LogByLevel(long uid, ulong battleId, int frame, int logLevel, string strFormat, params object[] argvList)
{
//先判断等级
if (logLevel < m_logLevel)
{
return;
}
//这个uid是否需要log
if (! NeedLogUser(uid))
{
return;
}
Logger logger;
if (m_logByBattleId)
{
if (false == m_allBattle.TryGetValue(battleId, out logger))
{
logger = new Logger(m_logPath, m_logFileName + "_bt_" + battleId + ".log", m_logLevel);
m_allBattle.Add(battleId, logger);
}
}
else
{
if (false == m_allUser.TryGetValue(uid, out logger))
{
logger = new Logger(m_logPath, m_logFileName + "_uid_" + uid + ".log", m_logLevel);
m_allUser.Add(uid, logger);
}
}
if (OSUtils.IsWindows() == false)
{
// 在服务器上运行时,log不要影响逻辑
try
{
string strLog = string.Format(strFormat, argvList);
logger.WriteLogNoTime(logLevel, frame, strLog);
}
catch (Exception ex)
{
logger.WriteLog(logLevel, ex.Message);
logger.WriteLog(logLevel, ex.Source);
logger.WriteLog(logLevel, ex.StackTrace);
}
}
else
{
//windows版本,为了发现问题,log错误直接异常,不继续处理了
string strLog = string.Format(strFormat, argvList);
logger.WriteLogNoTime(logLevel, frame, strLog);
}
}
public void LogTraceDetail(long uid, ulong battleId, int frameCount, string strFormat, params object[] argvList)
{
LogByLevel(uid, battleId, frameCount, LogLevel.TraceDetail, strFormat, argvList);
}
public void LogTrace(long uid, ulong battleId, int frameCount, string strFormat, params object[] argvList)
{
LogByLevel(uid, battleId, frameCount, LogLevel.Trace, strFormat, argvList);
}
public void LogDebug(long uid, ulong battleId, int frameCount, string strFormat, params object[] argvList)
{
LogByLevel(uid, battleId, frameCount, LogLevel.Debug, strFormat, argvList);
}
public void LogError(long uid, ulong battleId, int frameCount, string strFormat, params object[] argvList)
{
LogByLevel(uid, battleId, frameCount, LogLevel.Error, strFormat, argvList);
}
public void LogFatal(long uid, ulong battleId, int frameCount, string strFormat, params object[] argvList)
{
LogByLevel(uid, battleId, frameCount, LogLevel.Fatal, strFormat, argvList);
}
}
}

86
server/Sog/Core/Log/LogDef.cs

@ -0,0 +1,86 @@
/*
Sog
2016 by zouwei
*/
namespace Sog.Log
{
/// <summary>
/// 日志等级定义和辅助方法
/// </summary>
public static class LogLevel
{
public const int Any = 0;
public const int TraceDetail = 1;
public const int Trace = 2;
public const int Debug = 3;
public const int Error = 4;
public const int Fatal = 5;
public const int None = 10;
public static string LevelToString(int logLevel)
{
switch (logLevel)
{
case LogLevel.TraceDetail:
return "L";
case LogLevel.Trace:
return "T";
case LogLevel.Debug:
return "D";
case LogLevel.Error:
return "E";
case LogLevel.Fatal:
return "F";
}
return "";
}
public static int ParseFromString(string strLevel)
{
if(string.IsNullOrEmpty(strLevel))
{
return LogLevel.Debug;
}
string lowStrLevel = strLevel.ToLower();
if (lowStrLevel == "tracedetail")
{
return LogLevel.TraceDetail;
}
else if (lowStrLevel == "trace")
{
return LogLevel.Trace;
}
else if(lowStrLevel == "debug")
{
return LogLevel.Debug;
}
else if(lowStrLevel == "error")
{
return LogLevel.Error;
}
else if(lowStrLevel == "fatal")
{
return LogLevel.Fatal;
}
else if(lowStrLevel == "none")
{
return LogLevel.None;
}
return LogLevel.Debug;
}
}
//改成static,允许修改
public class LogDefaultParam
{
public static int ShiftFileSize = 1024 * 1024 * 50; // 10M file shift
public static int ShiftFileCount = 5; //5 file
public static int CloseTimeoutLogFileTime = 300; // 多少秒后关闭没有再写请求的文件,释放句柄
}
}

344
server/Sog/Core/Log/LogWriteThread.cs

@ -0,0 +1,344 @@
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();
}
}
}

194
server/Sog/Core/Log/Logger.cs

@ -0,0 +1,194 @@
/*
Sog
2016 by zouwei
*/
using System;
using System.IO;
using System.Text;
namespace Sog.Log
{
/// <summary>
/// 日志文件读写操作
/// </summary>
public class Logger
{
private string m_filePathName;
private string m_LogPath;
private string m_LogFileName;
private int m_logLevel;
//是否滚动文件,缺省滚动,运营日志可关闭
private bool m_shiftFile = true;
public Logger(string logPath, string logFileName, int logLevel)
{
SetPathName(logPath, logFileName);
m_logLevel = logLevel;
}
public void SetPathName(string logPath, string logFileName)
{
m_LogPath = logPath;
m_LogFileName = logFileName;
m_filePathName = m_LogPath + "/" + logFileName;
try
{
//不存在则创建目录
if (!Directory.Exists(logPath))
{
Directory.CreateDirectory(logPath);
}
}
catch(Exception)
{
}
}
public void SetFileName(string logFileName)
{
m_LogFileName = logFileName;
m_filePathName = m_LogPath + "/" + logFileName;
}
public int GetLevel()
{
return m_logLevel;
}
public void SetLevel(int logLevel)
{
m_logLevel = logLevel;
}
public void CloseShift()
{
m_shiftFile = false;
}
/// <summary>
/// 不是绝对路径
/// </summary>
/// <returns></returns>
public string GetFileName()
{
return m_LogFileName;
}
internal void WriteLog(int logLevel, string strLog)
{
string logmessage = "[" + AppTime.ServerAppTime.GetDateTime().ToString("yyyy-MM-dd HH:mm:ss.fff") + "]" + LogLevel.LevelToString(logLevel) + "|" + strLog;
//补上一个回车
if(logmessage[logmessage.Length-1] != '\n')
{
logmessage += '\n';
}
LogWriteThread.Instance.WriteLog(m_filePathName, logmessage, m_shiftFile);
}
internal void WriteLogNoTime(int logLevel, int frame, string strLog)
{
string logmessage = string.Format("[{0}]{1}|{2}", frame, LogLevel.LevelToString(logLevel), strLog);
//补上一个回车
if (logmessage[logmessage.Length - 1] != '\n')
{
logmessage += '\n';
}
LogWriteThread.Instance.WriteLog(m_filePathName, logmessage, m_shiftFile);
}
/// <summary>
/// bill使用,写日志的时间由外部传入
/// 支持线程安全
/// </summary>
/// <param name="time"></param>
/// <param name="strLog"></param>
public void WriteLogWithTime(DateTime time, string strLog)
{
string logmessage = time.ToString("yyyy-MM-dd HH:mm:ss") + "|" + strLog + "\n";
LogWriteThread.Instance.WriteLog(m_filePathName, logmessage, m_shiftFile);
}
/// <summary>
/// TALog使用,写文件不需要打印时间
/// </summary>
/// <param name="strLog"></param>
public void WriteTALog(string strLog)
{
string logmessage = strLog + "\r\n";
LogWriteThread.Instance.WriteLog(m_filePathName, logmessage, m_shiftFile);
}
public void LogByLevel(int logLevel, string strFormat, params object[] argvList)
{
if (logLevel >= m_logLevel)
{
if(OSUtils.IsWindows() == false)
{
//外网版本,log错误不影响逻辑
try {
string strLog = string.Format(strFormat, argvList);
WriteLog(logLevel, strLog);
}
catch(Exception ex)
{
WriteLog(logLevel, ex.Message);
WriteLog(logLevel, ex.Source);
WriteLog(logLevel, ex.StackTrace);
}
}
else
{
//windows版本,为了发现问题,log错误直接异常,不继续处理了
string strLog = string.Format(strFormat, argvList);
WriteLog(logLevel, strLog);
}
}
}
public void LogByLevelNoFormat(int logLevel, string strMessage)
{
if (logLevel >= m_logLevel)
{
WriteLog(logLevel, strMessage);
}
}
public void LogTraceDetail(string strFormat, params object[] argvList)
{
LogByLevel(LogLevel.TraceDetail, strFormat, argvList);
}
public void LogTrace(string strFormat, params object[] argvList)
{
LogByLevel(LogLevel.Trace, strFormat, argvList);
}
public void LogDebug(string strFormat, params object[] argvList)
{
LogByLevel(LogLevel.Debug, strFormat, argvList);
}
public void LogError(string strFormat, params object[] argvList)
{
LogByLevel(LogLevel.Error, strFormat, argvList);
}
public void LogFatal(string strFormat, params object[] argvList)
{
LogByLevel(LogLevel.Fatal, strFormat, argvList);
}
public void LogDebugNoFormat(string strMessage)
{
LogByLevelNoFormat(LogLevel.Debug, strMessage);
}
}
}

339
server/Sog/Core/Log/ServerStat.cs

@ -0,0 +1,339 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Sog.Log
{
public class NetMsgStat
{
public int MsgID;
//发送数量
public int SendNum;
//发送的数据长度,字节
public long SendLength;
//接收数量
public int RecvNum;
//接收的数据长度,字节
public long RecvLength;
//接受消息总耗时
public long RecvTotalTime;
//接受消息最大耗时
public long RecvMaxTime;
//接受消息最小耗时
public long RecvMinTime;
public void Clear()
{
SendNum = 0;
SendLength = 0;
RecvNum = 0;
RecvLength = 0;
RecvTotalTime = 0;
RecvMaxTime = 0;
RecvMinTime = 0;
}
}
public class StatIDValue
{
public string ID;
public long Value;
//log后不清空,缺省都清空
public bool NotClearAfterLog;
}
/// <summary>
/// 服务器统计类
/// </summary>
public class ServerStat : Singleton<ServerStat>
{
//字符串为索引
private SortedDictionary<string, StatIDValue> m_statIDValuesMap;
//每个消息发送,接收信息
private SortedDictionary<int, NetMsgStat> m_statNetMsgMap;
private int TotalSendNum;
private int TotalRecvNum;
private long TotalSendLength;
private long TotalRecvLength;
private long m_lastLogTime;
private int m_logInterval;
private object m_threadLock = new object();
public ServerStat()
{
//缺省60秒log一次
m_logInterval = 60*1000;
m_statIDValuesMap = new SortedDictionary<string, StatIDValue>();
m_statNetMsgMap = new SortedDictionary<int, NetMsgStat>();
}
public void Tick(long tNowMs)
{
if(m_lastLogTime == 0)
{
m_lastLogTime = tNowMs;
}
if (tNowMs < m_lastLogTime + m_logInterval)
{
return;
}
m_lastLogTime = tNowMs;
LogHead();
LogContent();
LogTail();
}
private void LogContent_imp()
{
LogNetMsg();
LogIDValues();
LogGCMonitor();
}
private void LogContent()
{
lock (m_threadLock)
{
LogContent_imp();
}
}
//搞个头,看起来方便点
private void LogHead()
{
TraceLog.Stat("ServerStat begin =================================================================");
}
private void LogTail()
{
TraceLog.Stat("ServerStat end.\n");
}
private void LogIDValues()
{
//没有就算了
if(m_statIDValuesMap.Count == 0)
{
return;
}
TraceLog.Stat(" ID Value");
foreach(var idvalue in m_statIDValuesMap.Values)
{
TraceLog.Stat("{0,-40}{1,-20}", idvalue.ID, idvalue.Value);
//log完后清空这项数值
if (idvalue.NotClearAfterLog == false)
{
idvalue.Value = 0;
}
}
/*
var keys = m_statIDValuesMap.Keys;
var keyarray = keys.ToArray<string>();
foreach (string id in keyarray)
{
StatIDValue idvalue = m_statIDValuesMap[id];
TraceLog.Stat("{0,-40}{1,-20}",id, idvalue.Value);
//log完后清空这项数值
if (idvalue.NotClearAfterLog == false)
{
idvalue.Value = 0;
}
}*/
}
/// <summary>
/// 给id项目加value
/// </summary>
/// <param name="id"></param>
/// <param name="value"></param>
private void AddValue_imp(string id,long value, bool clearAfterLog = true)
{
if (m_statIDValuesMap.ContainsKey(id) == false)
{
StatIDValue idvalue = new StatIDValue();
idvalue.ID = id;
idvalue.Value = value;
idvalue.NotClearAfterLog = !clearAfterLog;
m_statIDValuesMap.Add(id, idvalue);
}
else
{
StatIDValue idvalue = m_statIDValuesMap[id];
idvalue.Value += value;
idvalue.NotClearAfterLog = !clearAfterLog;
}
}
public void AddValue(string id, long value, bool clearAfterLog = true)
{
lock (m_threadLock)
{
AddValue_imp(id, value, clearAfterLog);
}
}
/// <summary>
/// 设置id项目为value
/// </summary>
/// <param name="id"></param>
/// <param name="value"></param>
private void SetValue_imp(string id, long value, bool clearAfterLog = true)
{
if (m_statIDValuesMap.ContainsKey(id) == false)
{
StatIDValue idvalue = new StatIDValue();
idvalue.ID = id;
idvalue.Value = value;
idvalue.NotClearAfterLog = !clearAfterLog;
m_statIDValuesMap.Add(id, idvalue);
}
else
{
StatIDValue idvalue = m_statIDValuesMap[id];
idvalue.Value = value;
idvalue.NotClearAfterLog = !clearAfterLog;
}
}
public void SetValue(string id, long value, bool clearAfterLog = true)
{
lock (m_threadLock)
{
SetValue_imp(id, value, clearAfterLog);
}
}
//如果不存在则创建
private NetMsgStat GetNetMsgStatByID(int iMsgID)
{
if(!m_statNetMsgMap.ContainsKey(iMsgID))
{
NetMsgStat stat = new NetMsgStat();
stat.MsgID = iMsgID;
m_statNetMsgMap.Add(iMsgID, stat);
}
return m_statNetMsgMap[iMsgID];
}
public void OnNetSend(int iMsgID, int iDataLength)
{
lock (m_threadLock)
{
NetMsgStat stat = GetNetMsgStatByID(iMsgID);
stat.SendLength += iDataLength;
stat.SendNum += 1;
TotalSendLength += iDataLength;
TotalSendNum += 1;
}
}
public void OnNetRecv(int iMsgID, int iDataLength, long time)
{
lock (m_threadLock)
{
NetMsgStat stat = GetNetMsgStatByID(iMsgID);
stat.RecvLength += iDataLength;
stat.RecvNum += 1;
stat.RecvTotalTime += time;
stat.RecvMaxTime = stat.RecvMaxTime < time ? time : stat.RecvMaxTime;
if (stat.RecvNum > 1) //不是第一次
{
stat.RecvMinTime = stat.RecvNum > 0 ? time : stat.RecvMinTime;
}
else
{
stat.RecvMinTime = time;
}
TotalRecvLength += iDataLength;
TotalRecvNum += 1;
}
}
//网络消息,接受,发送数量和长度
private void LogNetMsg()
{
TraceLog.Stat("TotalSendNum:{0,-10} TotalRecvNum:{1,-10} TotalSendLength:{2,-12} TotalRecvLength:{3,-12}",
TotalSendNum, TotalRecvNum, TotalSendLength, TotalRecvLength);
//清空
TotalRecvLength = 0;
TotalRecvNum = 0;
TotalSendLength = 0;
TotalSendNum = 0;
TraceLog.Stat("MsgID SendNum RecvNum SendLength RecvLength RecvTotalTime RecvMaxTime RecvMinTime RecvAvgTime");
foreach(var item in m_statNetMsgMap.Values)
{
long RecvAvgTime = item.RecvNum <= 0 ? 0 : item.RecvTotalTime / item.RecvNum;
TraceLog.Stat("{0,-10}{1,-10}{2,-10}{3,-15}{4,-15}{5,-18}{6,-16}{7,-16}{8,-16}",
item.MsgID, item.SendNum, item.RecvNum, item.SendLength, item.RecvLength, item.RecvTotalTime, item.RecvMaxTime, item.RecvMinTime, RecvAvgTime);
//log完后清空这项数值
item.Clear();
}
/*
var keys = m_statNetMsgMap.Keys;
var keyarray = keys.ToArray<int>();
foreach (int id in keyarray)
{
NetMsgStat stat = m_statNetMsgMap[id];
TraceLog.Stat("{0,-10}{1,-10}{2,-10}{3,-15}{4,-15}", id, stat.SendNum,stat.RecvNum,stat.SendLength,stat.RecvLength);
//log完后清空这项数值
stat.Clear();
}
*/
}
private void LogGCMonitor()
{
GCMonitor.Instance.LogStat();
}
}
}

343
server/Sog/Core/Log/TraceLog.cs

@ -0,0 +1,343 @@
/*
Sog
2016 by zouwei
*/
using System;
using Sog.Log;
namespace Sog
{
/// <summary>
/// 日志操作类,对日志,错误日志,状态日志进行简单的管理,如果需要复杂逻辑,请自己实现
/// </summary>
/// <example>
/// <code>
/// public class Program
/// {
/// static void Main()
/// {
/// TraceLog.Trace("Hello {0}", "Sog")
/// TraceLog.Error("Error {0}", "error test.")
/// }
/// }
/// </code>
/// </example>
public static class TraceLog
{
/// <summary>
/// 缺省打开这个log
/// </summary>
private static Logger s_logger = new Logger("./", "trace.log", LogLevel.Trace);
private static Logger s_errorLogger;
private static Logger s_statLogger;
private static UserLogger s_userLogger;
private static BattleLogger s_battleLogger;
private static int[] s_skipLogMsgID;
public static void SetLogPathName(string strPath,string strName)
{
if (s_logger == null)
{
s_logger = new Logger(strPath, strName, LogLevel.Trace);
}
if (s_errorLogger == null)
{
s_errorLogger = new Logger(strPath, strName, LogLevel.Error);
}
if(s_statLogger == null)
{
s_statLogger = new Logger(strPath, strName, LogLevel.Debug);
}
s_logger.SetPathName(strPath, strName+".log");
s_errorLogger.SetPathName(strPath, strName + ".error");
s_statLogger.SetPathName(strPath, strName + ".stat");
//开始写线程
LogWriteThread.Instance.Start();
}
public static void InitUserLog(string path, string filename, int logLevel,
bool logAllUser, long[] logSomeUser)
{
if(s_userLogger == null)
{
s_userLogger = new UserLogger();
}
s_userLogger.Init(path, filename, logLevel, logAllUser, logSomeUser);
}
public static void InitBattleLog(string path, string filename, int logLevel,
bool logAllUser, long[] logSomeUser, bool logByBattleId)
{
if (s_battleLogger == null)
{
s_battleLogger = new BattleLogger();
}
s_battleLogger.Init(path, filename, logLevel, logAllUser, logSomeUser, logByBattleId);
}
public static int GetLogLevel()
{
return s_logger.GetLevel();
}
public static void SetLogLevel(int level)
{
s_logger.SetLevel(level);
if (level >= LogLevel.Error)
{
s_errorLogger.SetLevel(level);
}
else
{
s_errorLogger.SetLevel(LogLevel.Error);
}
}
public static void SetSkipLogMsgID(int[] msgIDs)
{
s_skipLogMsgID = msgIDs;
}
public static bool IsSkipLogMsgID(int iMsgID)
{
if(s_skipLogMsgID == null)
{
return false;
}
for(int i=0; i< s_skipLogMsgID.Length; i++)
{
if(iMsgID == s_skipLogMsgID[i])
{
return true;
}
}
return false;
}
public static void ForceCloseLogFile()
{
LogWriteThread.Instance.ForceClose();
}
public static void Error(string strFormat, params object[] argvList)
{
s_logger.LogError(strFormat, argvList);
if (s_errorLogger != null)
{
s_errorLogger.LogError(strFormat, argvList);
}
}
public static void Trace(string strFormat, params object[] argvList)
{
s_logger.LogTrace(strFormat, argvList);
}
public static void TraceDetail(string strFormat, params object[] argvList)
{
s_logger.LogTraceDetail(strFormat, argvList);
}
public static void Debug(string strFormat, params object[] argvList)
{
s_logger.LogDebug(strFormat, argvList);
}
public static void DebugNoFormat(string strMessage)
{
s_logger.LogDebugNoFormat(strMessage);
}
//写错误日志并抛出异常
public static void Assert(string strFormat, params object[] argvList)
{
string strLog = string.Format(strFormat, argvList);
Error(strLog);
throw new System.Exception(strLog);
}
/// <summary>
/// 写异常信息
/// </summary>
/// <param name="ex"></param>
/// <param name="bWriteConsole">是否打印到console窗口</param>
public static void Exception(Exception ex, bool bWriteConsole = false)
{
try
{
Error("catch one exception");
Error("{0}", ex.Message);
if (bWriteConsole)
{
Console.WriteLine(ex.Message);
}
Error("{0}", ex.Source);
if (bWriteConsole)
{
Console.WriteLine(ex.Source);
}
Error("{0}", ex.StackTrace);
if (bWriteConsole)
{
Console.WriteLine(ex.StackTrace);
}
if (ex.InnerException != null)
{
Error("{0}", ex.InnerException);
if (bWriteConsole)
{
Console.WriteLine(ex.InnerException);
}
}
}
catch(Exception innerEx)
{
//打exception又抛出异常就算了
Error("TraceLog.Exception throw a Exception {0}", innerEx.Message);
}
}
/// <summary>
/// 写统计日志,xxx.stat
/// </summary>
/// <param name="strFormat"></param>
/// <param name="argvList"></param>
public static void Stat(string strFormat, params object[] argvList)
{
if (s_statLogger != null)
{
s_statLogger.LogDebug(strFormat, argvList);
}
}
/// <summary>
/// 玩家日志
/// </summary>
/// <param name="strFormat"></param>
/// <param name="argvList"></param>
public static void UserError(long uid, string strFormat, params object[] argvList)
{
if (s_userLogger != null && uid > 0)
{
s_userLogger.LogError(uid, strFormat, argvList);
}
s_logger.LogError(strFormat, argvList);
if (s_errorLogger != null)
{
s_errorLogger.LogError(strFormat, argvList);
}
}
public static void UserTraceDetail(long uid, string strFormat, params object[] argvList)
{
if (s_userLogger != null && uid > 0)
{
s_userLogger.LogTraceDetail(uid, strFormat, argvList);
}
s_logger.LogTraceDetail(strFormat, argvList);
}
public static void UserTrace(long uid, string strFormat, params object[] argvList)
{
if (s_userLogger != null && uid > 0)
{
s_userLogger.LogTrace(uid, strFormat, argvList);
}
s_logger.LogTrace(strFormat, argvList);
}
public static void UserDebug(long uid, string strFormat, params object[] argvList)
{
if (s_userLogger != null && uid > 0)
{
s_userLogger.LogDebug(uid, strFormat, argvList);
}
s_logger.LogDebug(strFormat, argvList);
}
public static bool NeedLogUserTraceLevel(long uid)
{
if(s_userLogger.GetLogLevel() > (int)LogLevel.TraceDetail)
{
return false;
}
return s_userLogger.NeedLogUser(uid);
}
public static void BattleTraceDetail(long uid, ulong battleId, int seq, string strFormat, params object[] argvList)
{
if (s_logger != null)
{
s_logger.LogByLevel(LogLevel.TraceDetail, strFormat, argvList);
}
if (s_battleLogger != null)
{
s_battleLogger.LogTraceDetail(uid, battleId, seq, strFormat, argvList);
}
}
public static void BattleTrace(long uid, ulong battleId, int seq, string strFormat, params object[] argvList)
{
if (s_logger != null)
{
s_logger.LogTrace(strFormat, argvList);
}
if (s_battleLogger != null)
{
s_battleLogger.LogTrace(uid, battleId, seq, strFormat, argvList);
}
}
public static void BattleDebug(long uid, ulong battleId, int seq, string strFormat, params object[] argvList)
{
if (s_logger != null)
{
s_logger.LogDebug(strFormat, argvList);
}
if (s_battleLogger != null)
{
s_battleLogger.LogDebug(uid, battleId, seq, strFormat, argvList);
}
}
public static void BattleError(long uid, ulong battleId, int seq, string strFormat, params object[] argvList)
{
if (s_logger != null)
{
s_logger.LogError(strFormat, argvList);
}
if (s_battleLogger != null)
{
s_battleLogger.LogError(uid, battleId, seq, strFormat, argvList);
}
}
}
}

24
server/Sog/Core/Log/UserLogConfig.cs

@ -0,0 +1,24 @@
using System.Runtime.Serialization;
namespace Sog.Log
{
public class UserLogConfig
{
public string userlogname { get; set; }
/// <summary>
/// UserLog的等级
/// </summary>
public string userloglevel { get; set; }
/// <summary>
/// 是否log全部User的日志
/// </summary>
public bool userlogAll { get; set; }
/// <summary>
/// User配置数组
/// </summary>
public long[] userlogSome { get; set; }
}
}

137
server/Sog/Core/Log/UserLogger.cs

@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Sog.Log
{
public class UserLogger
{
private int m_logLevel;
/// <summary>
/// 是否log所有玩家,外网请关闭
/// </summary>
private bool m_logAllUser;
private long[] m_logSomeUser;
private string m_logPath;
private string m_logFileName;
//这个加了后就不会删,只是占用点内存,无所谓了
private Dictionary<long, Logger> m_allUser = new Dictionary<long, Logger>();
public void Init(string path, string filename, int logLevel, bool logAllUser,long[] logSomeUser)
{
m_logAllUser = logAllUser;
m_logLevel = logLevel;
m_logSomeUser = logSomeUser;
m_logPath = path;
m_logFileName = filename;
m_allUser.Clear();
}
public int GetLogLevel()
{
return m_logLevel;
}
public bool NeedLogUser(long uid)
{
if(m_logAllUser)
{
return true;
}
if(m_logSomeUser == null)
{
return false;
}
for(int i=0; i< m_logSomeUser.Length; i++)
{
if(m_logSomeUser[i] == uid)
{
return true;
}
}
return false;
}
public void LogByLevel(long uid, int logLevel, string strFormat, params object[] argvList)
{
//先判断等级
if (logLevel < m_logLevel)
{
return;
}
//这个uid是否需要log
if (!NeedLogUser(uid))
{
return;
}
Logger logger;
if (false == m_allUser.TryGetValue(uid, out logger))
{
logger = new Logger(m_logPath, m_logFileName + "_" + uid.ToString() + ".log", m_logLevel);
m_allUser.Add(uid, logger);
}
if (OSUtils.IsWindows() == false)
{
//外网版本,log错误不影响逻辑
try
{
string strLog = string.Format(strFormat, argvList);
logger.WriteLog(logLevel, strLog);
}
catch (Exception ex)
{
logger.WriteLog(logLevel, ex.Message);
logger.WriteLog(logLevel, ex.Source);
logger.WriteLog(logLevel, ex.StackTrace);
}
}
else
{
//windows版本,为了发现问题,log错误直接异常,不继续处理了
string strLog = string.Format(strFormat, argvList);
logger.WriteLog(logLevel, strLog);
}
//string strLog = string.Format(strFormat, argvList);
//logger.WriteLog(logLevel, strLog);
}
public void LogTraceDetail(long uid, string strFormat, params object[] argvList)
{
LogByLevel(uid, LogLevel.TraceDetail, strFormat, argvList);
}
public void LogTrace(long uid,string strFormat, params object[] argvList)
{
LogByLevel(uid,LogLevel.Trace, strFormat, argvList);
}
public void LogDebug(long uid, string strFormat, params object[] argvList)
{
LogByLevel(uid,LogLevel.Debug, strFormat, argvList);
}
public void LogError(long uid, string strFormat, params object[] argvList)
{
LogByLevel(uid,LogLevel.Error, strFormat, argvList);
}
public void LogFatal(long uid, string strFormat, params object[] argvList)
{
LogByLevel(uid,LogLevel.Fatal, strFormat, argvList);
}
}
}
Loading…
Cancel
Save