using SqlSugar;
|
using System.Collections.Concurrent;
|
using System.Text;
|
using WIDESEAWCS_Core.HttpContextUser;
|
using WIDESEAWCS_Core.Seed;
|
using WIDESEAWCS_Model.Models;
|
using System.Security.Cryptography;
|
using WIDESEAWCS_Core.Helper;
|
using Newtonsoft.Json.Linq;
|
using WIDESEAWCS_DTO.RGV.FOURBOT;
|
using WIDESEAWCS_DTO.WMS;
|
using WIDESEAWCS_DTO;
|
|
namespace WIDESEAWCS_Core.LogHelper
|
{
|
public static class LoggerNew
|
{
|
// 用于缓存当天已存在的日志(key: 日期+ApiCode+请求哈希+响应哈希)
|
private static ConcurrentDictionary<string, Dt_InterfaceLog> _cacheLogs = new ConcurrentDictionary<string, Dt_InterfaceLog>();
|
// 队列用于存储需要新增或更新的日志
|
public static ConcurrentQueue<Dt_InterfaceLog> loggerQueueData = new ConcurrentQueue<Dt_InterfaceLog>();
|
|
// 每天凌晨清空缓存
|
private static DateTime _lastClearDate = DateTime.Now.Date;
|
|
static LoggerNew()
|
{
|
Task.Run(() =>
|
{
|
StartWriteLog();
|
});
|
|
// 启动一个后台任务,每天凌晨清空缓存
|
Task.Run(() =>
|
{
|
while (true)
|
{
|
Thread.Sleep(60000); // 每分钟检查一次
|
DateTime today = DateTime.Now.Date;
|
if (_lastClearDate < today)
|
{
|
_cacheLogs.Clear();
|
_lastClearDate = today;
|
Console.WriteLine($"Logger缓存已清空,日期:{today:yyyy-MM-dd}");
|
}
|
}
|
});
|
}
|
|
static void StartWriteLog()
|
{
|
List<Dt_InterfaceLog> batchList = new List<Dt_InterfaceLog>();
|
|
while (true)
|
{
|
try
|
{
|
if (loggerQueueData.Count() > 0 && batchList.Count < 500)
|
{
|
DequeueToBatchList(batchList);
|
continue;
|
}
|
|
Thread.Sleep(5000);
|
|
if (batchList.Count == 0) { continue; }
|
|
SqlSugarClient sugarClient = new SqlSugarClient(new ConnectionConfig()
|
{
|
ConnectionString = DBContext.GetMainConnectionDb().Connection,
|
IsAutoCloseConnection = true,
|
DbType = DBContext.DbType,
|
});
|
|
try
|
{
|
sugarClient.BeginTran(); // 开启事务
|
|
var toInsert = new List<Dt_InterfaceLog>();
|
var toUpdate = new List<Dt_InterfaceLog>();
|
|
foreach (var log in batchList)
|
{
|
// 如果已经有 Id 或者 IsExisting 标志,直接处理
|
if (log.Id > 0)
|
{
|
toUpdate.Add(log);
|
continue;
|
}
|
|
// 根据哈希值查询是否已存在
|
var existing = sugarClient.Queryable<Dt_InterfaceLog>()
|
.First(x => x.RequestParametersHash == log.RequestParametersHash
|
&& x.ResponseParametersHash == log.ResponseParametersHash
|
&& x.ApiCode == log.ApiCode
|
&& SqlFunc.DateIsSame(x.CreateDate, DateTime.Now)); // 同一天
|
|
if (existing != null)
|
{
|
// 已存在,更新
|
log.Id = existing.Id;
|
log.PushFrequency = existing.PushFrequency + 1; // 叠加次数
|
log.ModifyDate = DateTime.Now;
|
toUpdate.Add(log);
|
|
// 更新缓存中的 Id
|
string cacheKey = GenerateCacheKey(log.ApiCode, log.RequestParametersHash, log.ResponseParametersHash);
|
if (_cacheLogs.TryGetValue(cacheKey, out var cachedLog))
|
{
|
cachedLog.Id = existing.Id;
|
}
|
}
|
else
|
{
|
// 不存在,新增
|
toInsert.Add(log);
|
}
|
}
|
|
// 批量新增
|
if (toInsert.Any())
|
{
|
int rows = sugarClient.Fastest<Dt_InterfaceLog>().BulkCopy(toInsert);
|
|
// 获取新增日志的自增ID并更新缓存
|
foreach (var insertedLog in toInsert)
|
{
|
var savedLog = sugarClient.Queryable<Dt_InterfaceLog>()
|
.First(x => x.RequestParametersHash == insertedLog.RequestParametersHash
|
&& x.ResponseParametersHash == insertedLog.ResponseParametersHash);
|
if (savedLog != null)
|
{
|
string cacheKey = GenerateCacheKey(insertedLog.ApiCode,
|
insertedLog.RequestParametersHash, insertedLog.ResponseParametersHash);
|
if (_cacheLogs.TryGetValue(cacheKey, out var cachedLog))
|
{
|
cachedLog.Id = savedLog.Id;
|
}
|
}
|
}
|
}
|
|
// 批量更新推送次数
|
if (toUpdate.Any())
|
{
|
foreach (var log in toUpdate)
|
{
|
sugarClient.Updateable<Dt_InterfaceLog>()
|
.SetColumns(it => new Dt_InterfaceLog
|
{
|
PushFrequency = log.PushFrequency,
|
PushState = log.PushState,
|
Remark = log.Remark,
|
//CreateDate = log.CreateDate
|
ModifyDate = log.ModifyDate
|
})
|
.Where(it => it.Id == log.Id)
|
.ExecuteCommand();
|
}
|
}
|
|
sugarClient.CommitTran(); // 提交事务
|
}
|
catch (Exception ex)
|
{
|
sugarClient.RollbackTran(); // 回滚事务
|
Console.WriteLine($"处理日志批次失败: {ex.Message}");
|
}
|
finally
|
{
|
batchList.Clear();
|
}
|
}
|
catch (Exception ex)
|
{
|
Console.WriteLine(ex.ToString());
|
}
|
}
|
}
|
|
private static void DequeueToBatchList(List<Dt_InterfaceLog> batchList)
|
{
|
if (loggerQueueData.TryDequeue(out Dt_InterfaceLog log) && log != null)
|
{
|
batchList.Add(log);
|
}
|
}
|
|
/// <summary>
|
/// 计算字符串的SHA256哈希值
|
/// </summary>
|
private static string ComputeHash(string input)
|
{
|
if (string.IsNullOrEmpty(input))
|
return string.Empty;
|
|
using (SHA256 sha256 = SHA256.Create())
|
{
|
byte[] bytes = Encoding.UTF8.GetBytes(input);
|
byte[] hashBytes = sha256.ComputeHash(bytes);
|
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
|
}
|
}
|
|
/// <summary>
|
/// 生成缓存Key
|
/// </summary>
|
private static string GenerateCacheKey(string apiCode, string requestHash, string responseHash)
|
{
|
string today = DateTime.Now.ToString("yyyy-MM-dd");
|
return $"{today}_{apiCode}_{requestHash}_{responseHash}";
|
}
|
|
/// <summary>
|
/// 获取或创建日志(用于叠加推送次数)
|
/// </summary>
|
/// <param name="apiCode">编号</param>
|
/// <param name="apiName">名称</param>
|
/// <param name="apiAddress">地址</param>
|
/// <param name="requestParameters">请求内容</param>
|
/// <param name="responseParameters">响应内容</param>
|
/// <param name="pushState">状态</param>
|
/// <param name="requestorUserIP">请求用户IP</param>
|
/// <param name="requestor">请求方</param>
|
/// <param name="recipient">接收方</param>
|
/// <param name="remark">备注</param>
|
/// <returns></returns>
|
private static Dt_InterfaceLog GetOrCreateLog(string apiCode, string apiName, string apiAddress,
|
string requestParameters, string responseParameters, int pushState,
|
string requestorUserIP, string requestor, string recipient, string remark)
|
{
|
string requestHash = ComputeHash(requestParameters);
|
string responseHash = ComputeHash(responseParameters);
|
string cacheKey = GenerateCacheKey(apiCode, requestHash, responseHash);
|
|
// 尝试从缓存中获取
|
if (_cacheLogs.TryGetValue(cacheKey, out Dt_InterfaceLog existingLog))
|
{
|
// 存在相同参数的日志,增加推送次数
|
existingLog.PushFrequency++;
|
existingLog.PushState = pushState; // 更新推送状态
|
existingLog.Remark = remark; // 更新备注
|
//existingLog.CreateDate = DateTime.Now; // 更新时间
|
existingLog.ModifyDate = DateTime.Now; // 更新时间
|
|
// 返回现有日志(需要更新数据库)
|
return existingLog;
|
}
|
else
|
{
|
// 不存在,创建新日志
|
var newLog = new Dt_InterfaceLog
|
{
|
ApiCode = apiCode,
|
ApiName = apiName,
|
ApiAddress = apiAddress,
|
PushFrequency = 1,
|
PushState = pushState,
|
RequestorUserIP = requestorUserIP,
|
Requestor = requestor,
|
RequestParameters = requestParameters,
|
RequestParametersHash = requestHash,
|
Recipient = recipient,
|
ResponseParameters = responseParameters,
|
ResponseParametersHash = responseHash,
|
Remark = remark,
|
Creater = "System",
|
CreateDate = DateTime.Now
|
};
|
|
// 加入缓存
|
_cacheLogs.TryAdd(cacheKey, newLog);
|
|
return newLog;
|
}
|
}
|
|
/// <summary>
|
/// 添加接口日志(带URL、请求参数、响应参数、开始时间)
|
/// </summary>
|
public static void Add(string apiCode, string apiName, string apiAddress,
|
string requestParameters, string responseParameters,
|
int pushState = 0, string recipient = "", string remark = "")
|
{
|
Dt_InterfaceLog log = null;
|
try
|
{
|
// 获取当前用户
|
IUser? user = App.User;
|
|
// 获取或创建日志(自动处理叠加)
|
log = GetOrCreateLog(apiCode, apiName, apiAddress,
|
requestParameters, responseParameters, pushState,
|
"", user?.UserName ?? "", recipient, remark);
|
}
|
catch (Exception exception)
|
{
|
// 如果发生异常,创建基础日志对象
|
log = log ?? new Dt_InterfaceLog
|
{
|
ApiCode = apiCode,
|
ApiName = apiName,
|
ApiAddress = apiAddress,
|
PushFrequency = 1,
|
PushState = pushState,
|
RequestParameters = requestParameters,
|
ResponseParameters = responseParameters,
|
Creater = "System",
|
Remark = $"记录日志时发生异常:{exception.Message}"
|
};
|
}
|
|
// 添加系统日志
|
loggerQueueData.Enqueue(log);
|
}
|
|
/// <summary>
|
/// 添加接口日志(从HttpContext自动获取信息)
|
/// </summary>
|
/// <param name="requestParameters">请求内容</param>
|
/// <param name="responseParameters">响应内容</param>
|
/// <param name="apiCode">接口编号</param>
|
/// <param name="apiName">接口名称</param>
|
/// <param name="pushState">推送状态</param>
|
/// <param name="recipient">接收方</param>
|
/// <param name="remark">备注</param>
|
public static void Add(string requestParameters, string responseParameters, HttpContext context, string apiCode = "", string apiName = "", int pushState = 0, string recipient = "WCS", string remark = "")
|
{
|
Dt_InterfaceLog log = null;
|
try
|
{
|
// 如果请求方法为OPTIONS,则返回
|
if (context.Request.Method == "OPTIONS") return;
|
|
#region 数据转换
|
|
// 解析外层 JSON
|
JObject outerObj = JObject.Parse(requestParameters);
|
|
// 获取 BodyData 的值(它是一个字符串)
|
requestParameters = outerObj["BodyData"]?.ToString() ?? requestParameters;
|
|
// 构建完整的接口地址
|
string apiAddress = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase + context.Request.Path;
|
// 获取客户端IP
|
string clientIP = GetClientIP(context)?.Replace("::ffff:", "") ?? "";
|
string requestor = "";//请求方
|
if (apiAddress.Contains("/api/WMS"))
|
{
|
requestor = "WMS";//秒优
|
var wMSReturn = responseParameters.DeserializeObject<WMSReturn>();
|
pushState = wMSReturn.code == 0 ? 1 : 2;
|
}
|
else if (apiAddress.Contains("/api/KHAGV"))
|
{
|
requestor = "海康AGV";
|
var hIKROBOTReturn = responseParameters.DeserializeObject<HIKROBOTReturn>();
|
pushState = hIKROBOTReturn.code == "SUCCESS" ? 1 : 2;
|
}
|
else if (apiAddress.Contains("/api/KLS"))
|
{
|
requestor = "凯乐士AGV";
|
ReturnGALAXIS returnGALAXIS = responseParameters.DeserializeObject<ReturnGALAXIS>();
|
pushState = returnGALAXIS.returnStatus == 0 ? 1 : 2;
|
}
|
else if (apiAddress.Contains("/api/RGV"))
|
{
|
requestor = "四向穿梭车";//旷视河图
|
FOURBOTReturn fOURBOTReturn = responseParameters.DeserializeObject<FOURBOTReturn>();
|
pushState = fOURBOTReturn.returnCode == 0 ? 1 : 2;
|
}
|
apiCode = apiAddress.Split("/").Last();
|
apiName = AppSettings.Configuration.GetValue($"{requestor}:{apiCode}", apiCode);
|
#endregion
|
|
// 获取或创建日志(自动处理叠加)
|
log = GetOrCreateLog(apiCode, apiName, apiAddress,
|
requestParameters, responseParameters, pushState,
|
clientIP, requestor, recipient, remark);
|
}
|
catch (Exception exception)
|
{
|
// 如果发生异常,创建基础日志对象
|
log = log ?? new Dt_InterfaceLog
|
{
|
ApiCode = apiCode,
|
ApiName = apiName,
|
PushFrequency = 1,
|
PushState = pushState,
|
RequestParameters = requestParameters,
|
ResponseParameters = responseParameters,
|
Creater = "System",
|
Remark = $"记录日志时发生异常:{exception.Message}"
|
};
|
}
|
|
// 添加系统日志
|
loggerQueueData.Enqueue(log);
|
}
|
|
/// <summary>
|
/// 手动增加推送次数(用于重试场景)
|
/// </summary>
|
public static void IncrementPushCount(string apiCode, string requestParameters, string responseParameters)
|
{
|
string requestHash = ComputeHash(requestParameters);
|
string responseHash = ComputeHash(responseParameters);
|
string cacheKey = GenerateCacheKey(apiCode, requestHash, responseHash);
|
|
if (_cacheLogs.TryGetValue(cacheKey, out Dt_InterfaceLog existingLog))
|
{
|
existingLog.PushFrequency++;
|
loggerQueueData.Enqueue(existingLog);
|
}
|
}
|
|
public static string GetClientIP(HttpContext context)
|
{
|
// 获取请求头中的X-Forwarded-For字段,并将其转换为字符串
|
var ip = context.Request.Headers["X-Forwarded-For"].ObjToString();
|
// 如果X-Forwarded-For字段为空,则获取远程IP地址
|
if (string.IsNullOrEmpty(ip))
|
{
|
ip = context.Connection.RemoteIpAddress.ObjToString();
|
}
|
|
// 返回IP地址
|
return ip;
|
}
|
}
|
}
|