using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Threading; using Sog; namespace BillLog { public static class LogTransferHandler { private static Thread m_thread; private static ParameterizedThreadStart m_parStart; private static AutoResetEvent m_eventWorkList; private static bool m_isStop = false; private static long m_times = 0;//记录下检查次数 private static long m_errorTimes = 0;//记录下异常次数 private static long m_tickMs; //目录相关 private static Dictionary logDir; private static Dictionary transferDir; private static int intervalDay = 30; //按类型,按天存放文件 private static Dictionary>> tmpDir = new Dictionary>>(); public static void InitLogTransferHandler() { StartThread(); } //停服 public static void OnStop() { TraceLog.Debug("LogTransferHandler stop server begin"); m_isStop = true; m_eventWorkList?.Set(); m_thread?.Join();//最多打完一天的包就会退出 TraceLog.Debug("LogTransferHandler stop server end"); } //释放 public static void OnDispose() { TraceLog.Debug("LogTransferHandler OnDispose begin"); m_isStop = true; m_eventWorkList?.Set(); m_thread?.Join(); //清空 m_eventWorkList = null; m_thread = null; m_parStart = null; logDir = null; transferDir = null; TraceLog.Debug("LogTransferHandler OnDispose end"); } private static void StartThread() { TraceLog.Debug("LogTransferHandler StartThread"); logDir = new Dictionary(); transferDir = new Dictionary(); m_eventWorkList = new AutoResetEvent(false); m_parStart = DoThreadWork; m_thread = new Thread(m_parStart, 1024 * 1024 * 10); //设置成后台线程,如果不是后台线程,线程不是主动关闭,则会一直运行,那怕进程主线程退出也没用 m_thread.IsBackground = true; m_thread.Start(); } private static void DoThreadWork(object obj) { while (!m_isStop) { //执行一次 m_eventWorkList.WaitOne(); if (m_isStop) { break; } //todo try { m_times++; TraceLog.Debug("LogTransferHandler DoThreadWork Times {0}", m_times); LogTransfer(AppTime.GetNowSysSecond()); } catch (Exception e) { m_errorTimes++; TraceLog.Error("LogTransferHandler DoThreadWork Error Times {0} ",m_times); TraceLog.Exception(e); BillLogServerUtils.GetApp()?.Alerter?.AlertException(e); } //重置 m_eventWorkList.Reset(); } } public static void TickDaily(long nowMs) { if (m_tickMs == 0) { m_tickMs = nowMs; } //每小时 if (m_tickMs + 3600 * 1000 > nowMs) { return; } m_tickMs = nowMs; //暂时每天3点检查下 if (AppTime.GetHour(nowMs / 1000) != 3) { return; } //检查一次数据 m_eventWorkList?.Set(); } public static void InitLogPath() { if (logDir == null || transferDir == null) return; var cfg = BillLogServerUtils.GetServerConfig(); if (cfg.logTransfer == null || string.IsNullOrEmpty(cfg.logTransfer.transferPath) || cfg.logTransfer.transferLogs == null || cfg.logTransfer.transferLogs.Length == 0) { return; } if (!Directory.Exists(cfg.logTransfer.transferPath)) { Directory.CreateDirectory(cfg.logTransfer.transferPath); } logDir.Clear(); transferDir.Clear(); if (cfg.logTransfer.intervalDay > 0) { intervalDay = cfg.logTransfer.intervalDay; } foreach (var logs in cfg.logTransfer.transferLogs) { switch (logs) { case "bill": GetTransferPath(cfg.logpatchs.bill,cfg,logs); break; case "bdc": GetTransferPath(cfg.logpatchs.bdc, cfg, logs); break; case "bdcCli": GetTransferPath(cfg.logpatchs.bdcCli, cfg, logs); break; case "ta": GetTransferPath(cfg.logpatchs.ta, cfg, logs); break; case "taCli": GetTransferPath(cfg.logpatchs.taCli, cfg, logs); break; case "taFilter": GetTransferPath(cfg.logpatchs.taFilter, cfg, logs); break; } } //不存在,创建目录 foreach (var log in transferDir) { if (!Directory.Exists(log.Value)) { Directory.CreateDirectory(log.Value); } } } private static void GetTransferPath(string logsDir,BillLogServerConfig cfg,string logs) { var split = logsDir.Split("/"); if (split.Length == 0) { return; } string tpath = null; if (string.IsNullOrEmpty(split[split.Length - 1])) { if (split.Length >= 2) { tpath = split[split.Length - 2]; } } else { tpath = split[split.Length - 1]; } if (string.IsNullOrEmpty(tpath)) { return; } tpath = cfg.logTransfer.transferPath + "/" + tpath; logDir.Add(logs, logsDir); transferDir.Add(logs, tpath); } private static void LogTransfer(long nowSec) { if (logDir == null || transferDir == null) return; if (logDir.Count == 0 || transferDir.Count == 0) return; tmpDir.Clear(); //找到所有的文件 foreach (var log in logDir) { if (m_isStop) { //如果开始停服了 return; } if (!transferDir.ContainsKey(log.Key)) { continue; } string[] files = Directory.GetFiles(log.Value, "*.log"); foreach (var file in files) { var createTime = Directory.GetCreationTime(file); var diffday = AppTime.GetDayElapse(nowSec, AppTime.GetTimeSecond(createTime),0); if (diffday >= intervalDay) { if (!tmpDir.ContainsKey(log.Key)) { tmpDir.Add(log.Key,new Dictionary>()); } if (!tmpDir[log.Key].ContainsKey(diffday)) { tmpDir[log.Key].Add(diffday,new List()); } //同一天的文件放在一起压缩打包 tmpDir[log.Key][diffday].Add(file); } } } //压缩文件和删除文件 foreach (var tmp in tmpDir)//一个类型所有文件 { if (m_isStop) { //如果开始停服了 return; } if (!transferDir.ContainsKey(tmp.Key)) { continue; } foreach (var dayFile in tmp.Value)//每天所有文件 { if (m_isStop) { //如果开始停服了 return; } if (dayFile.Value.Count == 0 || !File.Exists(dayFile.Value.First())) { continue; } string timeformat = Directory.GetCreationTime(dayFile.Value.First()).ToString("yyyy-MM-dd"); var targzpath = transferDir[tmp.Key] + "/" + $"{tmp.Key}_{timeformat}.zip"; var mvPath = transferDir[tmp.Key] + "/tmp/"; if (!Directory.Exists(mvPath)) { Directory.CreateDirectory(mvPath); } //先移动文件到指定位置 try { foreach (var oneFile in dayFile.Value) { File.Move(oneFile, mvPath + Path.GetFileName(oneFile)); } //打包zip if (File.Exists(targzpath)) { File.Delete(targzpath); } ZipFile.CreateFromDirectory(mvPath, targzpath); //删除临时目录文件 if (Directory.Exists(mvPath)) { DirectoryInfo di = new DirectoryInfo(mvPath); di.Delete(true); } } catch (Exception e) { //如果出问题了,要把临时目录的文件再移动回去 if (Directory.Exists(mvPath)) { foreach (var oneFile in dayFile.Value) { var mvfilepath = mvPath + Path.GetFileName(oneFile); if (File.Exists(mvfilepath)) { File.Move(mvfilepath, oneFile); } } } throw; } } } //清空 tmpDir.Clear(); } } }