440 lines
16 KiB
C#
440 lines
16 KiB
C#
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 };
|
|
/// <summary>
|
|
///ERROR : 중알람 - SW 정지됨
|
|
///ALARM : 경알람 - SW 정지 안 됨
|
|
///PRODUCT : 생산 관련
|
|
///SYSTEM : SW 시스템
|
|
///BUTTON : UI 버튼
|
|
///USER_ACCOUNT : 장비 사용자
|
|
///MCC : 시퀀스 차트
|
|
///COMMAND : ReactiveLayer(Resource, Behavior)의 수행 정보를 DeliberateLayer(GUI) 로 전달
|
|
///COMMUNICATION : 통신
|
|
///DEBUG : 디버그용(테스트용)
|
|
///INITIALIZZE : SW 초기화 시에만 사용
|
|
/// </summary>
|
|
|
|
|
|
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<LogItem> m_logBuffer = new List<LogItem>();
|
|
public List<LogItem> LogBuffer
|
|
{
|
|
get { return m_logBuffer; }
|
|
set { m_logBuffer = value; }
|
|
}
|
|
|
|
object logDisplayErrorItemLock = new object();
|
|
|
|
List<LogItem> m_displayedErrorItem = new List<LogItem>();
|
|
public List<LogItem> DisplayedErrorItem
|
|
{
|
|
get { return m_displayedErrorItem; }
|
|
set { m_displayedErrorItem = value; }
|
|
}
|
|
|
|
object logBufferForSavingLock= new object();
|
|
|
|
Dictionary<eLogType, List<string>> m_logBufferForSaving = new Dictionary<eLogType, List<string>>();
|
|
public Dictionary<eLogType, List<string>> 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<string>();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void DisplayLog(ListView lsvLog, List<LogItem> 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<LogItem> arrangedLogItemList = new List<LogItem>();
|
|
|
|
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<LogItem> arrangedLogItemListAll = new List<LogItem>();
|
|
|
|
List<LogItem> arrangedLogItemList1 = new List<LogItem>();
|
|
List<LogItem> arrangedLogItemList2 = new List<LogItem>();
|
|
List<LogItem> arrangedLogItemList3 = new List<LogItem>();
|
|
List<LogItem> arrangedLogItemList4 = new List<LogItem>();
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
}
|