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 _cacheLogs = new ConcurrentDictionary(); // 队列用于存储需要新增或更新的日志 public static ConcurrentQueue loggerQueueData = new ConcurrentQueue(); // 每天凌晨清空缓存 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 batchList = new List(); 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(); var toUpdate = new List(); foreach (var log in batchList) { // 如果已经有 Id 或者 IsExisting 标志,直接处理 if (log.Id > 0) { toUpdate.Add(log); continue; } // 根据哈希值查询是否已存在 var existing = sugarClient.Queryable() .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().BulkCopy(toInsert); // 获取新增日志的自增ID并更新缓存 foreach (var insertedLog in toInsert) { var savedLog = sugarClient.Queryable() .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() .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 batchList) { if (loggerQueueData.TryDequeue(out Dt_InterfaceLog log) && log != null) { batchList.Add(log); } } /// /// 计算字符串的SHA256哈希值 /// 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(); } } /// /// 生成缓存Key /// private static string GenerateCacheKey(string apiCode, string requestHash, string responseHash) { string today = DateTime.Now.ToString("yyyy-MM-dd"); return $"{today}_{apiCode}_{requestHash}_{responseHash}"; } /// /// 获取或创建日志(用于叠加推送次数) /// /// 编号 /// 名称 /// 地址 /// 请求内容 /// 响应内容 /// 状态 /// 请求用户IP /// 请求方 /// 接收方 /// 备注 /// 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; } } /// /// 添加接口日志(带URL、请求参数、响应参数、开始时间) /// 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); } /// /// 添加接口日志(从HttpContext自动获取信息) /// /// 请求内容 /// 响应内容 /// 接口编号 /// 接口名称 /// 推送状态 /// 接收方 /// 备注 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(); pushState = wMSReturn.code == 0 ? 1 : 2; } else if (apiAddress.Contains("/api/KHAGV")) { requestor = "海康AGV"; var hIKROBOTReturn = responseParameters.DeserializeObject(); pushState = hIKROBOTReturn.code == "SUCCESS" ? 1 : 2; } else if (apiAddress.Contains("/api/KLS")) { requestor = "凯乐士AGV"; ReturnGALAXIS returnGALAXIS = responseParameters.DeserializeObject(); pushState = returnGALAXIS.returnStatus == 0 ? 1 : 2; } else if (apiAddress.Contains("/api/RGV")) { requestor = "四向穿梭车";//旷视河图 FOURBOTReturn fOURBOTReturn = responseParameters.DeserializeObject(); 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); } /// /// 手动增加推送次数(用于重试场景) /// 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; } } }