Browse Source

修复SIPProtocolParser.GeneralParse方法严谨性并增强日志跟踪

主要修复内容:
1. 修复变量名错误:MCC和MNC变量名与实际匹配内容对应
2. 增强空值检查:添加完整的参数验证和空值检查
3. 修复重复赋值:分别设置PLMN和IMSI属性
4. 优化正则表达式:添加RegexOptions.Compiled提高性能
5. 修复返回值检查:使用正确的StringToId返回值判断逻辑
6. 添加参数验证:验证Groups数量和参数有效性
7. 增强日志跟踪:
   - 添加ILogger支持,创建类型安全的Logger实例
   - 记录BuildProtocolLog参数为空的情况
   - 记录StringToId返回0(空字符串)的情况
   - 记录正则匹配Groups数量不足的详细信息
   - 使用私有Logger字段避免重复创建Logger实例

设计优势:
- 逻辑正确性:修复了变量名错误和重复赋值问题
- 空值安全:添加了完整的空值检查和参数验证
- 性能优化:正则表达式使用编译选项提高性能
- 代码严谨性:添加了Groups数量验证和参数有效性检查
- 错误预防:使用空条件操作符避免空引用异常
- 调试友好:提供详细的错误日志记录便于问题排查

影响范围:
- SIP协议解析的准确性
- 协议日志数据的完整性
- 代码的稳定性和可靠性
- 性能优化和错误预防
- 代码可读性和维护性
- 调试和问题排查能力显著提升
feature/protocol-log-Perfect
root 1 day ago
parent
commit
f542e1a0e7
  1. 62
      CoreAgent.ProtocolClient/BuildProtocolParser/SIPProtocolParser.cs
  2. 2
      CoreAgent.ProtocolClient/Context/ProtocolClientContext.cs
  3. 274
      CoreAgent.ProtocolClient/Helpers/TimeStampHelper.cs
  4. 17
      CoreAgent.ProtocolClient/Models/BuildProtocolLog.cs
  5. 9
      CoreAgent.ProtocolClient/ProtocolEngineCore/LogDataConverter.cs
  6. 3976
      modify.md

62
CoreAgent.ProtocolClient/BuildProtocolParser/SIPProtocolParser.cs

