Browse Source

dsda1

feature/log-detailed-types
root 1 month ago
parent
commit
539440ed42
  1. 483
      LTEMvcApp/Models/LTEClient.cs
  2. 52
      LTEMvcApp/Models/LTELog.cs

483
LTEMvcApp/Models/LTEClient.cs

@ -1,5 +1,6 @@
using System.Collections.Immutable;
using System.Text.RegularExpressions;
using System.Threading;
using Newtonsoft.Json;
namespace LTEMvcApp.Models;
@ -21,6 +22,13 @@ public class LTEClient
/// </summary>
private const int LOGS_MAX = 2000000;
/// <summary>
/// BSR表 - 对应JavaScript中的_bsr_table
/// </summary>
private static readonly int[] BsrTable = {
0, 10, 12, 14, 17, 19, 22, 26, 31, 36, 42, 49, 57, 67, 78, 91, 107, 125, 146, 171, 200, 234, 274, 321, 376, 440, 515, 603, 706, 826, 967, 1132, 1326, 1552, 1817, 2127, 2490, 2915, 3413, 3995, 4677, 5476, 6411, 7505, 8787, 10287, 12043, 14099, 16507, 19325, 22624, 26487, 31009, 36304, 42502, 49759, 58255, 68201, 79846, 93479, 109439, 128125, 150000, 500000
};
#endregion
#region 正则表达式
@ -768,47 +776,34 @@ public class LTEClient
continue;
}
var infoMatch = RegExpInfo1.Match(log.Message);
if (infoMatch.Success)
var rrcInfoMatch = RegExpInfo1.Match(log.Message);
if (rrcInfoMatch.Success)
{
if (!SetLogInfo(log, infoMatch.Groups[1].Value)) continue;
log.Message = infoMatch.Groups[2].Value;
if (!SetLogInfo(log, rrcInfoMatch.Groups[1].Value)) continue;
log.Message = rrcInfoMatch.Groups[2].Value;
ProcessRrcLog(log);
}
var bcMatch = RegExpRRC_BC.Match(log.Message);
if (bcMatch.Success)
var rrcBcMatch = RegExpRRC_BC.Match(log.Message);
if (rrcBcMatch.Success)
{
try
{
var data = log.GetDataString();
var jsonData = JsonConvert.DeserializeObject<object>(data);
// 处理频段组合信息
// 这里需要调用getUECaps(log.ue_id).setBandComb(data, info[1].toLowerCase());
// 暂时注释掉,因为还没有实现getUECaps方法
// GetUECaps(log.UeId ?? 0).SetBandComb(jsonData, rrcBcMatch.Groups[1].Value.ToLower());
}
catch
catch (Exception e)
{
// 忽略JSON解析错误
Console.WriteLine($"Band combination parsing error: {e.Message}");
}
}
break;
case "NAS":
ParseCellId(log, isWebSocket);
var nasTmsiMatch = RegExpNAS_TMSI.Match(log.Message);
if (nasTmsiMatch.Success)
{
SetTmsi(log, nasTmsiMatch.Groups[1].Value);
continue;
}
var nas5gTmsiMatch = RegExpNAS_5GTMSI.Match(log.Message);
if (nas5gTmsiMatch.Success)
{
SetTmsi(log, nas5gTmsiMatch.Groups[1].Value);
continue;
}
var nasInfoMatch = RegExpInfo2.Match(log.Message);
var nasInfoMatch = RegExpInfo1.Match(log.Message);
if (nasInfoMatch.Success)
{
if (!SetLogInfo(log, nasInfoMatch.Groups[1].Value)) continue;
@ -817,11 +812,31 @@ public class LTEClient
}
break;
case "MON":
case "OTS":
var monOtsInfoMatch = RegExpInfo1.Match(log.Message);
if (monOtsInfoMatch.Success)
{
if (!SetLogInfo(log, monOtsInfoMatch.Groups[1].Value)) continue;
log.Message = monOtsInfoMatch.Groups[2].Value;
}
break;
case "MAC":
ParseCellId(log, isWebSocket);
ParseMacLog(log);
break;
case "RLC":
case "PDCP":
var rlcPdcpInfoMatch = RegExpInfo2.Match(log.Message);
if (rlcPdcpInfoMatch.Success)
{
if (!SetLogInfo(log, rlcPdcpInfoMatch.Groups[1].Value)) continue;
log.Message = rlcPdcpInfoMatch.Groups[2].Value;
}
break;
case "IP":
var ipMatch = RegExpIP.Match(log.Message);
if (ipMatch.Success)
@ -853,6 +868,15 @@ public class LTEClient
var ranId = int.TryParse(s1ngMatch.Groups[2].Value, System.Globalization.NumberStyles.HexNumber, null, out var ran) ? ran : (int?)null;
log.LinkIds = new LinkIds { Core = coreId, Ran = ranId };
// 根据模型类型决定 UeId 赋值
if ((Config.Model?.ToUpper() ?? "") == "MME")
{
if (coreId.HasValue) log.UeId = coreId.Value;
}
else
{
if (ranId.HasValue) log.UeId = ranId.Value;
}
}
break;
@ -861,11 +885,26 @@ public class LTEClient
if (sipMatch.Success)
{
if (!SetLogInfo(log, sipMatch.Groups[2].Value)) continue;
log.Message = sipMatch.Groups[3].Value;
log.Msg0 = log.Message;
// 替换 ue_id 并调用 SetSameUe
var msg = sipMatch.Groups[3].Value;
var ueIdMatch = System.Text.RegularExpressions.Regex.Match(msg, @" ue_id=(\d+)");
if (ueIdMatch.Success)
{
if (int.TryParse(ueIdMatch.Groups[1].Value, out var ueId))
{
SetSameUe(log, ueId);
}
msg = System.Text.RegularExpressions.Regex.Replace(msg, @" ue_id=\d+", "");
}
// 拼接 from/to 和 info[1]
var dirStr = log.Direction == 1 ? " from " : " to "; // 1=UL, 2=DL
log.Message = msg + dirStr + sipMatch.Groups[1].Value;
}
break;
case "MEDIA":
case "RTP":
var mediaMatch = RegExpMediaReq.Match(log.Message);
if (mediaMatch.Success)
{
@ -875,11 +914,60 @@ public class LTEClient
break;
case "IPsec":
var ipsecMatch = RegExpIPsec.Match(log.Message);
if (ipsecMatch.Success)
var ipsecInfoMatch = RegExpInfo1.Match(log.Message);
if (ipsecInfoMatch.Success)
{
if (!SetLogInfo(log, ipsecInfoMatch.Groups[1].Value)) continue;
log.Message = ipsecInfoMatch.Groups[2].Value;
}
var ipsecPacketMatch = RegExpIPsec.Match(log.Message);
if (ipsecPacketMatch.Success)
{
log.IpLen = int.Parse(ipsecPacketMatch.Groups[1].Value);
HasData = true;
}
break;
case "SWU":
case "NWU":
var swuNwuInfoMatch = RegExpInfo1.Match(log.Message);
if (swuNwuInfoMatch.Success)
{
if (!SetLogInfo(log, swuNwuInfoMatch.Groups[1].Value)) continue;
log.Message = swuNwuInfoMatch.Groups[2].Value;
}
break;
case "IMS":
var imsInfoMatch = RegExpInfo1.Match(log.Message);
if (imsInfoMatch.Success)
{
if (!SetLogInfo(log, imsInfoMatch.Groups[1].Value)) continue;
log.Message = imsInfoMatch.Groups[2].Value;
var hints = ParseHints(log, new Dictionary<string, object> { { "rid", 0 }, { "aid", 0 } });
if (hints != null)
{
if (hints.ContainsKey("rid") && hints["rid"] != null)
{
SetSameUeId(log.UeId ?? 0, Convert.ToInt32(hints["rid"]));
}
if (hints.ContainsKey("aid") && hints["aid"] != null)
{
SetSameUeId(log.UeId ?? 0, Convert.ToInt32(hints["aid"]));
}
}
}
break;
case "EPDG":
case "PROD":
case "COM":
var comInfoMatch = RegExpInfo1.Match(log.Message);
if (comInfoMatch.Success)
{
log.IpLen = int.Parse(ipsecMatch.Groups[1].Value);
log.Message = ipsecMatch.Groups[2].Value;
if (!SetLogInfo(log, comInfoMatch.Groups[1].Value)) continue;
log.Message = comInfoMatch.Groups[2].Value;
var hints = ParseHints(log);
}
break;
@ -1158,15 +1246,163 @@ public class LTEClient
/// </summary>
private void ProcessNasLog(LTELog log)
{
// NAS日志处理逻辑
// 根据消息类型处理不同的NAS消息
switch (log.Message.ToLower())
{
case "attach accept":
var tmsiMatch = log.FindData(RegExpNAS_TMSI);
if (tmsiMatch != null)
{
SetTmsi(log, tmsiMatch.Groups[1].Value);
}
break;
case "registration accept":
var tmsi5gMatch = log.FindData(RegExpNAS_5GTMSI);
if (tmsi5gMatch != null)
{
SetTmsi(log, tmsi5gMatch.Groups[1].Value);
}
break;
}
// 解析提示信息
var hints = ParseHints(log, new Dictionary<string, object>
{
{ "ran_ue_id", 0 },
{ "ran_address", "" }
});
// 处理RAN ID
if (hints != null && hints.TryGetValue("ran_ue_id", out var ranUeIdObj))
{
var ranUeId = Convert.ToInt32(ranUeIdObj);
if (ranUeId > 0)
{
// 获取RAN ID
string? ranId = null;
if (hints.TryGetValue("global_ran_node_id", out var globalRanNodeId))
{
ranId = globalRanNodeId.ToString();
}
else if (hints.TryGetValue("global_enb_id", out var globalEnbId))
{
ranId = globalEnbId.ToString();
}
if (!string.IsNullOrEmpty(ranId))
{
AddUERanID(log, ranUeId, ranId);
}
}
}
}
/// <summary>
/// 解析MAC日志
/// 解析MAC日志 - 对应JavaScript中的_logParseMac方法
/// </summary>
private void ParseMacLog(LTELog log)
{
// MAC日志解析逻辑
var type = "";
var args = log.Message.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int m = 0; m < args.Length; m++)
{
var param = args[m];
string? value = null;
// 检查是否有等号分隔符
var equalIndex = param.IndexOf('=');
if (equalIndex >= 0)
{
value = param.Substring(equalIndex + 1);
param = param.Substring(0, equalIndex);
}
else
{
// 检查是否有冒号分隔符
var colonIndex = param.IndexOf(':');
if (colonIndex >= 0)
{
value = param.Substring(colonIndex + 1);
param = param.Substring(0, colonIndex);
}
}
switch (param.ToLower())
{
case "ph":
if (value != null && int.TryParse(value, out var phr))
{
log.Phr = phr - 23;
}
break;
case "b":
if (value != null && int.TryParse(value, out var bValue))
{
switch (type)
{
case "SBSR":
if (bValue >= 0 && bValue < BsrTable.Length)
{
log.UlBufferSize = BsrTable[bValue];
}
break;
case "LBSR":
if (bValue >= 0 && bValue < BsrTable.Length &&
m + 3 < args.Length)
{
var b1 = int.TryParse(args[++m], out var b1Val) ? b1Val : 0;
var b2 = int.TryParse(args[++m], out var b2Val) ? b2Val : 0;
var b3 = int.TryParse(args[++m], out var b3Val) ? b3Val : 0;
var total = 0;
if (bValue < BsrTable.Length) total += BsrTable[bValue];
if (b1 < BsrTable.Length) total += BsrTable[b1];
if (b2 < BsrTable.Length) total += BsrTable[b2];
if (b3 < BsrTable.Length) total += BsrTable[b3];
log.UlBufferSize = total;
}
break;
}
}
break;
case "len":
if (value != null && int.TryParse(value, out var len))
{
switch (type)
{
case "PAD":
log.MacPad = (log.MacPad ?? 0) + len;
break;
case "LCID":
log.MacLen = (log.MacLen ?? 0) + len;
break;
}
}
break;
case "lcid":
type = param;
break;
case "ta":
if (value != null && int.TryParse(value, out var ta))
{
log.Ta = ta - 31;
}
break;
default:
if (value == "")
{
type = param;
}
break;
}
}
}
/// <summary>
@ -1201,6 +1437,147 @@ public class LTEClient
}
}
/// <summary>
/// 获取UE信息
/// </summary>
/// <param name="ueId">UE ID</param>
/// <returns>UE信息</returns>
public UEInfo? GetUE(int ueId)
{
return UeList.TryGetValue(ueId, out var ue) ? ue : null;
}
/// <summary>
/// 创建UE信息
/// </summary>
/// <param name="ueId">UE ID</param>
/// <returns>UE信息</returns>
public UEInfo CreateUE(int ueId)
{
if (!UeList.TryGetValue(ueId, out var ue))
{
ue = new UEInfo { UeId = ueId };
UeList[ueId] = ue;
}
return ue;
}
/// <summary>
/// 根据参数获取UE
/// </summary>
/// <param name="name">参数名</param>
/// <param name="value">参数值</param>
/// <returns>UE信息</returns>
public UEInfo? GetUEByParam(string name, object value)
{
foreach (var ue in UeList.Values)
{
var property = typeof(UEInfo).GetProperty(name);
if (property?.GetValue(ue)?.Equals(value) == true)
return ue;
}
return null;
}
/// <summary>
/// 获取UE能力信息
/// </summary>
/// <param name="ueId">UE ID</param>
/// <returns>UE能力信息</returns>
public object GetUECaps(int ueId)
{
var ue = CreateUE(ueId);
if (ue.Caps == null)
{
// 这里可以创建一个LTECaps对象
// ue.Caps = new LTECaps(ueId);
ue.Caps = new object(); // 临时实现
}
return ue.Caps;
}
/// <summary>
/// 添加UE RAN ID
/// </summary>
/// <param name="log">日志</param>
/// <param name="ranUeId">RAN UE ID</param>
/// <param name="ranId">RAN ID</param>
private void AddUERanID(LTELog log, int ranUeId, string ranId)
{
// 简化实现,实际可能需要更复杂的逻辑
var ue = CreateUE(log.UeId ?? 0);
// 这里可以添加RAN ID相关的处理逻辑
}
/// <summary>
/// 解析提示信息
/// </summary>
/// <param name="log">日志</param>
/// <param name="config">配置</param>
/// <returns>提示信息字典</returns>
private Dictionary<string, object>? ParseHints(LTELog log, Dictionary<string, object>? config = null)
{
if (log.Info != ID_HINTS) return null;
var hints = new Dictionary<string, object>(config ?? new Dictionary<string, object>());
// 解析消息中的参数
var args = log.Message.Split(' ', StringSplitOptions.RemoveEmptyEntries);
foreach (var arg in args)
{
var parts = arg.Split('=');
if (parts.Length == 2)
{
hints[parts[0]] = parts[1];
}
}
// 处理IMEI/IMEISV
if (hints.TryGetValue("imei", out var imeiObj))
{
var imei = imeiObj.ToString();
var ue = GetUEByParam("Imei", imei);
if (ue != null)
{
SetSameUe(log, ue.UeId);
}
else
{
ue = CreateUE(log.UeId ?? 0);
ue.Imei = imei;
}
}
else if (hints.TryGetValue("imeisv", out var imeisvObj))
{
var imeisv = imeisvObj.ToString();
var imei = imeisv.Length > 2 ? imeisv[..^2] : imeisv; // 移除最后两个字符
var ue = GetUEByParam("Imei", imei);
if (ue != null)
{
SetSameUe(log, ue.UeId);
}
else
{
ue = CreateUE(log.UeId ?? 0);
ue.Imei = imei;
}
}
// 处理IMSI
if (hints.TryGetValue("imsi", out var imsiObj))
{
var imsi = imsiObj.ToString();
var ue = GetUEByParam("Imsi", imsi);
if (ue == null)
{
ue = CreateUE(log.UeId ?? 0);
ue.Imsi = imsi;
}
}
return hints;
}
#endregion
#region 私有辅助方法
@ -1527,6 +1904,46 @@ public class LTEClient
};
#endregion
/// <summary>
/// 设置两个UE ID为同一UE(合并UE信息)
/// </summary>
private void SetSameUeId(int id0, int id1)
{
if (id0 == id1) return;
var ue0 = UeList.ContainsKey(id0) ? UeList[id0] : null;
var ue1 = UeList.ContainsKey(id1) ? UeList[id1] : null;
if (ue0 == ue1)
{
if (ue1 == null)
{
ue1 = CreateUE(id1);
UeList[id0] = ue1;
}
}
else if (ue0 == null)
{
UeList[id0] = ue1;
}
else if (ue1 == null)
{
UeList[id1] = ue0;
}
else
{
// 合并所有指向id1的UE为ue0
var keysToUpdate = UeList.Where(kv => kv.Value == ue1).Select(kv => kv.Key).ToList();
foreach (var key in keysToUpdate)
{
UeList[key] = ue0;
}
// 合并属性
if (string.IsNullOrEmpty(ue0.Imsi)) ue0.Imsi = ue1.Imsi;
if (string.IsNullOrEmpty(ue0.Imei)) ue0.Imei = ue1.Imei;
if (ue0.Caps == null) ue0.Caps = ue1.Caps;
}
}
}
/// <summary>

