11 changed files with 1732 additions and 88 deletions
@ -0,0 +1,35 @@ |
|||||
|
using System.Runtime.Serialization; |
||||
|
|
||||
|
namespace Sog.Log |
||||
|
{ |
||||
|
[DataContract] |
||||
|
public class BattleLogConfig |
||||
|
{ |
||||
|
[DataMember(Order = 1)] |
||||
|
public string logname { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// UserLog的等级
|
||||
|
/// </summary>
|
||||
|
[DataMember(Order = 2)] |
||||
|
public string loglevel { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 是否log全部User的日志
|
||||
|
/// </summary>
|
||||
|
[DataMember(Order = 3)] |
||||
|
public bool userlogAll { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// User配置数组
|
||||
|
/// </summary>
|
||||
|
[DataMember(Order = 4)] |
||||
|
public long[] userlogSome { get; set; } |
||||
|
|
||||
|
[DataMember(Order = 5)] |
||||
|
public bool logByBattleId { get; set; } |
||||
|
|
||||
|
[DataMember(Order = 6)] |
||||
|
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,342 @@ |
|||||
|
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(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
/// <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 = 0; |
||||
|
|
||||
|
//一分钟检查一次
|
||||
|
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,193 @@ |
|||||
|
/* |
||||
|
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 = "[" + DateTime.Now.ToString() + "]" + 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() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,334 @@ |
|||||
|
/* |
||||
|
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(ex.ToString());
|
||||
|
//Console.WriteLine(ex.ToString());
|
||||
|
Error("catch one exception"); |
||||
|
Error(ex.Message); |
||||
|
|
||||
|
if (bWriteConsole) |
||||
|
{ |
||||
|
Console.WriteLine(ex.Message); |
||||
|
} |
||||
|
|
||||
|
Error(ex.Source); |
||||
|
|
||||
|
if (bWriteConsole) |
||||
|
{ |
||||
|
Console.WriteLine(ex.Source); |
||||
|
} |
||||
|
|
||||
|
Error(ex.StackTrace); |
||||
|
|
||||
|
if (bWriteConsole) |
||||
|
{ |
||||
|
Console.WriteLine(ex.StackTrace); |
||||
|
} |
||||
|
}//打exception又抛出异常就算了
|
||||
|
catch(Exception) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <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,29 @@ |
|||||
|
using System.Runtime.Serialization; |
||||
|
|
||||
|
namespace Sog.Log |
||||
|
{ |
||||
|
[DataContract] |
||||
|
public class UserLogConfig |
||||
|
{ |
||||
|
[DataMember(Order = 1)] |
||||
|
public string userlogname { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// UserLog的等级
|
||||
|
/// </summary>
|
||||
|
[DataMember(Order = 2)] |
||||
|
public string userloglevel { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 是否log全部User的日志
|
||||
|
/// </summary>
|
||||
|
[DataMember(Order = 3)] |
||||
|
public bool userlogAll { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// User配置数组
|
||||
|
/// </summary>
|
||||
|
[DataMember(Order = 4)] |
||||
|
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); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,89 +1,89 @@ |
|||||
{ |
{ |
||||
"ActivityDesc": 1752049375, |
"ActivityDesc": 1753426333, |
||||
"AdvertisementConfigDesc": 1752049375, |
"AdvertisementConfigDesc": 1753426333, |
||||
"AffixDesc": 1752049375, |
"AffixDesc": 1753426333, |
||||
"AffixesDesc": 1743412566, |
"AffixesDesc": 1753426333, |
||||
"AffixesRandomGroupDesc": 1743412566, |
"AffixesRandomGroupDesc": 1753426333, |
||||
"AltarDesc": 1723785962, |
"AltarDesc": 1753426333, |
||||
"AnimationStatePriorityDesc": 1752049375, |
"AnimationStatePriorityDesc": 1753426333, |
||||
"BenifitDesc": 1743412566, |
"BenifitDesc": 1753426333, |
||||
"BulletDesc": 1752142172, |
"BulletDesc": 1753426333, |
||||
"ChapterDesc": 1752049374, |
"ChapterDesc": 1753426333, |
||||
"ChapterBattleDesc": 1752049374, |
"ChapterBattleDesc": 1753426333, |
||||
"ChapterBattleStageDesc": 1752049374, |
"ChapterBattleStageDesc": 1753426333, |
||||
"CommParamDesc": 1752485322, |
"CommParamDesc": 1753426333, |
||||
"ContinueBattleDesc": 1752049374, |
"ContinueBattleDesc": 1753426333, |
||||
"CountryAreaNameMapDesc": 1743412566, |
"CountryAreaNameMapDesc": 1753426333, |
||||
"CSPropIDTypeDesc": 1752049373, |
"CSPropIDTypeDesc": 1753426333, |
||||
"DropSkillDesc": 1743412566, |
"DropSkillDesc": 1753426333, |
||||
"EnumDesc": 1753350887, |
"EnumDesc": 1753426333, |
||||
"EquipDesc": 1752049373, |
"EquipDesc": 1753426333, |
||||
"EquipAttrDesc": 1752049373, |
"EquipAttrDesc": 1753426333, |
||||
"EquipSuitDesc": 1752049373, |
"EquipSuitDesc": 1753426333, |
||||
"ErrorCodeDesc": 1743412566, |
"ErrorCodeDesc": 1753426333, |
||||
"ExpressionDesc": 1752049372, |
"ExpressionDesc": 1753426333, |
||||
"GACastConditionDesc": 1752049372, |
"GACastConditionDesc": 1753426333, |
||||
"GachaDesc": 1752049372, |
"GachaDesc": 1753426333, |
||||
"GachaChooseRewardDesc": 1752049372, |
"GachaChooseRewardDesc": 1753426333, |
||||
"GAS_TagDesc": 1752049372, |
"GAS_TagDesc": 1753426333, |
||||
"GECastPointSelectDesc": 1752049371, |
"GECastPointSelectDesc": 1753426333, |
||||
"GECatchTargetDesc": 1752049371, |
"GECatchTargetDesc": 1753426333, |
||||
"GemDesc": 1752049371, |
"GemDesc": 1753426333, |
||||
"GEModiferDesc": 1752049371, |
"GEModiferDesc": 1753426333, |
||||
"GmDesc": 1752049371, |
"GmDesc": 1753426333, |
||||
"HandBookDesc": 1752049371, |
"HandBookDesc": 1753426333, |
||||
"HeadDesc": 1752049370, |
"HeadDesc": 1753426333, |
||||
"ItemDesc": 1752049370, |
"ItemDesc": 1753426333, |
||||
"LanguageAbbrCfgDesc": 1743412566, |
"LanguageAbbrCfgDesc": 1753426333, |
||||
"LanguageDesc": 1752049370, |
"LanguageDesc": 1753426333, |
||||
"LanguageParamsDesc": 1743412567, |
"LanguageParamsDesc": 1753426333, |
||||
"LevelDesc": 1752049370, |
"LevelDesc": 1753426333, |
||||
"LoopWeeklyBpAwardDesc": 1743412567, |
"LoopWeeklyBpAwardDesc": 1753426333, |
||||
"MailDesc": 1752049370, |
"MailDesc": 1753426333, |
||||
"MarketShopDesc": 1752049370, |
"MarketShopDesc": 1753426333, |
||||
"MarketShopGoodsDesc": 1752049369, |
"MarketShopGoodsDesc": 1753426333, |
||||
"MarqueeDesc": 1743412567, |
"MarqueeDesc": 1753426333, |
||||
"MiniMapDesc": 1743412567, |
"MiniMapDesc": 1753426333, |
||||
"MonsterPropDesc": 1752210578, |
"MonsterPropDesc": 1753426333, |
||||
"MonthlyCardDesc": 1752049369, |
"MonthlyCardDesc": 1753426333, |
||||
"NewSeverRankAwardDesc": 1743412567, |
"NewSeverRankAwardDesc": 1753426333, |
||||
"NoviceGuidanceDesc": 1752049369, |
"NoviceGuidanceDesc": 1753426333, |
||||
"NpcDesc": 1752049369, |
"NpcDesc": 1753426333, |
||||
"PassCardDesc": 1752049369, |
"PassCardDesc": 1753426333, |
||||
"PayDiamondDesc": 1752049368, |
"PayDiamondDesc": 1753426333, |
||||
"PeakLevelDesc": 1743412567, |
"PeakLevelDesc": 1753426333, |
||||
"PopUpPackageDesc": 1752049368, |
"PopUpPackageDesc": 1753426333, |
||||
"QuestEXDesc": 1752049368, |
"QuestEXDesc": 1753426333, |
||||
"RandNameDesc": 1743412567, |
"RandNameDesc": 1753426333, |
||||
"RankAwardDesc": 1752049368, |
"RankAwardDesc": 1753426333, |
||||
"RankConfigDesc": 1743412567, |
"RankConfigDesc": 1753426333, |
||||
"RenderEffectDesc": 1752049368, |
"RenderEffectDesc": 1753426333, |
||||
"RewardDesc": 1752049367, |
"RewardDesc": 1753426333, |
||||
"RoleModelDesc": 1752142866, |
"RoleModelDesc": 1753426333, |
||||
"SignRewardDesc": 1752049367, |
"SignRewardDesc": 1753426333, |
||||
"SkillDesc": 1752211004, |
"SkillDesc": 1753426333, |
||||
"SkillGroupDesc": 1752210533, |
"SkillGroupDesc": 1753426333, |
||||
"SoundDesc": 1753151133, |
"SoundDesc": 1753426333, |
||||
"SummonDesc": 1752049366, |
"SummonDesc": 1753426333, |
||||
"SwitchDesc": 1752049366, |
"SwitchDesc": 1753426333, |
||||
"TalentDesc": 1752049366, |
"TalentDesc": 1753426333, |
||||
"TreasureDesc": 1743412567, |
"TreasureDesc": 1753426333, |
||||
"TriggerDesc": 1753151134, |
"TriggerDesc": 1753426333, |
||||
"UnlockSystemDesc": 1752049366, |
"UnlockSystemDesc": 1753426333, |
||||
"WeaponDesc": 1752049365, |
"WeaponDesc": 1753426333, |
||||
"WingsDesc": 1752049365, |
"WingsDesc": 1753426333, |
||||
"WingsLevelDesc": 1752049365, |
"WingsLevelDesc": 1753426333, |
||||
"WingsRankDesc": 1752049365, |
"WingsRankDesc": 1753426333, |
||||
"WingsRefitDesc": 1752049365, |
"WingsRefitDesc": 1753426333, |
||||
"WingsStarDesc": 1752049365, |
"WingsStarDesc": 1753426333, |
||||
"ZoneDesc": 1752049364, |
"ZoneDesc": 1753426333, |
||||
"CueDesc": 1753152930, |
"CueDesc": 1753426333, |
||||
"BallDesc": 1752210574, |
"BallDesc": 1753426333, |
||||
"GasAssetPathDesc": 1752211010, |
"GasAssetPathDesc": 1753426333, |
||||
"GridPieceInfoDesc": 1752586355, |
"GridPieceInfoDesc": 1753426333, |
||||
"AssetPathDesc": 1752498528, |
"AssetPathDesc": 1753426333, |
||||
"GridGroupCfgDesc": 1753364128, |
"GridGroupCfgDesc": 1753426333, |
||||
"GridMonsterDesc": 1753350887, |
"GridMonsterDesc": 1753426333, |
||||
"LevelWaveCfgDesc": 1753365270, |
"LevelWaveCfgDesc": 1753426333, |
||||
"WaveStructCfgDesc": 1753365158 |
"WaveStructCfgDesc": 1753426333 |
||||
} |
} |
Loading…
Reference in new issue