code-layout/GeneratorCode/Logs/NLog.cs

585 lines
20 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using GeneratorCode.Configure;
using JetBrains.Annotations;
namespace GeneratorCode.Logs
{
public enum NLogLevel
{
Fatal = 0,
Crash,
Error,
Warring,
Info,
Debug,
MaxLevel
}
public enum CacheOptMode
{
Drop = 0,
Replease
}
public class NLogConfig
{
private object _cfgLock = new object();
public delegate void LogCfgChangedHandle();
public static event LogCfgChangedHandle OnLogCfgChanged;
public NLogConfig()
{
LogConfig();
NConfig.OnConfigChanged += () => { LogCfgChanged(); };
}
protected static void LogCfgChanged()
{
OnLogCfgChanged?.Invoke();
}
public bool LogEnable { get; set; }
public NLogLevel LogLevel { get; set; }
public NLogLevel DefaultLevel { get; set; }
public bool AsyncMode { get; set; }
public bool ForceNewLine { get; set; }
public bool ShowDate { get; set; }
public bool ShowTime { get; set; }
public bool ShowMSec { get; set; }
public bool ShowLevel { get; set; }
public bool ShowCodeFile { get; set; }
public bool ShowFunction { get; set; }
public bool ShowCodeLine { get; set; }
public bool EnConsole { get; set; }
public bool EnTrace { get; set; }
public bool EnDebug { get; set; }
public bool EnFile { get; set; }
public int MaxItemsCache { get; set; }
public CacheOptMode CacheMode { get; set; }
public int SleepTime { get; set; }
public int NumOutItems { get; set; }
public string DirPath { get; set; }
public string FileNamePre { get; set; }
public bool EnSplitLog { get; set; }
public bool SplitByData { get; set; }
public int SplitBySize { get; set; }
public bool RoolbackFile { get; set; }
public int MaxFileNum { get; set; }
public void LogConfig()
{
lock (_cfgLock)
{
LogEnable = NConfig.GetCfgValue("LogGlobal", "LogEnable", false);
LogLevel = (NLogLevel)NConfig.GetCfgValue("LogGlobal", "LogLevel", (int)NLogLevel.MaxLevel);
DefaultLevel = (NLogLevel)NConfig.GetCfgValue("LogGlobal", "DefaultLogLevel", (int)NLogLevel.Info);
AsyncMode = NConfig.GetCfgValue("LogGlobal", "AsyncMode", false);
ForceNewLine = NConfig.GetCfgValue("LogGlobal", "AutoForceNewLine", false);
ShowDate = NConfig.GetCfgValue("LogFormat", "ShowDate", true);
ShowTime = NConfig.GetCfgValue("LogFormat", "ShowTime", true);
ShowMSec = NConfig.GetCfgValue("LogFormat", "ShowMSec", true);
ShowLevel = NConfig.GetCfgValue("LogFormat", "ShowLevel", true);
ShowCodeFile = NConfig.GetCfgValue("LogFormat", "ShowCodeFile", true);
ShowFunction = NConfig.GetCfgValue("LogFormat", "ShowFunction", true);
ShowCodeLine = NConfig.GetCfgValue("LogFormat", "ShowCodeLine", true);
EnConsole = NConfig.GetCfgValue("LogOutput", "Console", true);
EnTrace = NConfig.GetCfgValue("LogOutput", "Trace", false);
EnDebug = NConfig.GetCfgValue("LogOutput", "Debug", true);
EnFile = NConfig.GetCfgValue("LogOutput", "File", false);
if (AsyncMode)
{
MaxItemsCache = NConfig.GetCfgValue("AsyncLogSetting", "MaxItemsCache", 0);
if (MaxItemsCache == 0) MaxItemsCache = int.MaxValue;
CacheMode = (CacheOptMode)NConfig.GetCfgValue("AsyncLogSetting", "CacheFullOpts", (int)CacheOptMode.Drop);
NumOutItems = NConfig.GetCfgValue("AsyncLogSetting", "NumItemsOutEachTime", 10);
}
SleepTime = NConfig.GetCfgValue("AsyncLogSetting", "ThreadSleep", 10);
if (EnFile)
{
DirPath = NConfig.GetCfgValue("FileLogSetting", "Path", @"");
if (DirPath == "" || !Directory.Exists(DirPath) || DirPath == @".\")
{
DirPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + @"\";
}
if (!Directory.Exists(DirPath))
{
Directory.CreateDirectory(DirPath);
}
FileNamePre = NConfig.GetCfgValue("FileLogSetting", "FileNamePrefix", "");
EnSplitLog = NConfig.GetCfgValue("FileLogSetting", "AutoSplitFile", true);
if (EnSplitLog)
{
SplitByData = NConfig.GetCfgValue("SplitFiles", "SplitByDate", true);
SplitBySize = NConfig.GetCfgValue("SplitFiles", "SplitBySize", 4);
RoolbackFile = NConfig.GetCfgValue("SplitFiles", "FileNameRollback", true);
MaxFileNum = NConfig.GetCfgValue("SplitFiles", "MaxFileNameNum", 10);
}
}
}
}
}
public class NLogItem
{
public NLogItem(NLogLevel level = NLogLevel.Debug,
[NotNull] string logContent = "",
[NotNull] string fileName = "",
[NotNull] string funName = "",
int lineNo = 0,
DateTime? dt = null)
{
if (dt == null)
{
LogStamp = DateTime.Now;
}
else
{
LogStamp = (DateTime)dt;
}
LogLevel = level;
LogContent = logContent;
CodeFile = fileName;
CodeFunction = funName;
CodeLine = lineNo;
}
public DateTime LogStamp { get; set; }
public NLogLevel LogLevel { get; set; }
public string LogContent { get; set; }
public string CodeFile { get; set; }
public int CodeLine { get; set; }
public string CodeFunction { get; set; }
}
public static class NLog
{
private static NLogConfig _logCfg;
private static readonly ConcurrentQueue<NLogItem> _logItemCollection = new ConcurrentQueue<NLogItem>();
private static readonly object _logOutputLock = new object();
private static string _logFileName = "";
private static uint _logFileNum = 0;
private static StreamWriter _logSw = null;
private static void CreateLogFileHead()
{
_logSw?.WriteLine("FileName: " + _logFileName);
_logSw?.WriteLine("CreateTime: " + string.Format("{0:yyyy-MM-dd HH:mm:ss}", DateTime.Now));
_logSw?.WriteLine("Program: " + Process.GetCurrentProcess().MainModule.FileName);
_logSw?.WriteLine("PID: " + Process.GetCurrentProcess().Id);
_logSw?.WriteLine("Split Count: " + (_logFileNum - 1).ToString());
_logSw?.WriteLine("--------------------------------------------------");
_logSw?.Flush();
}
private static void ConfigInit()
{
if (_logCfg.EnFile)
{
_logFileName = string.Format("{0}{1}[{3:yyyy-MM-dd_HH-mm}][{4:d}]_{2}",
_logCfg.DirPath,
_logCfg.FileNamePre.Length > 0 ? _logCfg.FileNamePre + "_" : "",
Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().MainModule.FileName),
DateTime.Now,
Process.GetCurrentProcess().Id);
if (_logCfg.EnSplitLog && _logCfg.RoolbackFile && _logCfg.MaxFileNum > 0)
{
_logFileName += $"_{_logFileNum:d3}";
_logFileNum = Convert.ToUInt32((_logFileNum + 1) % _logCfg.MaxFileNum);
}
_logFileName += ".log";
if (File.Exists(_logFileName))
{
if (_logCfg.EnSplitLog)
{
File.Delete(_logFileName);
}
}
_logSw = new StreamWriter(_logFileName, true);
CreateLogFileHead();
}
}
public static void NLog_Finish()
{
if (_logCfg.EnFile)
{
_logSw?.Flush();
_logSw?.Close();
}
}
public static void NLog_Init()
{
_logCfg = new NLogConfig();
NLogConfig.OnLogCfgChanged += () =>
{
_logSw?.Close();
_logCfg.LogConfig();
ConfigInit();
};
ConfigInit();
var asynWork = new Thread(() =>
{
uint cnt = 0;
while (true)
{
var lastDt = DateTime.Now;
var tolOut = Math.Min(_logCfg.NumOutItems, _logItemCollection.Count);
foreach (var val in Enumerable.Range(1, tolOut))
{
if (_logItemCollection.TryDequeue(out var logItem))
{
LogOutput(logItem);
}
}
Thread.Sleep(_logCfg.SleepTime);
// 每秒执行一次维护工作
if ((++cnt % (1000 / _logCfg.SleepTime)) != 0)
{
continue;
}
_logSw?.Flush();
if (_logCfg.EnSplitLog)
{
bool isNeedSplit = false;
if (_logCfg.SplitByData && lastDt.Day != DateTime.Now.Day)
{
isNeedSplit = true;
}
else if (_logCfg.SplitBySize > 0 && (new FileInfo(_logFileName)).Length > _logCfg.SplitBySize * (1024 * 1024))
{
isNeedSplit = true;
}
if (isNeedSplit)
{
_logSw?.Close();
_logSw?.Dispose();
_logSw = null;
string parttn = string.Format("*[{0:d3}]_{1}",
Process.GetCurrentProcess().Id,
Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().MainModule.FileName));
_logFileName = string.Format("{0}{1}[{3:yyyy-MM-dd_HH-mm}][{4:d}]_{2}",
_logCfg.DirPath,
_logCfg.FileNamePre.Length > 0 ? _logCfg.FileNamePre + "_" : "",
Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().MainModule.FileName),
DateTime.Now,
Process.GetCurrentProcess().Id);
if (_logCfg.EnSplitLog && _logCfg.RoolbackFile && _logCfg.MaxFileNum > 0)
{
_logFileName += $"_{_logFileNum:d3}";
parttn += $"_{_logFileNum:d3}";
_logFileNum = Convert.ToUInt32((_logFileNum + 1) % _logCfg.MaxFileNum);
}
_logFileName += ".log";
parttn += ".log";
foreach (var f in Directory.GetFiles(_logCfg.DirPath, parttn, SearchOption.TopDirectoryOnly))
{
File.Delete(f);
Trace.WriteLine("Delect Rollback log: " + f);
}
_logSw = new StreamWriter(_logFileName, true);
CreateLogFileHead();
}
}
}
})
{
Name = "Log Async Output Thread",
IsBackground = true
};
asynWork.Start();
}
private static string LogLevelToString([NotNull] NLogLevel logLevel)
{
string[] level = { "F", "C", "E", "I", "W", "D" };
if ((int) logLevel < level.Length && (int) logLevel >= 0)
return level[(int) logLevel];
return "U";
}
private static string LogFormat(NLogLevel logLevel, string logMsg, string fileName, string funName, int lineNo,
DateTime dt)
{
var msg = "";
if (_logCfg.ShowDate || _logCfg.ShowTime)
{
msg += "[";
}
if (_logCfg.ShowDate)
{
msg += dt.ToString("yyyy-MM-dd");
if (_logCfg.ShowTime)
{
msg += " ";
}
}
if (_logCfg.ShowTime)
{
msg += dt.ToString("HH:mm:ss");
if (_logCfg.ShowMSec)
{
msg += "." + dt.ToString("fff");
}
}
if (_logCfg.ShowDate || _logCfg.ShowTime)
{
msg += "]";
}
if (_logCfg.ShowLevel)
{
msg += " [" + LogLevelToString(logLevel) + "] ";
}
if (_logCfg.ShowCodeFile)
{
msg += "[" + Path.GetFileName(fileName) + "] ";
}
if (_logCfg.ShowFunction)
{
msg += "- " + funName;
}
if (_logCfg.ShowCodeFile || _logCfg.ShowFunction)
{
if (_logCfg.ShowCodeLine)
{
msg += "(" + lineNo.ToString() + ")";
}
}
msg += ": " + logMsg;
return msg;
}
private static void LogOutput(NLogItem logItem)
{
var msg = LogFormat(logItem.LogLevel,
logItem.LogContent,
logItem.CodeFile,
logItem.CodeFunction,
logItem.CodeLine,
logItem.LogStamp);
if (_logCfg.ForceNewLine)
{
msg += Environment.NewLine;
}
lock (_logOutputLock)
{
if (_logCfg.EnConsole) Console.Write(msg);
if (_logCfg.EnDebug | _logCfg.EnTrace)
{
if (_logCfg.EnTrace)
Trace.Write(msg);
else
System.Diagnostics.Debug.WriteLine(msg);
}
if (_logCfg.EnFile)
{
_logSw?.Write(msg);
}
}
}
private static void LogOutput2(string logMsg)
{
lock (_logOutputLock)
{
if (_logCfg.EnConsole) Console.Write(logMsg);
if (_logCfg.EnDebug | _logCfg.EnTrace)
{
if (_logCfg.EnTrace)
Trace.Write(logMsg);
else
System.Diagnostics.Debug.WriteLine(logMsg);
}
if (_logCfg.EnFile)
{
_logSw?.Write(logMsg);
}
}
}
public static void LogOut([NotNull] string logMsg = "",
[CallerFilePath] string fileName = "",
[CallerMemberName] string funName = "",
[CallerLineNumber] int lineNo = 0)
{
if (NLogLevel.Debug >= _logCfg.LogLevel || !_logCfg.LogEnable) return;
if (_logCfg.AsyncMode)
{
if (_logItemCollection.Count >= _logCfg.MaxItemsCache)
{
if (_logCfg.CacheMode == CacheOptMode.Drop)
{
return;
}
else
{
NLogItem val;
_logItemCollection.TryDequeue(out val);
}
}
var logItem = new NLogItem(_logCfg.DefaultLevel, logMsg, fileName, funName, lineNo, DateTime.Now);
_logItemCollection.Enqueue(logItem);
}
else
{
var logItem = new NLogItem(_logCfg.DefaultLevel, logMsg, fileName, funName, lineNo, DateTime.Now);
LogOutput(logItem);
}
}
public static void LogOut(NLogLevel logLevel = NLogLevel.Info,
[NotNull] string logMsg = "",
[CallerFilePath] string fileName = "",
[CallerMemberName] string funName = "",
[CallerLineNumber] int lineNo = 0)
{
if (logLevel >= _logCfg.LogLevel || !_logCfg.LogEnable) return;
if (_logCfg.AsyncMode)
{
if (_logItemCollection.Count >= _logCfg.MaxItemsCache)
{
if (_logCfg.CacheMode == CacheOptMode.Drop)
{
return;
}
else
{
NLogItem val;
_logItemCollection.TryDequeue(out val);
}
}
var logItem = new NLogItem(NLogLevel.Debug, logMsg, fileName, funName, lineNo, DateTime.Now);
_logItemCollection.Enqueue(logItem);
}
else
{
var logItem = new NLogItem(NLogLevel.Debug, logMsg, fileName, funName, lineNo, DateTime.Now);
LogOutput(logItem);
}
}
#region LogOutputMethod
public static void Debug([NotNull] string logMsg = "",
[CallerFilePath] string fileName = "",
[CallerMemberName] string funName = "",
[CallerLineNumber] int lineNo = 0)
{
LogOut(NLogLevel.Debug, logMsg, fileName, funName, lineNo);
}
public static void Warring([NotNull] string logMsg = "",
[CallerFilePath] string fileName = "",
[CallerMemberName] string funName = "",
[CallerLineNumber] int lineNo = 0)
{
LogOut(NLogLevel.Warring, logMsg, fileName, funName, lineNo);
}
public static void Info([NotNull] string logMsg = "",
[CallerFilePath] string fileName = "",
[CallerMemberName] string funName = "",
[CallerLineNumber] int lineNo = 0)
{
LogOut(NLogLevel.Info, logMsg, fileName, funName, lineNo);
}
public static void Error([NotNull] string logMsg = "",
[CallerFilePath] string fileName = "",
[CallerMemberName] string funName = "",
[CallerLineNumber] int lineNo = 0)
{
LogOut(NLogLevel.Error, logMsg, fileName, funName, lineNo);
}
public static void Crash([NotNull] string logMsg = "",
[CallerFilePath] string fileName = "",
[CallerMemberName] string funName = "",
[CallerLineNumber] int lineNo = 0)
{
LogOut(NLogLevel.Crash, logMsg, fileName, funName, lineNo);
}
public static void Fatal([NotNull] string logMsg = "",
[CallerFilePath] string fileName = "",
[CallerMemberName] string funName = "",
[CallerLineNumber] int lineNo = 0)
{
LogOut(NLogLevel.Fatal, logMsg, fileName, funName, lineNo);
}
#endregion
}
}