using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CoreAgent.ProtocolClient.Context; using CoreAgent.ProtocolClient.Enums; using CoreAgent.ProtocolClient.Helpers; using CoreAgent.ProtocolClient.Models; using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace CoreAgent.ProtocolClient.ProtocolEngineCore { /// /// 日志数据转换器 /// 负责将BuildProtocolLog转换为TransferProtocolLog,并处理IMSI等关联数据的获取 /// public class LogDataConverter { private readonly ProtocolClientContext _context; private readonly ILogger _logger; private readonly ProtocolClientConfig _config; public LogDataConverter(ProtocolClientContext context, ProtocolClientConfig config,ILogger logger) { _context = context; _logger = logger; _config = config; } /// /// 将BuildProtocolLog列表转换为TransferProtocolLog列表 /// /// 协议日志列表 /// 协议日志详情列表 public List ConvertToProtocolLogDetails(IEnumerable protocolLogs) { var result = new List(); var tmsiMatches =new List(); var srTmsiMappings = new List(); if (_config.Model == "RAN") { tmsiMatches = _context.UeIdentifier.GenerateTmsiMatches(); srTmsiMappings = _context.UeIdentifier.GenerateSrTmsiMappings(tmsiMatches); } foreach (var log in protocolLogs) { try { var detail = ConvertSingleLog(log, tmsiMatches, srTmsiMappings); if (detail != null) { result.Add(detail); } } catch (Exception ex) { _logger.LogError(ex, $"转换日志详情失败,Layer: {log.Layer}, Message: {log.Message}"); } } // 更新 cellid 为 null 的记录 UpdateNullCellIds(result); // 统计IMSI和PLMN为null的数量 LogNullStatistics(result); return result; } /// /// 更新 cellid 为 null 的记录 /// 通过先根据 ueid 不为空分组,然后检查 cellid 为 null 的 ueid 与分组 ueid 匹配修改 /// /// 协议日志详情列表 private void UpdateNullCellIds(List details) { if (details == null || !details.Any()) { _logger.LogInformation("没有日志详情需要更新 cellid"); return; } try { // 1. 先根据 ueid 不为空分组,获取每个 UE ID 对应的有效 cellid var ueIdToCellIdMapping = details .Where(d => d.UEID.HasValue && d.CellID.HasValue) .GroupBy(d => d.UEID.Value) .ToDictionary( group => group.Key, group => group.Select(d => d.CellID.Value).Distinct().ToList() ); if (!ueIdToCellIdMapping.Any()) { _logger.LogInformation("没有找到有效的 UE ID 到 Cell ID 映射"); return; } // 2. 检查 cellid 为 null 的记录 var nullCellIdDetails = details.Where(d => d.UEID.HasValue && !d.CellID.HasValue).ToList(); if (!nullCellIdDetails.Any()) { _logger.LogInformation("没有找到 cellid 为 null 的记录"); return; } _logger.LogInformation($"找到 {nullCellIdDetails.Count} 条 cellid 为 null 的记录,开始更新..."); // 3. 通过 ueid 匹配来更新这些记录的 cellid int updatedCount = 0; foreach (var detail in nullCellIdDetails) { if (detail.UEID.HasValue && ueIdToCellIdMapping.TryGetValue(detail.UEID.Value, out var cellIds)) { // 如果该 UE ID 有多个 cellid,选择第一个(或者可以根据业务逻辑选择最合适的) if (cellIds.Any()) { detail.CellID = cellIds.First(); updatedCount++; _logger.LogDebug($"更新 UE ID {detail.UEID} 的 cellid 为 {detail.CellID}"); } } } _logger.LogInformation($"成功更新了 {updatedCount} 条记录的 cellid"); // 4. 统计更新结果 var remainingNullCellIds = details.Where(d => d.UEID.HasValue && !d.CellID.HasValue).Count(); if (remainingNullCellIds > 0) { _logger.LogWarning($"仍有 {remainingNullCellIds} 条记录的 cellid 为 null,这些 UE ID 可能没有对应的 cellid 信息"); } } catch (Exception ex) { _logger.LogError(ex, "更新 cellid 为 null 的记录时发生异常"); } } /// /// 转换单个BuildProtocolLog为TransferProtocolLog /// /// 协议日志 /// TMSI匹配结果列表 /// Service Request TMSI映射列表 /// 协议日志详情 private TransferProtocolLog? ConvertSingleLog(BuildProtocolLog log, List tmsiMatches, List srTmsiMappings) { if (log == null) return null; var detail = new TransferProtocolLog { Id=log.Id, LayerType = GetProtocolLayer(log.Layer), Direction = log.Direction, UEID = log.UeId, CellID = log.Cell, //Timestamp = log.Timestamp, TimeMs = log.Timestamp, Message = log.Message, Info = _context.UeIdentifier.IdToString(log.Info ?? -1), MessageDetailJson = JsonConvert.SerializeObject(log.Data) }; detail.Timestamp = TimeStampHelper.ConvertToFullTimestamp(log.Timestamp); if (_config.Model == "RAN") { // 获取IMSI信息 detail.IMSI = GetImsiFromUeList(log.UeId, tmsiMatches, srTmsiMappings); // 获取PLMN信息 detail.PLMN = GetPlmnFromPlmnToUeIdMapping(log.UeId, srTmsiMappings); } if (_config.Model == "IMS") { detail.IMSI = log.SIP.IMSI; detail.PLMN = log.SIP.Plmn; } return detail; } /// /// 根据UE ID获取IMSI信息 /// 使用TmsiMatchProcessor从UE链中获取IMSI,优先从根节点获取 /// /// UE ID /// TMSI匹配结果列表 /// Service Request TMSI映射列表 /// IMSI字符串,如果未找到则返回null private string? GetImsiFromUeList(int? ueId, List tmsiMatches, List srTmsiMappings) { if (!ueId.HasValue) return null; // 1. 优先从TMSI匹配结果中查找IMSI // 查找包含当前UE ID的匹配结果 var matchingResult = tmsiMatches.FirstOrDefault(match => match.RequestUeId == ueId.Value || match.ReceiveUeId == ueId.Value); if (matchingResult != null && !string.IsNullOrEmpty(matchingResult.Imsi)) { return matchingResult.Imsi; } // 2. 从Service Request TMSI映射中查找IMSI var srTmsiMatch = srTmsiMappings.FirstOrDefault(mapping => mapping.UeId == ueId.Value); if (srTmsiMatch != null && !string.IsNullOrEmpty(srTmsiMatch.Imsi)) { return srTmsiMatch.Imsi; } // 3. 如果TMSI匹配中没有找到,使用TmsiMatchProcessor从UE链中查找 var processor = new TmsiMatchProcessor( _context.UeIdentifier.TmsiToUeId, _context.UeIdentifier.RequestTmsiToUeId, _context.UeIdentifier.ImsiToUeId); // 获取UE链详细信息 var ueChains = processor.GetUeChainDetails(); // 查找包含当前UE ID的链 var containingChain = ueChains.FirstOrDefault(chain => chain.UeIds.Contains(ueId.Value)); if (containingChain != null && !string.IsNullOrEmpty(containingChain.Imsi)) { return containingChain.Imsi; } // 4. 如果UE链中也没有找到,回退到原有的查找逻辑 return GetImsiFromLegacySources(ueId.Value); } /// /// 从传统数据源获取IMSI(回退方法) /// 查找顺序:1.直接查找UeList 2.从Caps中查找 3.从ImsiToUeId映射表查找 /// /// UE ID /// IMSI字符串,如果未找到则返回null private string? GetImsiFromLegacySources(int ueId) { // 1. 直接从UeList中查找UE信息 if (_context.UeIdentifier.UeList?.TryGetValue(ueId, out var ueInfo) == true) { if (!string.IsNullOrEmpty(ueInfo?.Imsi)) { return ueInfo.Imsi; } } // 2. 从其他UE的Caps中查找UE ID if (_context.UeIdentifier.UeList != null) { var imsiFromCaps = _context.UeIdentifier.UeList.Values .Where(ueInfoItem => ueInfoItem?.Caps?.UeId == ueId) .Select(ueInfoItem => ueInfoItem.Imsi) .FirstOrDefault(imsi => !string.IsNullOrEmpty(imsi)); if (imsiFromCaps != null) { return imsiFromCaps; } } // 3. 从ImsiToUeId映射表中查找 if (_context.UeIdentifier.ImsiToUeId != null) { var imsiFromMapping = _context.UeIdentifier.ImsiToUeId .Where(mapping => mapping.Value?.Contains(ueId) == true) .Select(mapping => mapping.Key) .FirstOrDefault(imsi => !string.IsNullOrEmpty(imsi)); if (imsiFromMapping != null) { return imsiFromMapping; } } return null; } /// /// 根据协议层字符串获取ProtocolLayer枚举 /// /// 协议层字符串 /// ProtocolLayer枚举值 private ProtocolLayer GetProtocolLayer(string layer) { return layer?.ToUpperInvariant() switch { "RRC" => ProtocolLayer.RRC, "NAS" => ProtocolLayer.NAS, "PHY" => ProtocolLayer.PHY, "MAC" => ProtocolLayer.MAC, "RLC" => ProtocolLayer.RLC, "PDCP" => ProtocolLayer.PDCP, "SIP" => ProtocolLayer.SIP, "IMS" => ProtocolLayer.IMS, _ => ProtocolLayer.NONE }; } /// /// 根据UE ID从UeIdentifier.PlmnToUeId映射表中获取PLMN /// 优先使用srTmsiMappings中的RootUeId查找PLMN,提高匹配准确性 /// /// UE ID /// Service Request TMSI映射列表 /// PLMN字符串,如果未找到则返回null private string? GetPlmnFromPlmnToUeIdMapping(int? ueId, List srTmsiMappings) { if (!ueId.HasValue) return null; // 1. 优先从srTmsiMappings中查找对应的RootUeId,然后根据RootUeId查找PLMN var srTmsiMatch = srTmsiMappings.FirstOrDefault(mapping => mapping.UeId == ueId.Value); if (srTmsiMatch != null && srTmsiMatch.RootUeId > 0) { // 检查PlmnToUeId映射表是否存在 if (_context.UeIdentifier.PlmnToUeId != null) { // 直接使用RootUeId查找PLMN映射 var plmnMapping = _context.UeIdentifier.PlmnToUeId .FirstOrDefault(mapping => mapping.Value?.Contains(srTmsiMatch.RootUeId) == true); if (!string.IsNullOrEmpty(plmnMapping.Key)) { return plmnMapping.Key; } } } // 2. 如果srTmsiMappings中没有找到或RootUeId为空,回退到原有的查找逻辑 // 检查PlmnToUeId映射表是否存在 if (_context.UeIdentifier.PlmnToUeId == null) return null; // 直接查找包含指定UE ID的PLMN映射 var directPlmnMapping = _context.UeIdentifier.PlmnToUeId .FirstOrDefault(mapping => mapping.Value?.Contains(ueId.Value) == true); return directPlmnMapping.Key; } /// /// 统计并打印有问题的日志详情 /// /// 协议日志详情列表 private void LogNullStatistics(List details) { if (details == null || !details.Any()) { _logger.LogInformation("没有日志详情需要统计"); return; } // 1. UE ID为空的日志 var ueIdNullLogs = details.Where(d => d.UEID == null).ToList(); if (ueIdNullLogs.Any()) { _logger.LogWarning($"发现 {ueIdNullLogs.Count} 条UE ID为空的日志:"); foreach (var log in ueIdNullLogs) { _logger.LogWarning($" UE ID为空 - Layer: {log.LayerType}, Message: {log.Message}, IMSI: {log.IMSI}, PLMN: {log.PLMN}"); } } // 2. 只有IMSI但没有PLMN的日志 var onlyImsiLogs = details.Where(d => d.UEID.HasValue && !string.IsNullOrEmpty(d.IMSI) && string.IsNullOrEmpty(d.PLMN)).ToList(); if (onlyImsiLogs.Any()) { _logger.LogWarning($"发现 {onlyImsiLogs.Count} 条只有IMSI但没有PLMN的日志:"); foreach (var log in onlyImsiLogs) { _logger.LogWarning($" 只有IMSI - UE ID: {log.UEID}, Layer: {log.LayerType}, IMSI: {log.IMSI}, PLMN: {log.PLMN}"); } } // 3. 只有PLMN但没有IMSI的日志 var onlyPlmnLogs = details.Where(d => d.UEID.HasValue && string.IsNullOrEmpty(d.IMSI) && !string.IsNullOrEmpty(d.PLMN)).ToList(); if (onlyPlmnLogs.Any()) { _logger.LogWarning($"发现 {onlyPlmnLogs.Count} 条只有PLMN但没有IMSI的日志:"); foreach (var log in onlyPlmnLogs) { _logger.LogWarning($" 只有PLMN - UE ID: {log.UEID}, Layer: {log.LayerType}, IMSI: {log.IMSI}, PLMN: {log.PLMN}"); } } // 4. 同时有IMSI和PLMN的日志 var bothLogs = details.Where(d => d.UEID.HasValue && !string.IsNullOrEmpty(d.IMSI) && !string.IsNullOrEmpty(d.PLMN)).ToList(); if (bothLogs.Any()) { _logger.LogInformation($"发现 {bothLogs.Count} 条同时有IMSI和PLMN的日志:"); foreach (var log in bothLogs) { _logger.LogInformation($" 完整信息 - UE ID: {log.UEID}, Layer: {log.LayerType}, IMSI: {log.IMSI}, PLMN: {log.PLMN}"); } } // 5. 两者都为空的日志(UE ID不为空) var bothNullLogs = details.Where(d => d.UEID.HasValue && string.IsNullOrEmpty(d.IMSI) && string.IsNullOrEmpty(d.PLMN)).ToList(); if (bothNullLogs.Any()) { _logger.LogWarning($"发现 {bothNullLogs.Count} 条UE ID不为空但IMSI和PLMN都为空的日志:"); foreach (var log in bothNullLogs) { _logger.LogWarning($" 信息缺失 - UE ID: {log.UEID}, Layer: {log.LayerType}, IMSI: {log.IMSI}, PLMN: {log.PLMN}"); } } // 总结统计 var totalCount = details.Count; _logger.LogInformation($"日志详情总结 - 总数: {totalCount}, UE ID为空: {ueIdNullLogs.Count}, 只有IMSI: {onlyImsiLogs.Count}, 只有PLMN: {onlyPlmnLogs.Count}, 完整信息: {bothLogs.Count}, 信息缺失: {bothNullLogs.Count}"); } } }