@ -2,27 +2,87 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using CoreAgent.ProtocolClient.Context;
using CoreAgent.ProtocolClient.Models;
using Microsoft.Extensions.Logging;
namespace CoreAgent.ProtocolClient.BuildProtocolParser
{
public class SIPProtocolParser : IGeneralProtocolParser
{
private readonly ProtocolClientContext context;
private readonly ILogger<SIPProtocolParser> _logger;
// 修复正则表达式,使其更加严谨
private readonly Regex _regMnc = new Regex(@"mnc(\d+)", RegexOptions.Compiled);
private readonly Regex _regMcc = new Regex(@"mcc(\d+)", RegexOptions.Compiled);
private readonly Regex _regIMSI = new Regex(@"<sip:(\d+)@", RegexOptions.Compiled);
public SIPProtocolParser(ProtocolClientContext context)
{
this.context = context;
this.context = context ?? throw new ArgumentNullException(nameof(context));
this._logger = context._loggerFactory.CreateLogger<SIPProtocolParser>();
}
public void GeneralParse(ref BuildProtocolLog log)
{
// 参数验证
if (log == null)
{
_logger.LogWarning("SIP协议解析失败:BuildProtocolLog参数为空");
return;
}
var SIPInfoMatch = ProtocolLogPatterns.RegExpSIP.Match(log.Message);
if (SIPInfoMatch.Success)
{
var info = context.UeIdentifier.StringToId(SIPInfoMatch.Groups[2].Value);
// 修复返回值检查逻辑 - StringToId返回0表示空字符串,不是-1
if (info == 0)
{
_logger.LogWarning("SIP协议解析失败:StringToId返回0,表示空字符串,消息内容: {Message}", log.Message);
return;
}
log.Info = info;
// 验证Groups数量
if (SIPInfoMatch.Groups.Count < 4)
{
_logger.LogWarning("SIP协议解析失败:正则匹配Groups数量不足,期望至少4个,实际{ActualCount}个,消息内容: {Message}",
SIPInfoMatch.Groups.Count, log.Message);
return;
}
string Direction = log.Direction == 1 ? "to" : "from";
log.Message = $"{SIPInfoMatch.Groups[3].Value} {Direction} {SIPInfoMatch.Groups[1].Value}";
// 修复变量名错误和空引用风险
var mncValue = log.Data?.Select(line => _regMnc.Match(line))
.Where(match => match.Success)
.Select(match => match.Groups[1].Value)
.FirstOrDefault();
var mccValue = log.Data?.Select(line => _regMcc.Match(line))
.Where(match => match.Success)
.Select(match => match.Groups[1].Value)
.FirstOrDefault();
var imsiValue = log.Data?.Select(line => _regIMSI.Match(line))
.Where(match => match.Success)
.Select(match => match.Groups[1].Value)
.FirstOrDefault();
// 设置PLMN - 修复逻辑错误
if (!string.IsNullOrEmpty(mccValue) && !string.IsNullOrEmpty(mncValue))
{
log.SIP.Plmn = $"{mccValue}{mncValue}";
}
// 设置IMSI - 使用正确的属性
if (!string.IsNullOrEmpty(imsiValue))
{
log.SIP.IMSI = imsiValue;
}
}
}
}

2
CoreAgent.ProtocolClient/Context/ProtocolClientContext.cs

@ -13,7 +13,7 @@ namespace CoreAgent.ProtocolClient.Context
{
// 常量和正则表达式已迁移至 ProtocolLogPatterns 静态类,便于统一管理和调用。
private readonly ILoggerFactory _loggerFactory;
public readonly ILoggerFactory _loggerFactory;
public ProtocolBasicInfo BasicInfo { get; set; } = new();
public ProtocolFeatureFlags FeatureFlags { get; set; } = new();

274
CoreAgent.ProtocolClient/Helpers/TimeStampHelper.cs

@ -0,0 +1,274 @@
using System;
namespace CoreAgent.ProtocolClient.Helpers
{
/// <summary>
/// 时间戳工具类
/// 提供各种时间戳转换和处理的静态方法
/// </summary>
public static class TimeStampHelper
{
/// <summary>
/// 中国标准时间(北京时间,UTC+8)
/// </summary>
private static readonly TimeZoneInfo ChinaStandardTime = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");
/// <summary>
/// 将只有时分秒毫秒的时间戳转换为包含年月日的完整时间戳(按北京时间)
/// </summary>
/// <param name="timeOnlyTimestamp">只有时分秒毫秒的时间戳(如:73365316)</param>
/// <returns>包含年月日的完整Unix时间戳(毫秒)</returns>
public static long ConvertToFullTimestamp(long timeOnlyTimestamp)
{
// 获取当前北京时间的日期部分
var utcNow = DateTime.UtcNow;
var beijingNow = TimeZoneInfo.ConvertTime(utcNow, ChinaStandardTime);
var beijingToday = beijingNow.Date;
// 将毫秒时间戳转换为TimeSpan
var timeSpan = TimeSpan.FromMilliseconds(timeOnlyTimestamp);
// 组合成完整的北京时间
var fullDateTime = beijingToday.Add(timeSpan);
// 转换为Unix时间戳(确保使用UTC时间)
var utcDateTime = TimeZoneInfo.ConvertTimeToUtc(fullDateTime, ChinaStandardTime);
return new DateTimeOffset(utcDateTime, TimeSpan.Zero).ToUnixTimeMilliseconds();
}
/// <summary>
/// 将Unix时间戳转换为北京时间
/// </summary>
/// <param name="timestamp">Unix时间戳(毫秒)</param>
/// <returns>北京时间</returns>
public static DateTime ConvertToBeijingTime(long timestamp)
{
var utcDateTime = DateTimeOffset.FromUnixTimeMilliseconds(timestamp).UtcDateTime;
return TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, ChinaStandardTime);
}
/// <summary>
/// 将Unix时间戳转换为UTC时间
/// </summary>
/// <param name="timestamp">Unix时间戳(毫秒)</param>
/// <returns>UTC时间</returns>
public static DateTime ConvertToUtcTime(long timestamp)
{
return DateTimeOffset.FromUnixTimeMilliseconds(timestamp).UtcDateTime;
}
/// <summary>
/// 获取时间戳的北京时间字符串表示
/// </summary>
/// <param name="timestamp">Unix时间戳(毫秒)</param>
/// <param name="includeMilliseconds">是否包含毫秒</param>
/// <returns>格式化的北京时间字符串</returns>
public static string GetBeijingTimeString(long timestamp, bool includeMilliseconds = true)
{
var beijingTime = ConvertToBeijingTime(timestamp);
return includeMilliseconds
? beijingTime.ToString("yyyy-MM-dd HH:mm:ss.fff")
: beijingTime.ToString("yyyy-MM-dd HH:mm:ss");
}
/// <summary>
/// 获取时间戳的UTC时间字符串表示
/// </summary>
/// <param name="timestamp">Unix时间戳(毫秒)</param>
/// <param name="includeMilliseconds">是否包含毫秒</param>
/// <returns>格式化的UTC时间字符串</returns>
public static string GetUtcTimeString(long timestamp, bool includeMilliseconds = true)
{
var utcTime = ConvertToUtcTime(timestamp);
return includeMilliseconds
? utcTime.ToString("yyyy-MM-dd HH:mm:ss.fff")
: utcTime.ToString("yyyy-MM-dd HH:mm:ss");
}
/// <summary>
/// 判断时间戳是否为毫秒级
/// </summary>
/// <param name="timestamp">时间戳</param>
/// <returns>true表示毫秒级,false表示秒级</returns>
public static bool IsMillisecondsTimestamp(long timestamp)
{
return timestamp > 9999999999; // 大于10位数字通常是毫秒级
}
/// <summary>
/// 智能转换时间戳(自动判断是秒级还是毫秒级)
/// </summary>
/// <param name="timestamp">时间戳</param>
/// <returns>北京时间</returns>
public static DateTime SmartConvertToBeijingTime(long timestamp)
{
if (IsMillisecondsTimestamp(timestamp))
{
return ConvertToBeijingTime(timestamp);
}
else
{
// 秒级时间戳转换为毫秒级
var millisecondTimestamp = timestamp * 1000;
return ConvertToBeijingTime(millisecondTimestamp);
}
}
/// <summary>
/// 智能转换时间戳(自动判断是秒级还是毫秒级)
/// </summary>
/// <param name="timestamp">时间戳</param>
/// <returns>UTC时间</returns>
public static DateTime SmartConvertToUtcTime(long timestamp)
{
if (IsMillisecondsTimestamp(timestamp))
{
return ConvertToUtcTime(timestamp);
}
else
{
// 秒级时间戳转换为毫秒级
var millisecondTimestamp = timestamp * 1000;
return ConvertToUtcTime(millisecondTimestamp);
}
}
/// <summary>
/// 获取当前北京时间的Unix时间戳
/// </summary>
/// <returns>当前北京时间的Unix时间戳(毫秒)</returns>
public static long GetCurrentBeijingTimestamp()
{
var beijingNow = TimeZoneInfo.ConvertTime(DateTime.UtcNow, ChinaStandardTime);
return new DateTimeOffset(beijingNow, ChinaStandardTime.GetUtcOffset(beijingNow)).ToUnixTimeMilliseconds();
}
/// <summary>
/// 获取当前UTC时间的Unix时间戳
/// </summary>
/// <returns>当前UTC时间的Unix时间戳(毫秒)</returns>
public static long GetCurrentUtcTimestamp()
{
return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}
/// <summary>
/// 解析时间字符串为Unix时间戳
/// </summary>
/// <param name="dateTimeString">时间字符串(格式:yyyy-MM-dd HH:mm:ss 或 yyyy-MM-dd HH:mm:ss.fff)</param>
/// <param name="isBeijingTime">是否为北京时间,true为北京时间,false为UTC时间</param>
/// <returns>Unix时间戳(毫秒)</returns>
public static long ParseDateTimeString(string dateTimeString, bool isBeijingTime = true)
{
if (DateTime.TryParse(dateTimeString, out DateTime parsedDateTime))
{
if (isBeijingTime)
{
// 假设输入的是北京时间,转换为UTC
var utcDateTime = TimeZoneInfo.ConvertTimeToUtc(parsedDateTime, ChinaStandardTime);
return new DateTimeOffset(utcDateTime, TimeSpan.Zero).ToUnixTimeMilliseconds();
}
else
{
// 假设输入的是UTC时间
return new DateTimeOffset(parsedDateTime, TimeSpan.Zero).ToUnixTimeMilliseconds();
}
}
throw new ArgumentException($"无法解析时间字符串: {dateTimeString}");
}
/// <summary>
/// 获取时间戳的详细信息
/// </summary>
/// <param name="timestamp">Unix时间戳(毫秒)</param>
/// <returns>包含各种时间格式的详细信息</returns>
public static TimeStampInfo GetTimeStampInfo(long timestamp)
{
var beijingTime = ConvertToBeijingTime(timestamp);
var utcTime = ConvertToUtcTime(timestamp);
return new TimeStampInfo
{
OriginalTimestamp = timestamp,
BeijingTime = beijingTime,
UtcTime = utcTime,
BeijingTimeString = beijingTime.ToString("yyyy-MM-dd HH:mm:ss.fff"),
UtcTimeString = utcTime.ToString("yyyy-MM-dd HH:mm:ss.fff"),
Year = beijingTime.Year,
Month = beijingTime.Month,
Day = beijingTime.Day,
Hour = beijingTime.Hour,
Minute = beijingTime.Minute,
Second = beijingTime.Second,
Millisecond = beijingTime.Millisecond
};
}
}
/// <summary>
/// 时间戳详细信息
/// </summary>
public class TimeStampInfo
{
/// <summary>
/// 原始时间戳
/// </summary>
public long OriginalTimestamp { get; set; }
/// <summary>
/// 北京时间
/// </summary>
public DateTime BeijingTime { get; set; }
/// <summary>
/// UTC时间
/// </summary>
public DateTime UtcTime { get; set; }
/// <summary>
/// 北京时间字符串
/// </summary>
public string BeijingTimeString { get; set; } = string.Empty;
/// <summary>
/// UTC时间字符串
/// </summary>
public string UtcTimeString { get; set; } = string.Empty;
/// <summary>
/// 年
/// </summary>
public int Year { get; set; }
/// <summary>
/// 月
/// </summary>
public int Month { get; set; }
/// <summary>
/// 日
/// </summary>
public int Day { get; set; }
/// <summary>
/// 时
/// </summary>
public int Hour { get; set; }
/// <summary>
/// 分
/// </summary>
public int Minute { get; set; }
/// <summary>
/// 秒
/// </summary>
public int Second { get; set; }
/// <summary>
/// 毫秒
/// </summary>
public int Millisecond { get; set; }
}
}

17
CoreAgent.ProtocolClient/Models/BuildProtocolLog.cs

@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using CoreAgent.ProtocolClient.BuildProtocolParser;
namespace CoreAgent.ProtocolClient.Models
{
@ -78,6 +79,10 @@ namespace CoreAgent.ProtocolClient.Models
#region MAC层相关属性
public MacLayerFields Mac { get; set; } = new();
#endregion
#region
public SIPLayerFields SIP { get; set; } = new ();
#endregion
}
// PHY层分组
@ -195,6 +200,18 @@ namespace CoreAgent.ProtocolClient.Models
public int? Ran { get; set; }
}
public class SIPLayerFields
{
/// <summary>
/// PLMN标识
/// </summary>
public string? Plmn { get; set; } = string.Empty;
/// <summary>
/// IMSI标识
/// </summary>
public string? IMSI { get; set; } = string.Empty;
}
/// <summary>
/// BuildProtocolLog扩展方法类

9
CoreAgent.ProtocolClient/ProtocolEngineCore/LogDataConverter.cs

@ -5,6 +5,7 @@ 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;
@ -158,12 +159,13 @@ namespace CoreAgent.ProtocolClient.ProtocolEngineCore
Direction = log.Direction,
UEID = log.UeId,
CellID = log.Cell,
Timestamp = log.Timestamp,
//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.Name == "RAN")
{
// 获取IMSI信息
@ -172,6 +174,11 @@ namespace CoreAgent.ProtocolClient.ProtocolEngineCore
// 获取PLMN信息
detail.PLMN = GetPlmnFromPlmnToUeIdMapping(log.UeId, srTmsiMappings);
}
if (_config.Name == "IMS")
{
detail.IMSI = log.SIP.IMSI;
detail.PLMN = log.SIP.Plmn;
}
return detail;
}

3976
modify.md

File diff suppressed because it is too large
Loading…
Cancel
Save