9 changed files with 1644 additions and 0 deletions
@ -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; } |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
|||
} |
@ -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; // 多少秒后关闭没有再写请求的文件,释放句柄
|
|||
} |
|||
} |
@ -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(); |
|||
} |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
@ -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(); |
|||
} |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -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; } |
|||
} |
|||
} |
@ -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…
Reference in new issue