using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using System.IO; using System.Windows.Forms; using System.Threading; using System.Reflection; namespace CoreUnit.Common { public class LogUnit { public delegate void EventHandlerLog(LogItem item); public delegate void EventDisplayLog(LogItem item, eLogLevel logLevel); public enum eLogProtocol : int { Time = 0, Msg, Position, Type }; public enum eLogLevel { LOW, MIDDLE, HIGH }; //로그를 표시하는 레벨을 정리함(High: detail한 로그까지 표시(Debug모드), Low: 단순한 로그(System로그)만 표시) public enum eLogType { ERROR, ALARM, PRODUCT, SYSTEM, BUTTON, USER_ACCOUNT, MCC, COMMAND, COMMUNICATION, DEBUG, INITIALIZE, DATA, MEASURE }; /// ///ERROR : 중알람 - SW 정지됨 ///ALARM : 경알람 - SW 정지 안 됨 ///PRODUCT : 생산 관련 ///SYSTEM : SW 시스템 ///BUTTON : UI 버튼 ///USER_ACCOUNT : 장비 사용자 ///MCC : 시퀀스 차트 ///COMMAND : ReactiveLayer(Resource, Behavior)의 수행 정보를 DeliberateLayer(GUI) 로 전달 ///COMMUNICATION : 통신 ///DEBUG : 디버그용(테스트용) ///INITIALIZZE : SW 초기화 시에만 사용 /// public struct LogItem { public DateTime time; public string msg; public string position; public eLogType type; public eLogLevel level; public int unitNo; public LogItem Clone() { LogItem item = new LogItem(); item.time = this.time; item.msg = this.msg; item.position = this.position; item.type = this.type; item.level = this.level; item.unitNo = this.unitNo; return item; } } object logBufferLock = new object(); List m_logBuffer = new List(); public List LogBuffer { get { return m_logBuffer; } set { m_logBuffer = value; } } object logDisplayErrorItemLock = new object(); List m_displayedErrorItem = new List(); public List DisplayedErrorItem { get { return m_displayedErrorItem; } set { m_displayedErrorItem = value; } } object logBufferForSavingLock= new object(); Dictionary> m_logBufferForSaving = new Dictionary>(); public Dictionary> LogBufferForSaving { get { return m_logBufferForSaving; } set { m_logBufferForSaving = value; } } eLogLevel m_logLevel = eLogLevel.HIGH; public eLogLevel LogLevel { get { lock (this) { return m_logLevel; } } set { lock (this) { m_logLevel = value; } } } public LogUnit() { lock (logBufferForSavingLock) { foreach (eLogType logType in Enum.GetValues(typeof(eLogType))) { LogBufferForSaving[logType] = new List(); } } } public void DisplayLog(ListView lsvLog, List logItemList, eLogLevel masterLogLevel) { if (0 < logItemList.Count) { lsvLog.BeginUpdate(); foreach (LogItem item in logItemList) { if (item.level <= masterLogLevel || item.type == eLogType.ERROR || item.type == eLogType.ALARM) // 로그 레벨에 따른 로그 필터 기능 추가 { ListViewItem lvi = new ListViewItem(item.time.ToString("yyyyMMdd HH:mm:ss.fff")); lvi.SubItems.Add(item.msg); lsvLog.Items.Add(lvi); } } int count = lsvLog.Items.Count; uint maxLogCount = 200; if (0 < maxLogCount && maxLogCount < count) { for (int i = 0; i < count - maxLogCount; i++) { lsvLog.Items.RemoveAt(0); } } lsvLog.EndUpdate(); if (0 < lsvLog.Items.Count) { lsvLog.Items[lsvLog.Items.Count - 1].EnsureVisible(); } } } public void WriteLogToFile(string systemDataFolderPath) { foreach (eLogType logType in Enum.GetValues(typeof(eLogType))) { lock (logBufferForSavingLock) { if (0 < LogBufferForSaving[logType].Count) //로그가 있는 경우에 file 기록함. { try { string logFolder = string.Format(@"{0}\Log\{1}\{2}", systemDataFolderPath, logType.ToString(), DateTime.Now.ToString("yyyy.MM.dd")); string logFile = string.Format(@"{0}\{1}.log", logFolder, DateTime.Now.ToString("HH")); if (Directory.Exists(logFolder) == false) { Directory.CreateDirectory(logFolder); } using (FileStream file = new FileStream(logFile, FileMode.Append, FileAccess.Write)) { using (StreamWriter sw = new StreamWriter(file, System.Text.Encoding.Default)) { for (int i = 0; i < LogBufferForSaving[logType].Count; i++) { sw.WriteLine(LogBufferForSaving[logType][i]); } } } LogBufferForSaving[logType].Clear(); } catch (Exception ex) { throw ex; } } } } } public void SetLog(eLogType type, string position, string msg, eLogLevel level = eLogLevel.MIDDLE) { SetLog(type, position, msg, -1, level); } public void SetLog(eLogType type, string position, string msg, int unitNo, eLogLevel level = eLogLevel.MIDDLE) { LogItem logItem = new LogItem(); logItem.time = DateTime.Now; logItem.msg = msg; logItem.position = position; logItem.level = level; logItem.unitNo = unitNo; if (type == eLogType.ERROR) { var callSite = (new System.Diagnostics.StackTrace(1, true)).GetFrame(0); logItem.position += string.Format("(FILE NAME:{0},LINE NO:{1})", callSite.GetFileName(), callSite.GetFileLineNumber()); } logItem.type = type; lock (logBufferLock) { LogBuffer.Add(logItem); } } public bool FilterSameErrorLog(LogItem currLogItem) { if (currLogItem.type == eLogType.ERROR || currLogItem.type == eLogType.ALARM) { lock (logDisplayErrorItemLock) { foreach (LogItem log in DisplayedErrorItem) { if (log.msg == currLogItem.msg) { return true; } } DisplayedErrorItem.Add(currLogItem); } } return false; } public void ClearDisplayerErrorLog() { lock (logDisplayErrorItemLock) { if (DisplayedErrorItem.Count !=0) { DisplayedErrorItem.Clear(); } } } public void HandleLog(EventHandlerLog evtHandlerLog, string systemDataFolderPath, ListView lsvLog, eLogLevel masterLogLevel, bool enableDebugMode) { List arrangedLogItemList = new List(); lock (logBufferLock) { if (0 < LogBuffer.Count) { for (int i = 0; i < LogBuffer.Count; i++) { LogItem logItem = LogBuffer[i]; if (!FilterSameErrorLog(logItem)) { arrangedLogItemList.Add(logItem.Clone()); SaveLogToBuffer(enableDebugMode, logItem, masterLogLevel); } } LogBuffer.Clear(); Thread.Sleep(1); } } WriteLogToFile(systemDataFolderPath); DisplayLog(lsvLog, arrangedLogItemList, masterLogLevel); foreach (LogItem item in arrangedLogItemList) { evtHandlerLog(item); // 이 안에서 문제가 될 코드(예를 들면, 로그 기록)가 지나치게 많아서 lock을 걸 수가 없다 (정리 필요) } } public void HandleLogByUnit(EventHandlerLog evtHandlerLog, string systemDataFolderPath, ListView[] lsvLog, eLogLevel masterLogLevel, bool enableDebugMode) { List arrangedLogItemListAll = new List(); List arrangedLogItemList1 = new List(); List arrangedLogItemList2 = new List(); List arrangedLogItemList3 = new List(); List arrangedLogItemList4 = new List(); lock (logBufferLock) { if (0 < LogBuffer.Count) { for (int i = 0; i < LogBuffer.Count; i++) { LogItem logItem = LogBuffer[i]; if (!FilterSameErrorLog(logItem)) { SaveLogToBuffer(enableDebugMode, logItem, masterLogLevel); arrangedLogItemListAll.Add(logItem.Clone()); switch (logItem.unitNo) { case 1: arrangedLogItemList1.Add(logItem.Clone()); break; case 2: arrangedLogItemList2.Add(logItem.Clone()); break; case 3: arrangedLogItemList3.Add(logItem.Clone()); break; case 4: arrangedLogItemList4.Add(logItem.Clone()); break; default: break; } } } LogBuffer.Clear(); Thread.Sleep(1); } } WriteLogToFile(systemDataFolderPath); if (3 < lsvLog.Length) { DisplayLog(lsvLog[0], arrangedLogItemList1, masterLogLevel); DisplayLog(lsvLog[1], arrangedLogItemList2, masterLogLevel); DisplayLog(lsvLog[2], arrangedLogItemList3, masterLogLevel); DisplayLog(lsvLog[3], arrangedLogItemList4, masterLogLevel); } foreach (LogItem item in arrangedLogItemListAll) { evtHandlerLog(item); // 이 안에서 문제가 될 코드(예를 들면, 로그 기록)가 지나치게 많아서 lock을 걸 수가 없다 (정리 필요) } } private void SaveLogToBuffer(bool enableDebugMode, LogItem logItem, eLogLevel masterLogLevel) { string msg = string.Format("[TIME]:{0}\t[TYPE]:{1}\t[CONTENT]:{2}\t[POSITION]:{3}" , logItem.time.ToString("yyyy-MM-dd HH:mm:ss.fff") , Enum.GetName(typeof(eLogType), logItem.type) , logItem.msg , logItem.position); lock (logBufferForSavingLock) { if (enableDebugMode) //DB.Dao.SystemRecipe.EnableDebugMode { LogBufferForSaving[eLogType.DEBUG].Add(msg); //DEBUG 폴더에는 모든 로그를 저장 } if ((logItem.level >= masterLogLevel) || (logItem.type == eLogType.ERROR) || (logItem.type == eLogType.ALARM)) //로그 레벨에 따른 로그 필터 기능 추가 { if (enableDebugMode && logItem.type == eLogType.DEBUG) { // 로그 중복 기록 방지 } else { LogBufferForSaving[logItem.type].Add(msg); } } } } ////////////////////////////////////////////////////////////////////////// public string GetExceptionInformation(eLogType logType, Exception ex) { string msg = string.Format("[Type]\r\n{0}\r\n[Message]\r\n{1}\r\n[Exception]\r\n{2}\r\n{3}\r\n", logType.ToString(), ex.Message, ex.TargetSite.ToString(), ex.StackTrace.ToString()); if (ex.InnerException != null) { msg += "[InnerException]\r\n" + ex.InnerException.TargetSite.ToString() + "\r\n" + ex.InnerException.StackTrace.ToString(); } return msg; } public void DeleteLogOverUserPeriod(string logDataFolder, int logDeletePeriod, string[] dataFolders = null) { DirectoryInfo logFolder; //1.로그 폴더 삭제 foreach (eLogType logType in Enum.GetValues(typeof(eLogType))) { string folderName = string.Format(@"{0}\Log\{1}", logDataFolder, logType.ToString()); if (Directory.Exists(folderName) == true) { logFolder = new DirectoryInfo(folderName); foreach (DirectoryInfo datetimeDir in logFolder.GetDirectories()) { if (datetimeDir.CreationTime < DateTime.Now.AddDays(-1 * logDeletePeriod)) { datetimeDir.Delete(true); UtilUnit.logUnit.SetLog(eLogType.SYSTEM, MethodBase.GetCurrentMethod().Name, string.Format(@"로그 폴더 삭제(폴더명:{0}\{1})", logFolder, datetimeDir.Name), eLogLevel.HIGH); } Thread.Sleep(1); } } } if (dataFolders != null) { //2.사용자 정의 폴더 삭제 foreach (string dataFolder in dataFolders) { logFolder = new DirectoryInfo(dataFolder); foreach (DirectoryInfo dir in logFolder.GetDirectories()) { DirectoryInfo reviewFolder = new DirectoryInfo(dir.FullName); foreach (DirectoryInfo datetimeDir in reviewFolder.GetDirectories()) { if (datetimeDir.CreationTime < DateTime.Now.AddDays(-1 * logDeletePeriod)) { //날짜폴더 삭제 datetimeDir.Delete(true); UtilUnit.logUnit.SetLog(eLogType.SYSTEM, MethodBase.GetCurrentMethod().Name, string.Format("검사 폴더 삭제(폴더명:{0})", datetimeDir.Name), eLogLevel.HIGH); } Thread.Sleep(1); } } } } } } }