using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Windows; using leak_test_project.Models; namespace leak_test_project.Utils { /// /// 통신 로그 및 시스템 이력을 파일로 저장하는 유틸리티 /// public static class FileLogger { private static readonly string LogDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); private static readonly object _lock = new object(); /// /// 검사 데이터를 Logs/yyyy-MM-dd.csv 파일에 저장함 /// public static void LogInspectData(InspectData data) { lock (_lock) { try { if (!Directory.Exists(LogDirectory)) Directory.CreateDirectory(LogDirectory); string dateStr = DateTime.Now.ToString("yyyy-MM-dd"); string filePath = Path.Combine(LogDirectory, $"{dateStr}.csv"); bool isNewFile = !File.Exists(filePath); // CSV 헤더: Date,Time,Channel,ID,Value,Judgment,Mode,LineNo,ProductType,SpecUL,SpecLL,Retest if (isNewFile) { string header = "Date,Time,Channel,ID,Value,Judgment,Mode,LineNo,ProductType,SpecUL,SpecLL,Retest" + Environment.NewLine; File.WriteAllText(filePath, header, Encoding.UTF8); } string csvLine = $"{Esc(data.InspectDate)},{Esc(data.InspectTime)},{Esc(data.Channel)},{Esc(data.ProductId)}," + $"{Esc(data.MeasuredValue)},{Esc(data.Judgment)},{Esc(data.Mode)},{Esc(data.LineNo)}," + $"{Esc(data.ProductType)},{Esc(data.SpecUL)},{Esc(data.SpecLL)},{Esc(data.Retest)}{Environment.NewLine}"; File.AppendAllText(filePath, csvLine, Encoding.UTF8); } catch (Exception ex) { Console.WriteLine($"[FileLogger Error] {ex.Message}"); } } } /// /// 단순 텍스트 로그 (기존 호환성 유지용) /// public static void Log(string tag, string message) { lock (_lock) { try { if (!Directory.Exists(LogDirectory)) Directory.CreateDirectory(LogDirectory); string dateStr = DateTime.Now.ToString("yyyy-MM-dd"); string filePath = Path.Combine(LogDirectory, $"{dateStr}_system.log"); string logEntry = $"[{DateTime.Now:HH:mm:ss.fff}] [{tag}] {message}{Environment.NewLine}"; File.AppendAllText(filePath, logEntry, Encoding.UTF8); } catch (Exception ex) { Console.WriteLine($"[FileLogger Error] {ex.Message}"); } } } /// /// CSV 값 이스케이프: 쉼표, 따옴표, 줄바꿈이 포함된 값을 안전하게 감싸줌 /// private static string Esc(string value) { if (string.IsNullOrEmpty(value)) return ""; if (value.Contains(",") || value.Contains("\"") || value.Contains("\n")) return $"\"{value.Replace("\"", "\"\"")}\""; return value; } } public static class LogParser { private static readonly string LogDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); public static List ParseLogs(DateTime start, DateTime end, string judgmentFilter = "[전체]", string serialFilter = "") { var results = new List(); if (!Directory.Exists(LogDirectory)) { // 디렉토리가 없으면 빈 리스트 반환 return results; } // 날짜 범위 내의 모든 로그 파일 찾기 (.csv) var files = Directory.GetFiles(LogDirectory, "*.csv") .Where(f => { string fileName = Path.GetFileNameWithoutExtension(f); if (DateTime.TryParse(fileName, out DateTime fileDate)) { return fileDate.Date >= start.Date && fileDate.Date <= end.Date; } return false; }); foreach (var file in files) { try { var lines = File.ReadAllLines(file); if (lines.Length <= 1) continue; // Header only or empty // CSV 헤더: Date,Time,Channel,ID,Value,Judgment,Mode,LineNo,ProductType,SpecUL,SpecLL,Retest for (int i = 1; i < lines.Length; i++) { string line = lines[i]; if (string.IsNullOrWhiteSpace(line)) continue; var parts = line.Split(','); if (parts.Length < 12) continue; string date = parts[0].Trim(); string time = parts[1].Trim(); string channel = parts[2].Trim(); string id = parts[3].Trim(); string val = parts[4].Trim(); string judg = parts[5].Trim(); string mode = parts[6].Trim(); string lineNo = parts[7].Trim(); string prodType = parts[8].Trim(); string specUl = parts[9].Trim(); string specLl = parts[10].Trim(); string retest = parts[11].Trim(); // 필터 적용 if (judgmentFilter != "[전체]" && judg != judgmentFilter) continue; if (!string.IsNullOrEmpty(serialFilter) && !id.Contains(serialFilter)) continue; results.Add(new InspectData { InspectDate = date, InspectTime = time, Channel = channel, ProductId = id, MeasuredValue = val, Judgment = judg, Mode = mode, LineNo = lineNo, ProductType = prodType, SpecUL = specUl, SpecLL = specLl, Retest = retest }); } } catch (Exception ex) { Console.WriteLine($"[LogParser] Error reading file {file}: {ex.Message}"); } } return results.OrderByDescending(r => r.InspectDate).ThenByDescending(r => r.InspectTime).ToList(); } } /// /// 데이터를 CSV 파일로 내보내는 유틸리티 /// public static class CsvExporter { /// /// 컬렉션 데이터를 CSV 파일로 저장함 /// /// 데이터 모델 클래스 /// 내보낼 데이터 목록 /// 저장할 파일 경로 public static bool ExportToCsv(IEnumerable items, string filePath) { try { var sb = new StringBuilder(); var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); // Header foreach (var prop in props) { sb.Append(prop.Name).Append(","); } sb.AppendLine(); // Body foreach (var item in items) { foreach (var prop in props) { var val = prop.GetValue(item, null); var str = val?.ToString() ?? ""; if (str.Contains(",") || str.Contains("\"") || str.Contains("\n")) sb.Append($"\"{str.Replace("\"", "\"\"")}\""); else sb.Append(str); sb.Append(","); } sb.AppendLine(); } File.WriteAllText(filePath, sb.ToString(), Encoding.UTF8); return true; } catch (Exception ex) { MessageBox.Show($"CSV 저장 실패: {ex.Message}"); return false; } } } }