You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
9.5 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using EntrustSettle.Common.Helper;
using Newtonsoft.Json;
using NLog;
using System;
using System.IO;
using System.Linq;
using System.Threading;
namespace EntrustSettle.Common.LogHelper
{
public class LogLock
{
static Logger logger = null;
static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
static int WritedCount = 0;
static int FailedCount = 0;
static string _contentRoot = string.Empty;
public LogLock(string contentPath)
{
_contentRoot = contentPath;
}
public static void OutLogAOP(string prefix, string traceId, string[] dataParas, bool IsHeader = true)
{
string AppSetingNodeName = "AppSettings";
string AppSetingName = "";
switch (prefix)
{
// 自定义的AOP中使用
case "ServiceAOPLog":
case "ServiceAOPLogEx":
AppSetingName = "ServiceAOPLog";
break;
// 中间件中使用
case "RecordAccessLogs":
AppSetingNodeName = "Middleware";
AppSetingName = "RecordAccessLogs";
break;
case "RequestResponseLog":
AppSetingNodeName = "Middleware";
AppSetingName = "RequestResponseLog";
break;
// SqlSugarAOP中使用
case "SqlAOPLog":
AppSetingName = "SqlAOPLog";
break;
default:
break;
}
if (AppSettings.app(new string[] { AppSetingNodeName, AppSetingName, "Enabled" }).ObjToBool())
{
if (AppSettings.app(new string[] { AppSetingNodeName, AppSetingName, "LogToFile", "Enabled" }).ObjToBool())
{
OutSql2LogToFile(prefix, traceId, dataParas, IsHeader);
}
if (AppSettings.app(new string[] { AppSetingNodeName, AppSetingName, "LogToDB", "Enabled" }).ObjToBool())
{
OutSql2LogToDB(prefix, traceId, dataParas, IsHeader);
}
}
}
public static void OutSql2LogToFile(string prefix, string traceId, string[] dataParas, bool IsHeader = true, bool isWrt = false)
{
try
{
//设置读写锁为写入模式独占资源,其他写入请求需要等待本次写入结束之后才能继续写入
//注意:长时间持有读线程锁或写线程锁会使其他线程发生饥饿 (starve)。 为了得到最好的性能,需要考虑重新构造应用程序以将写访问的持续时间减少到最小。
// 从性能方面考虑,请求进入写入模式应该紧跟文件操作之前,在此处进入写入模式仅是为了降低代码复杂度
// 因进入与退出写入模式应在同一个try finally语句块内所以在请求进入写入模式之前不能触发异常否则释放次数大于请求次数将会触发异常
LogWriteLock.EnterWriteLock();
var folderPath = Path.Combine(_contentRoot, "Logs", DateTime.Now.ToString("yyyy-MM-dd"));
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
//string logFilePath = Path.Combine(path, $@"{filename}.log");
var logFilePath = FileHelper.GetAvailableFileWithPrefixOrderSize(folderPath, prefix, 5);
switch (prefix)
{
case "ServiceAOPLog":
AOPLogInfo apiLogAopInfo = JsonConvert.DeserializeObject<AOPLogInfo>(dataParas[1]);
//记录被拦截方法信息的日志信息
var dataIntercept = "" +
$"【操作时间】:{apiLogAopInfo.RequestTime}\r\n" +
$"【当前操作用户】:{apiLogAopInfo.OpUserName} \r\n" +
$"【当前执行方法】:{apiLogAopInfo.RequestMethodName} \r\n" +
$"【携带的参数有】: {apiLogAopInfo.RequestParamsName} \r\n" +
$"【携带的参数JSON】 {apiLogAopInfo.RequestParamsData} \r\n" +
$"【响应时间】:{apiLogAopInfo.ResponseIntervalTime}\r\n" +
$"【执行完成时间】:{apiLogAopInfo.ResponseTime}\r\n" +
$"【执行完成结果】:{apiLogAopInfo.ResponseJsonData}\r\n";
dataParas = new string[] { dataIntercept };
break;
case "ServiceAOPLogEx":
AOPLogExInfo apiLogAopExInfo = JsonConvert.DeserializeObject<AOPLogExInfo>(dataParas[1]);
var dataInterceptEx = "" +
$"【操作时间】:{apiLogAopExInfo.ApiLogAopInfo.RequestTime}\r\n" +
$"【当前操作用户】:{apiLogAopExInfo.ApiLogAopInfo.OpUserName} \r\n" +
$"【当前执行方法】:{apiLogAopExInfo.ApiLogAopInfo.RequestMethodName} \r\n" +
$"【携带的参数有】: {apiLogAopExInfo.ApiLogAopInfo.RequestParamsName} \r\n" +
$"【携带的参数JSON】 {apiLogAopExInfo.ApiLogAopInfo.RequestParamsData} \r\n" +
$"【响应时间】:{apiLogAopExInfo.ApiLogAopInfo.ResponseIntervalTime}\r\n" +
$"【执行完成时间】:{apiLogAopExInfo.ApiLogAopInfo.ResponseTime}\r\n" +
$"【执行完成结果】:{apiLogAopExInfo.ApiLogAopInfo.ResponseJsonData}\r\n" +
$"【执行完成异常信息】:方法中出现异常:{apiLogAopExInfo.ExMessage}\r\n" +
$"【执行完成异常】:方法中出现异常:{apiLogAopExInfo.InnerException}\r\n";
dataParas = new string[] { dataInterceptEx };
break;
}
string logContent = null;
if (IsHeader)
{
logContent = (
$"--------------------------------\r\n{DateTime.Now:yyyy-MM-dd HH:mm:ss:fff} TraceId:{traceId}\r\n{String.Join("\r\n", dataParas)}\r\n"
);
}
else
{
logContent = (
dataParas[1] + ",\r\n"
);
}
//if (logContent.IsNotEmptyOrNull() && logContent.Length > 500)
//{
// logContent = logContent.Substring(0, 500) + "\r\n";
//}
if (isWrt)
{
File.WriteAllText(logFilePath, logContent);
}
else
{
File.AppendAllText(logFilePath, logContent);
}
WritedCount++;
}
catch (Exception e)
{
Console.Write(e.Message);
FailedCount++;
}
finally
{
//退出写入模式,释放资源占用
//注意:一次请求对应一次释放
// 若释放次数大于请求次数将会触发异常[写入锁定未经保持即被释放]
// 若请求处理完成后未释放将会触发异常[此模式不下允许以递归方式获取写入锁定]
LogWriteLock.ExitWriteLock();
}
}
public static void OutSql2LogToDB(string prefix, string traceId, string[] dataParas, bool IsHeader = true)
{
if (logger == null)
{
logger = LogManager.GetCurrentClassLogger();
}
dataParas = dataParas.Skip(1).ToArray();
string logContent = String.Join("", dataParas);
if (IsHeader)
{
logContent = (String.Join("", dataParas));
}
switch (prefix)
{
//DEBUG | INFO | WARN | ERROR | FATAL
case "ServiceAOPLog":
logger.Info(logContent);
break;
case "ServiceAOPLogEx":
logger.Error(logContent);
break;
case "RecordAccessLogs":
logger.Info(logContent);
break;
case "RequestResponseLog":
logger.Info(logContent);
break;
case "SqlAOPLog":
logger.Info(logContent);
break;
default:
break;
}
}
}
public enum ReadType
{
/// <summary>
/// 精确查找一个
/// </summary>
Accurate,
/// <summary>
/// 指定前缀,模糊查找全部
/// </summary>
Prefix,
/// <summary>
/// 指定前缀,最新一个文件
/// </summary>
PrefixLatest
}
}