using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.Threading; using SLC1_N; namespace SLC1_N { public class mxlLog // 日志文件类 { // 日志级别 public enum LogLevel { LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_XXX }; // 单例实例 private static readonly mxlLog instance = new mxlLog(); public static mxlLog Instance { get { return instance; } } private readonly object mutex = new object(); private string logDir; private string logPrefix = "log_"; private long maxFileSize = 10 * 1024 * 1024; // 10MB private int maxBackupFiles = 5; // 允许文件最大备份数 private LogLevel minLevel = LogLevel.LOG_DEBUG; // 记录级别,大于则生成文件 // 标志位控制 public bool IsDebugEnabled { get; set; } = false; public bool IsInfoEnabled { get; set; } = false; public bool IsWarningEnabled { get; set; } = false; public bool IsErrorEnabled { get; set; } = false; public bool IsXXXEnabled { get; set; } = false; // 构造函数 - 自动初始化到当前目录 private mxlLog() { // 自动设置为软件当前目录下的Logs文件夹 logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); minLevel = LogLevel.LOG_DEBUG; // 确保日志目录存在 if (!Directory.Exists(logDir)) { Directory.CreateDirectory(logDir); } } // 初始化 public void Initialize(string dir = null, // 修改日志目录 string prefix = null, // 修改日志文件名前缀 long? maxSize = null, // 限制单个日志文件最大 int? maxBackups = null,// 最多保留备份数 LogLevel? minLevel = null, // 只写入xxx及以上级别 bool? isDebugEnabled = null, bool? isInfoEnabled = null, // 写入使能 bool? isWarningEnabled = null, bool? isErrorEnabled = null, bool? isXXXEnabled = null) { lock (mutex) { this.logDir = dir ?? this.logDir; this.logPrefix = prefix ?? this.logPrefix; this.maxFileSize = maxSize ?? this.maxFileSize; this.maxBackupFiles = maxBackups ?? this.maxBackupFiles; this.minLevel = minLevel ?? this.minLevel; // 设置标志位 IsDebugEnabled = isDebugEnabled ?? IsDebugEnabled; IsInfoEnabled = isInfoEnabled ?? IsInfoEnabled; IsWarningEnabled = isWarningEnabled ?? IsWarningEnabled; IsErrorEnabled = isErrorEnabled ?? IsErrorEnabled; IsXXXEnabled = isXXXEnabled ?? IsXXXEnabled; if (!Directory.Exists(logDir)) { Directory.CreateDirectory(logDir); } } } // 写入日志 public void Write(LogLevel level, string message, Exception ex = null) { if (!IsLevelEnabled(level) || level < minLevel) // 检查使能 return; lock (mutex) { try { string logFile = GetCurrentLogFilePath(); CheckFileSize(logFile); string logEntry = $"{GetCurrentTimeStamp()} [{GetLevelString(level)}] {message}"; if (ex != null) { logEntry += $"\nException: {ex.GetType().Name}\nMessage: {ex.Message}\nStack Trace: {ex.StackTrace}"; } File.AppendAllText(logFile, logEntry + Environment.NewLine); } catch (Exception logEx) { HandleLogFailure(logEx); } } } // 清理旧日志文件 public void ClearOldLogs(int keepDays = 30) { try { lock (mutex) { if (!Directory.Exists(logDir)) return; var cutoffDate = DateTime.Now.AddDays(-keepDays); // 截止日期 var allLogFiles = Directory.GetFiles(logDir, $"{logPrefix}*.log*"); // 筛选 foreach (var file in allLogFiles) { try { // 尝试从文件名中解析日期 var fileName = Path.GetFileNameWithoutExtension(file); if (fileName.StartsWith(logPrefix)) { var datePart = fileName.Substring(logPrefix.Length); //去掉前缀,获取日期部分 // 尝试解析日期 yyyyMMdd if (datePart.Length >= 8 && // 日期是否8个字符("20250101") 则存到fileDate DateTime.TryParseExact(datePart.Substring(0, 8), "yyyyMMdd", null, System.Globalization.DateTimeStyles.None, out var fileDate)) { if (fileDate < cutoffDate) // 对比日期 { File.Delete(file); Write(LogLevel.LOG_INFO, $"删除旧日志文件: {file}"); } } else if (File.Exists(file)) // 对于log.1, .log.2,检查最后修改时间 { var lastWriteTime = File.GetLastWriteTime(file); if (lastWriteTime < cutoffDate) { File.Delete(file); Write(LogLevel.LOG_INFO, $"删除旧日志备份: {file}"); } } } } catch (Exception ex) { Write(LogLevel.LOG_ERROR, $"删除旧日志文件失败: {file}", ex); } } } } catch (Exception ex) { Write(LogLevel.LOG_ERROR, "清除旧日志失败", ex); } } // 快捷方法 public void Debug(string message) => Write(LogLevel.LOG_DEBUG, message); public void Info(string message) => Write(LogLevel.LOG_INFO, message); public void Warning(string message, Exception ex = null) => Write(LogLevel.LOG_WARNING, message, ex); public void Error(string message, Exception ex = null) => Write(LogLevel.LOG_ERROR, message, ex); public void XXX(string message, Exception ex = null) => Write(LogLevel.LOG_XXX, message, ex); public void MESDebug(string message) => Write(LogLevel.LOG_DEBUG, $"[MES] {message}"); #region 私有方法 // 获取使能 private bool IsLevelEnabled(LogLevel level) { switch (level) { case LogLevel.LOG_DEBUG: return IsDebugEnabled; case LogLevel.LOG_INFO: return IsInfoEnabled; case LogLevel.LOG_WARNING: return IsWarningEnabled; case LogLevel.LOG_ERROR: return IsErrorEnabled; case LogLevel.LOG_XXX: return IsXXXEnabled; default: return true; } } // 生成当前日志文件的完整路径 private string GetCurrentLogFilePath() { string dateStamp = DateTime.Now.ToString("yyyyMMdd"); return Path.Combine(logDir, $"{logPrefix}{dateStamp}.log"); } // 超过大小,触发轮转(当前备份,重新新建) private void CheckFileSize(string logFile) { if (!File.Exists(logFile)) return; FileInfo fileInfo = new FileInfo(logFile); if (fileInfo.Length >= maxFileSize) { RotateLogFiles(logFile); } } // 实现日志轮转 private void RotateLogFiles(string currentLogFile) { for (int i = maxBackupFiles - 1; i >= 1; i--) { string source = $"{currentLogFile}.{i}"; string dest = $"{currentLogFile}.{i + 1}"; if (File.Exists(source)) { File.Move(source, dest); } } if (File.Exists(currentLogFile)) { File.Move(currentLogFile, $"{currentLogFile}.1"); } } private string GetCurrentTimeStamp() { return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); } private string GetLevelString(LogLevel level) { switch (level) { case LogLevel.LOG_DEBUG: return "DEBUG"; case LogLevel.LOG_INFO: return "INFO"; case LogLevel.LOG_WARNING: return "WARNING"; case LogLevel.LOG_ERROR: return "ERROR"; case LogLevel.LOG_XXX: return "XXX"; default: return "UNKNOWN"; } } // 主日志系统失败(如磁盘满、权限问题) private void HandleLogFailure(Exception ex) { try { string fallbackPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "LL_log_fallback.txt"); File.AppendAllText(fallbackPath, $"{GetCurrentTimeStamp()} [LOG_ERROR] Failed to write log: {ex.Message}" + Environment.NewLine); } catch { /* 最终保底措施 */ } } #endregion } } // 使用方法 : mxlLog.Instance.Error($"异常 ,行号{ex.StackTrace} ", ex); // mxlLog.Instance.IsErrorEnabled = true; 使能错误log // mxlLog.Instance.ClearOldLogs(5); 清理日志,仅保留近5天