using log4net; using log4net.Config; using log4net.Repository; using System.Text; using System.Timers; using System.Xml; namespace LogHelper { /// /// 日志帮助类 /// public static class LogHub { /// /// 日志仓库 /// public static ILoggerRepository? LoggerRepository { get; set; } #region 写入日志 private static ILog? GetLog(ILogType type, string flagKey) { if (LoggerRepository == null) return null; if (type.SubLogNames.ContainsKey(flagKey)) return LogManager.GetLogger(LoggerRepository.Name, type.SubLogNames[flagKey]); var defaultKey = string.Empty; foreach (var key in type.SubLogNames.Keys) { defaultKey = key; break; } return LogManager.GetLogger(LoggerRepository.Name, type.SubLogNames[defaultKey]); } #region Info /// /// 运行记录 /// /// 日志类型 /// 消息 /// 异常 /// 日志子项索引Key public static void Info(this ILogType type, string message, Exception ex, string flagKey) => GetLog(type, flagKey.ToUpper())?.Info(GetLogMessage(message, ex)); /// /// 运行记录 /// /// 日志类型 /// 消息 /// 日志子项索引Key public static void Info(this ILogType type, string message, string flagKey) => type.Info(message, null!, flagKey); /// /// 运行记录 /// /// 日志类型 /// 异常 /// 日志子项索引Key public static void Info(this ILogType type, Exception ex, string flagKey) => type.Info(null!, ex, flagKey); #endregion Info #region Error /// /// 错误记录 /// /// 日志类型 /// 消息 /// 异常 /// 日志子项索引Key public static void Error(this ILogType type, string message, Exception ex, string flagKey) => GetLog(type, flagKey.ToUpper())?.Error(GetLogMessage(message, ex)); /// /// 错误记录 /// /// 日志类型 /// 消息 /// 日志子项索引Key public static void Error(this ILogType type, string message, string flagKey) => type.Error(message, null!, flagKey); /// /// 错误记录 /// /// 日志类型 /// 异常 /// 日志子项索引Key public static void Error(this ILogType type, Exception ex, string flagKey) => type.Error(null!, ex, flagKey); #endregion Error #region Warn /// /// 警告 /// /// 日志类型 /// 消息 /// 异常 /// 日志子项索引Key public static void Warn(this ILogType type, string message, Exception ex, string flagKey) => GetLog(type, flagKey.ToUpper())?.Warn(GetLogMessage(message, ex)); /// /// 警告 /// /// 日志类型 /// 消息 /// 日志子项索引Key public static void Warn(this ILogType type, string message, string flagKey) => type.Warn(message, null!, flagKey); /// /// 警告 /// /// 日志类型 /// 异常 /// 日志子项索引Key public static void Warn(this ILogType type, Exception ex, string flagKey) => type.Warn(null!, ex, flagKey); #endregion Warn /// /// 获取详细日志信息 /// /// 信息 /// 异常 /// 详细信息 private static string GetLogMessage(string message, Exception ex) { if (string.IsNullOrEmpty(message) && ex == null) return "Unknown error."; if (string.IsNullOrEmpty(message) && ex != null) return $"[Type:{ex.GetType().Name}][StackTrace:{ex.StackTrace}][Message:{ex.Message.Replace("\r\n", " ")}]"; if (!string.IsNullOrEmpty(message) && ex == null) return message; return $"[Message:{message}][Type:{ex!.GetType().Name}][StackTrace:{ex.StackTrace}][Ex Message:{ex.Message.Replace("\r\n", " ")}]"; } #endregion 写入日志 #region 初始化日志 private static string? _configPath = "Log"; private static int _fileSize = 500; private static readonly List InitList = new List(); private static readonly LogConfig ConfigModel = new LogConfig(); private static bool _cleanSet = false; private static string? _previousCleanDay = null; private static int _cleanDays = 30; private static System.Timers.Timer? _logCleanTimer; /// /// 设置配置信息 /// /// public static void SetConfigInfo(LogConfig logConfig) { SetConfigPath(logConfig.LogPath); SetLogFileSize(logConfig.LogSize); SetLogCleanDays(logConfig.LogDays); SetConfigInfo(logConfig.Logs!); } /// /// 日志配置 /// /// public static void SetConfigPath(string path) { _configPath = path; } /// /// 设置日志层级关系 /// /// 配置信息 public static void SetConfigInfo(List logConfigs) { ConfigModel.Logs = logConfigs; } /// /// 设置日志项目文件数量和大小 /// /// 单文件大小(单位MB,最小10) public static void SetLogFileSize(int size) { if (size < 10) return; _fileSize = size; } /// /// 设置日志清理周期 /// /// 清理周期 public static void SetLogCleanDays(int days) { if (days < 7) return; _cleanDays = days; } /// /// 初始化Log组件 /// /// 日志类型数组 public static void Init(params ILogType[] types) { var addedTypes = types.Where(p => !InitList.Contains(p)).ToList(); if (addedTypes.Count == 0) return; if (ConfigModel.Logs == null || ConfigModel.Logs.Count == 0) throw new Exception("Log init, config is null."); _configPath = ConfigModel.Logs.FirstOrDefault(p => !string.IsNullOrEmpty(p.FileName))!.FileName; var xmlDoc = new XmlDocument(); xmlDoc.AppendChild(xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null)); var configuration = xmlDoc.CreateElement("configuration"); var root = xmlDoc.CreateElement("log4net"); foreach (var item in addedTypes) { InitList.Add(item); var config = ConfigModel.Logs.FirstOrDefault(p => p.Name == item.LogName); if (config is null) { config = new LogConfigModel { Name = item.LogName, FileName = _configPath, SubLogNames = item.SubLogNames }; } else { config.SubLogNames ??= new Dictionary(); foreach (var key in config.SubLogNames.Keys.Where(key => item.SubLogNames == null || !item.SubLogNames.ContainsKey(key))) { item.SubLogNames?.Add(key, config.SubLogNames[key]); } foreach (var key in item.SubLogNames!.Keys.Where(key => !config.SubLogNames.ContainsKey(key))) { config.SubLogNames.Add(key, item.SubLogNames[key]); } } if (item.SubLogNames == null || item.SubLogNames.Count == 0) continue; CreateXml(xmlDoc, root, config); } configuration.AppendChild(root); xmlDoc.AppendChild(configuration); //InitRepository.LoggerRepository ??= LogManager.CreateRepository("NETCoreRepository"); LoggerRepository ??= LogManager.CreateRepository("NETCoreRepository"); XmlConfigurator.Configure(LoggerRepository, new StreamReader(new MemoryStream(Encoding.ASCII.GetBytes(xmlDoc.OuterXml))).BaseStream); xmlDoc.Save("./log4net.config"); if (_cleanSet) return; _cleanSet = true; _previousCleanDay = DateTime.Now.ToString("yyyyMMdd"); // clean log _logCleanTimer = new System.Timers.Timer(1000 * 60); _logCleanTimer.Elapsed += LogCleanTimer_Elapsed; _logCleanTimer.Enabled = true; } /// /// 创建XML节点 /// /// XML文档 /// /// private static void CreateXml(XmlDocument xmlDoc, XmlElement root, LogConfigModel config) { foreach (var key in config.SubLogNames!.Keys) { // 创建 Logger var logger = xmlDoc.CreateElement("logger"); logger.SetAttribute("name", config.SubLogNames[key]); var level = xmlDoc.CreateElement("level"); level.SetAttribute("value", "ALL"); var appenderRef = xmlDoc.CreateElement("appender-ref"); appenderRef.SetAttribute("ref", $"{config.SubLogNames[key]}Appender"); logger.AppendChild(level); logger.AppendChild(appenderRef); // 创建 Appender var appender = xmlDoc.CreateElement("appender"); appender.SetAttribute("name", $"{config.SubLogNames[key]}Appender"); appender.SetAttribute("type", "log4net.Appender.RollingFileAppender"); var param = xmlDoc.CreateElement("param"); param.SetAttribute("name", "Encoding"); param.SetAttribute("value", "utf-8"); appender.AppendChild(param); var file = xmlDoc.CreateElement("file"); file.SetAttribute("value", Path.Combine(config.FileName!, config.Name!)); appender.AppendChild(file); var appendToFile = xmlDoc.CreateElement("appendToFile"); appendToFile.SetAttribute("value", "true"); appender.AppendChild(appendToFile); var rollingStyle = xmlDoc.CreateElement("rollingStyle"); rollingStyle.SetAttribute("value", "Composite"); appender.AppendChild(rollingStyle); var maxSizeRollBackups = xmlDoc.CreateElement("maxSizeRollBackups"); maxSizeRollBackups.SetAttribute("value", "-1"); appender.AppendChild(maxSizeRollBackups); var maximumFileSize = xmlDoc.CreateElement("maximumFileSize"); maximumFileSize.SetAttribute("value", $"{_fileSize}MB"); appender.AppendChild(maximumFileSize); var lockingModel = xmlDoc.CreateElement("lockingModel"); lockingModel.SetAttribute("type", "log4net.Appender.FileAppender+MinimalLock"); appender.AppendChild(lockingModel); var staticLogFileName = xmlDoc.CreateElement("staticLogFileName"); staticLogFileName.SetAttribute("value", "false"); appender.AppendChild(staticLogFileName); var datePattern = xmlDoc.CreateElement("DatePattern"); datePattern.SetAttribute("value", $"/yyyyMMdd/'{config.SubLogNames[key]}.log'"); appender.AppendChild(datePattern); var layout = xmlDoc.CreateElement("layout"); layout.SetAttribute("type", "log4net.Layout.PatternLayout"); var conversionPattern = xmlDoc.CreateElement("conversionPattern"); conversionPattern.SetAttribute("value", "%date || %5level || %logger || %message || %exception || end %newline"); layout.AppendChild(conversionPattern); appender.AppendChild(layout); root.AppendChild(appender); root.AppendChild(logger); } } private static void LogCleanTimer_Elapsed(object? sender, ElapsedEventArgs e) { try { if (_previousCleanDay!.Equals(DateTime.Now.ToString("yyyyMMdd"))) return; _previousCleanDay = DateTime.Now.ToString("yyyyMMdd"); if (!Directory.Exists(_configPath)) return; string[] typeDirs = Directory.GetDirectories(_configPath); foreach (var t in typeDirs) { string[] dateDirs = Directory.GetDirectories(t); foreach (var t1 in dateDirs) { var dirName = t1[(t1.LastIndexOf('\\') + 1)..]; if (Convert.ToInt32(dirName) < Convert.ToInt32(DateTime.Now.AddDays(_cleanDays * -1).ToString("yyyyMMdd"))) Directory.Delete(t1, true); } } } catch (Exception) { //TODO:增加日志 } } #endregion 初始化日志 } }