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 初始化日志
}
}