using System; using Sog; using Sog.Log; using ProtoCSStruct; using Sog.Service; namespace BillLog { public class BillLogMsgHandler : BaseReloadableService { private ServerApp m_app; // 本地bill日志 private Logger m_billLogger; private DateTime m_lastLogTime; // 本地bdc日志 private Logger m_bdcLogger; private DateTime m_lastBdcLogTime; // bdc客户端日志 private Logger m_clibdcLogger; private DateTime m_cliLastBdcLogTime; private int noUidCount; //ta日志 private Logger m_taLogger; private DateTime m_lastTaLogTime; //ta客户端日志 private Logger m_clitaLogger; private DateTime m_lastCliTaLogTime; //ta过滤日志,关闭的日志是数数数量太多了不要了,我们这最好存好不上报吧 private Logger m_taFilterLogger; private DateTime m_lastTaFilterLogTime; // todo 这个值需要存盘, 否则会有重复的问题 private static long uuidSeq; public override int GetServiceType() { return BillLogServiceType.BillLogMsgHandler; } //销毁的时候置空 public override void Dispose() { m_app = null; m_billLogger = null; m_bdcLogger = null; m_clibdcLogger = null; m_taLogger = null; m_taFilterLogger = null; } public BillLogMsgHandler(ServerApp app) { m_app = app; var logPaths = BillLogServerUtils.GetServerConfig().logpatchs; //先写死,to do 放到配置文件 m_billLogger = new Logger(logPaths.bill, "", LogLevel.Debug); //关闭文件自动滚动功能,自己实现按时间(每小时)滚动 m_billLogger.CloseShift(); m_bdcLogger = new Logger(logPaths.bdc, "", LogLevel.Debug); //关闭文件自动滚动功能,自己实现按时间(每小时)滚动 m_bdcLogger.CloseShift(); m_clibdcLogger = new Logger(logPaths.bdcCli, "", LogLevel.Debug); //关闭文件自动滚动功能,自己实现按时间(每小时)滚动 m_clibdcLogger.CloseShift(); m_taLogger = new Logger(logPaths.ta, "", LogLevel.Debug); //关闭文件自动滚动功能,自己实现按时间(每小时)滚动 m_taLogger.CloseShift(); m_clitaLogger = new Logger(logPaths.taCli, "", LogLevel.Debug); //关闭文件自动滚动功能,自己实现按时间(每小时)滚动 m_clitaLogger.CloseShift(); m_taFilterLogger = new Logger(logPaths.taFilter, "", LogLevel.Debug); //关闭文件自动滚动功能,自己实现按时间(每小时)滚动 m_taFilterLogger.CloseShift(); } public ServerApp GetApp() { return m_app; } public void HandlerMessage(uint remoteAppID, MessageData message) { StructPacket packet; bool bSuccess = BillLogServerUtils.GetProtoPacker().UnpackMessage(message, out packet); if(bSuccess == false) { TraceLog.Error("HandlerMessage ,unpack msg failed {0}, remoteAppID {1}", message.Header.Type, remoteAppID); return; } //预先判断,提高效率 if (TraceLog.GetLogLevel() <= (int)Sog.Log.LogLevel.TraceDetail) { TraceLog.TraceDetail("recv message from server {0}, message type {1} length {2} : {3}->{4}" , ServerIDUtils.IDToString(remoteAppID) , message.Header.Type , message.Header.Length , packet.MessageName() , packet.ToString()); } switch (packet.MsgID) { case (int)SSGameMsgID.BillLogReq: OnBillLogReq(remoteAppID, packet); break; case (int)SSGameMsgID.BdcLogReq: OnBDCLogReq(remoteAppID, packet); break; case (int)CSGameMsgID.LogClientBdcReq: OnBdcClientLogReq(remoteAppID, packet); break; case (int)SSGameMsgID.TaLogReq: OnTALogReq(remoteAppID, packet); break; case (int)CSGameMsgID.LogClientTaReq: OnTAClientLogReq(remoteAppID, packet); break; default: TraceLog.Error("MsgHandler unknow MsgID {0}", packet.MsgID); break; } } private void OnBillLogReq(uint remoteAppID, StructPacket packet) { ref SSBillLogReq billLogReq = ref packet.GetMessage(); string logmessage = billLogReq.StrLogMessage.ToString(); TraceLog.Debug("OnBillLogReq log message from server {0} log:{1}", ServerIDUtils.IDToString(remoteAppID), logmessage); WriteBillLog(logmessage); } private void OnBdcClientLogReq(uint remoteAppID, StructPacket packet) { ref CsLogClientBDCReq billLogReq = ref packet.GetMessage(); string logmessage = billLogReq.StrLogMessage.ToString(); TraceLog.Debug("OnBdcClientLogReq log message from server {0} log:{1}", ServerIDUtils.IDToString(remoteAppID), logmessage); WriteClientBdcLog(logmessage); } private void OnTAClientLogReq(uint remoteAppID, StructPacket packet) { ref CsLogClientTAReq taLogReq = ref packet.GetMessage(); string logmessage = taLogReq.StrLogMessage.ToString(); TraceLog.Debug("OnTAClientLogReq log message from server {0} log:{1}", ServerIDUtils.IDToString(remoteAppID), logmessage); WriteClientTALog(logmessage); } private void WriteBillLog(string strMessage) { DateTime now = DateTime.Now; if(IsLogFileNameChanged(m_lastLogTime, now)) { m_lastLogTime = now; m_billLogger.SetFileName(CalcLogFileName(now)); } //时间就用这个now,写的时候不用再取了,取2次会有时间不一致问题 m_billLogger.WriteLogWithTime(now,strMessage); } private void WriteLocalBdcLog(string strMessage) { DateTime now = DateTime.Now; if (IsLogFileNameChanged(m_lastBdcLogTime, now)) { m_lastBdcLogTime = now; m_bdcLogger.SetFileName(CalcLogFileName(now, 1)); } //时间就用这个now,写的时候不用再取了,取2次会有时间不一致问题 m_bdcLogger.WriteLogWithTime(now, strMessage); } private void WriteLocalTALog(string strMessage) { DateTime now = DateTime.Now; if (IsLogFileNameChanged(m_lastTaLogTime, now)) { m_lastTaLogTime = now; m_taLogger.SetFileName(CalcLogFileName(now, 3)); } m_taLogger.WriteTALog(strMessage); } private void WriteLocalTAFilterLog(string strMessage) { DateTime now = DateTime.Now; if (IsLogFileNameChanged(m_lastTaFilterLogTime, now)) { m_lastTaFilterLogTime = now; m_taFilterLogger.SetFileName(CalcLogFileName(now, 5)); } m_taFilterLogger.WriteTALog(strMessage); } private void WriteClientBdcLog(string strMessage) { DateTime now = DateTime.Now; if (IsLogFileNameChanged(m_cliLastBdcLogTime, now)) { m_cliLastBdcLogTime = now; m_clibdcLogger.SetFileName(CalcLogFileName(now, 2)); } //时间就用这个now,写的时候不用再取了,取2次会有时间不一致问题 m_clibdcLogger.WriteLogWithTime(now, strMessage); } private void WriteClientTALog(string strMessage) { DateTime now = DateTime.Now; if (IsLogFileNameChanged(m_lastCliTaLogTime, now)) { m_lastCliTaLogTime = now; m_clitaLogger.SetFileName(CalcLogFileName(now, 4)); } m_clitaLogger.WriteLogWithTime(now, strMessage); } private string CalcLogFileName(DateTime now, int logType = 0) { // "2016-10-01 01:13:59" string nowTimeFormat = now.ToString("u"); string nowDay = nowTimeFormat.Substring(0, 10); string nowHour = nowTimeFormat.Substring(11, 2); if (logType == 1) { return string.Format("bdcSvr_{0}_{1}.log", nowDay, nowHour); } else if(logType == 2) { return string.Format("bdcCli_{0}_{1}.log", nowDay, nowHour); } else if (logType == 3) { return string.Format("talog_{0}_{1}.log", nowDay, nowHour); } else if (logType == 4) { return string.Format("clitalog_{0}_{1}.log", nowDay, nowHour); } else if (logType == 5) { return string.Format("tafilterlog_{0}_{1}.log", nowDay, nowHour); } return string.Format("bill_{0}_{1}.log", nowDay, nowHour); } private bool IsLogFileNameChanged(DateTime lastLogTime, DateTime now) { if(lastLogTime.Hour == now.Hour && lastLogTime.Day == now.Day && lastLogTime.Month == now.Month && lastLogTime.Year == now.Year) { return false; } return true; } private string GenUUID() { uuidSeq++; if (uuidSeq > 1000000) { uuidSeq = 1; } return $"{BillLogServerUtils.GetDateTime().ToString("yyyyMMdd-HHmmss")}-{uuidSeq.ToString().PadLeft(7, '0')}"; } private void OnBDCLogReq(uint remoteAppID, StructPacket packet) { var cfg = BillLogServerUtils.GetServerConfig().bdcCfg; if (cfg.isBdcOpen == 0) { return; } //因为需要放入每个线程的队列,所以需要clone 一个新的对象,UnpackMessage出来的消息每次其实是同一个 //如果存在性能问题,可以根据消息类型进行缓冲 packet = packet.Clone(); string uuid = GenUUID(); ref SSBDCLogReq req = ref packet.GetMessage(); req.Event_uuid.SetString(uuid); // 本地bdc日志在主线程里面写入bdc_xxx_xxx.log // 本地bdc日志比远端bdc日志少了2个字段, appKey, platform, 这2个字段读取的配置文件, 运行期间不会改变 // 另外, 本地和远端的event_time可能不一致, 按照bdc要求event_time是日志上报时间 // 远端event_time是work线程实际提交http请求时的时间. // 目前选择不统一本地和远端的event_time, 保留时间差以便性能分析 var localBdcMsg = string.Format("{0}|event_uuid={1}|event_time={2}|event_time2={3}|platform={4}|time_zone={5}" , req.LogMsg.GetString() , uuid , BillLogServerUtils.GetTimeSecond().ToString() , BillLogServerUtils.GetDateTime().ToString("yyyy-MM-dd"), BillLogServerUtils.GetServerConfig().bdcCfg.Bdcplatform, "UTC+" + AppTime.TimeZone.ToString() + ":00"); WriteLocalBdcLog(localBdcMsg); bool isFilter = false; if (req.EventId > 0 && cfg.FilterLogEventIds != null && cfg.FilterLogEventIds.Length > 0) { for (int i = 0; i < cfg.FilterLogEventIds.Length; i++) { if (req.EventId == cfg.FilterLogEventIds[i]) { isFilter = true; break; } } } if (!isFilter) { int iTaskIndex = CalcTaskIndex(noUidCount); noUidCount++; if (noUidCount < 0) { noUidCount = 1; } MessageTaskDistributor.Instance.Distribute(remoteAppID, packet, iTaskIndex); } } private void OnTALogReq(uint remoteAppID, StructPacket packet) { if (BillLogServerUtils.GetServerConfig().isTALogOpen == 0) { return; } ref SSTALogReq req = ref packet.GetMessage(); if(IsTaFilterEvent(req.EventName.ToString())) //是过滤事件 { WriteLocalTAFilterLog(req.LogMsg.ToString()); } else { WriteLocalTALog(req.LogMsg.ToString()); } } private bool IsTaFilterEvent(string eventName) { if(string.IsNullOrEmpty(eventName)) //不是事件,是上报属性 { return false; } var cfg = BillLogServerUtils.GetServerConfig().taCfg; //没有配置过滤 if(cfg == null || cfg.isOpenFilter == false || cfg.filterEvents == null) { return false; } foreach(var filter in cfg.filterEvents) { if(filter == eventName) { return true; } } return false; } private int CalcTaskIndex(long uid) { return (int)(uid % MessageTaskHandler.TaskCount); } } }