52
LTEMvcApp/Models/LTELog.cs

@ -71,6 +71,11 @@ public class LTELog
/// </summary>
public string? Marker { get; set; }
/// <summary>
/// SIP原始消息内容
/// </summary>
public string? Msg0 { get; set; }
#endregion
#region PHY层相关属性
@ -171,6 +176,35 @@ public class LTELog
#endregion
#region MAC层相关属性
/// <summary>
/// 功率余量报告(PHR)
/// </summary>
public int? Phr { get; set; }
/// <summary>
/// 上行缓冲区大小
/// </summary>
public int? UlBufferSize { get; set; }
/// <summary>
/// MAC填充长度
/// </summary>
public int? MacPad { get; set; }
/// <summary>
/// MAC数据长度
/// </summary>
public int? MacLen { get; set; }
/// <summary>
/// 定时提前量(TA)
/// </summary>
public int? Ta { get; set; }
#endregion
#region 扩展方法
/// <summary>
@ -191,6 +225,24 @@ public class LTELog
return Data;
}
/// <summary>
/// 在数据中查找匹配正则表达式的模式
/// </summary>
/// <param name="regex">正则表达式</param>
/// <returns>匹配结果,如果没有匹配则返回null</returns>
public Match? FindData(Regex regex)
{
if (Data == null) return null;
foreach (var line in Data)
{
var match = regex.Match(line);
if (match.Success)
return match;
}
return null;
}
#endregion
}

Loading…
Cancel
Save