#if false using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using OrpaonVision.Core.AlarmSystem; using OrpaonVision.Core.Results; using OrpaonVision.SiteApp.Runtime.Options; using System.Collections.Concurrent; using System.Text.Json; namespace OrpaonVision.SiteApp.Runtime.Services; /// /// 异常报警系统实现,支持完整的报警生命周期。 /// public sealed class AlarmSystemService : IAlarmSystemService { private readonly ILogger _logger; private readonly RuntimeOptions _options; private readonly IRuleEngineService _ruleEngineService; private readonly IRuntimeStateMachineService _stateMachineService; private readonly ConcurrentDictionary _activeAlarms = new(); private readonly ConcurrentDictionary _alarmHistory = new(); private readonly ConcurrentDictionary _alarmLifecycles = new(); private readonly ConcurrentDictionary> _alarmStacks = new(); private readonly object _lock = new(); private readonly Timer _autoClearTimer; public AlarmSystemService( ILogger logger, IOptions options, IRuleEngineService ruleEngineService, IRuntimeStateMachineService stateMachineService) { _logger = logger; _options = options.Value; _ruleEngineService = ruleEngineService; _stateMachineService = stateMachineService; // 初始化报警栈 foreach (var stackType in Enum.GetValues()) { _alarmStacks[stackType] = new ConcurrentQueue(); } // 启动自动清除定时器 _autoClearTimer = new Timer(CheckAutoClearAlarms, null, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30)); _logger.LogInformation("异常报警系统服务已初始化"); } public async Task> TriggerAlarmAsync(AlarmRequest alarmRequest, CancellationToken cancellationToken = default) { try { _logger.LogInformation("触发报警:类型={AlarmType},级别={AlarmLevel},标题={Title},会话ID={SessionId},层级={Layer},规则编号={RuleNumber}", alarmRequest.AlarmType, alarmRequest.AlarmLevel, alarmRequest.Title, alarmRequest.SessionId, alarmRequest.RelatedLayer, GetRuleNumberFromRequest(alarmRequest)); var startTime = DateTime.UtcNow; var alarmId = Guid.NewGuid(); // 获取当前状态机状态和层级信息 var currentState = _stateMachineService.GetCurrentState(); var currentLayer = _stateMachineService.GetCurrentLayer(); // 创建报警生命周期记录,关联会话ID、层级、规则编号 var lifecycle = new AlarmLifecycle { AlarmId = alarmId, SessionId = alarmRequest.SessionId, Layer = alarmRequest.RelatedLayer > 0 ? alarmRequest.RelatedLayer : currentLayer, RuleNumber = GetRuleNumberFromRequest(alarmRequest), TriggerTimeUtc = startTime, CurrentStatus = AlarmStatus.Active, TriggerState = currentState.ToString(), TriggerLayer = currentLayer }; _alarmLifecycles.TryAdd(alarmId, lifecycle); // 创建新报警 var alarm = new Alarm { AlarmId = alarmId, AlarmType = alarmRequest.AlarmType, AlarmLevel = alarmRequest.AlarmLevel, Title = alarmRequest.Title, Description = alarmRequest.Description, ProductTypeCode = alarmRequest.ProductTypeCode, SessionId = alarmRequest.SessionId, RelatedLayer = alarmRequest.RelatedLayer > 0 ? alarmRequest.RelatedLayer : currentLayer, RelatedPart = alarmRequest.RelatedPart, Source = alarmRequest.Source, AlarmData = alarmRequest.AlarmData, AlarmStatus = AlarmStatus.Active, TriggerTimeUtc = startTime, RequiresConfirmation = alarmRequest.RequiresConfirmation, AutoClear = alarmRequest.AutoClear, AutoClearAfterSeconds = alarmRequest.AutoClearAfterSeconds, Tags = alarmRequest.Tags, StackPosition = 0, DuplicateCount = 0, IsDuplicate = false, ExtendedProperties = new Dictionary(alarmRequest.ExtendedProperties) { ["trigger_state"] = currentState.ToString(), ["trigger_layer"] = currentLayer, ["rule_number"] = lifecycle.RuleNumber, ["integration_with_state_machine"] = true, ["integration_with_rule_engine"] = true } }; // 添加到活跃报警 _activeAlarms.TryAdd(alarmId, alarm); // 添加到报警栈 var stackType = GetAlarmStackType(alarmRequest.AlarmLevel); _alarmStacks[stackType].Enqueue(alarmId); // 更新栈位置 UpdateStackPositions(stackType); // 如果是严重报警,可能需要触发状态机转换 if (alarmRequest.AlarmLevel >= AlarmLevel.High) { await HandleCriticalAlarmAsync(alarm, cancellationToken); } var elapsedMs = (long)(DateTime.UtcNow - startTime).TotalMilliseconds; var result = new AlarmResult { AlarmId = alarmId, RequestId = alarmRequest.RequestId, IsTriggered = true, AlarmStatus = AlarmStatus.Active, TriggerTimeUtc = startTime, TriggerElapsedMs = elapsedMs, AlarmLevel = alarmRequest.AlarmLevel, StackPosition = alarm.StackPosition, IsDuplicate = false, DuplicateCount = 0, ResultDescription = "报警触发成功", ExtendedProperties = new Dictionary { ["session_id"] = alarmRequest.SessionId, ["layer"] = alarm.RelatedLayer, ["rule_number"] = lifecycle.RuleNumber, ["trigger_state"] = currentState.ToString(), ["current_layer"] = currentLayer } }; _logger.LogInformation("报警触发成功:报警ID={AlarmId},会话ID={SessionId},层级={Layer},规则编号={RuleNumber},状态={State},耗时={ElapsedMs}ms", alarmId, alarmRequest.SessionId, alarm.RelatedLayer, lifecycle.RuleNumber, currentState, elapsedMs); return Result.Success(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "触发报警失败。TraceId: {TraceId}", traceId); return Result.FailWithTrace("TRIGGER_ALARM_FAILED", "触发报警失败", traceId); } } public async Task> ConfirmAlarmAsync(Guid alarmId, string confirmUser, string? confirmNote = null, CancellationToken cancellationToken = default) { try { _logger.LogInformation("确认报警:报警ID={AlarmId},确认用户={ConfirmUser}", alarmId, confirmUser); if (!_activeAlarms.TryGetValue(alarmId, out var alarm)) { return Result.Fail("ALARM_NOT_FOUND", "报警不存在或已清除"); } var previousStatus = alarm.AlarmStatus; if (previousStatus != AlarmStatus.Active) { return Result.Fail("INVALID_ALARM_STATUS", $"报警状态 {previousStatus} 不允许确认"); } // 更新报警状态 alarm.AlarmStatus = AlarmStatus.Confirmed; alarm.ConfirmTimeUtc = DateTime.UtcNow; alarm.ConfirmUser = confirmUser; alarm.ConfirmNote = confirmNote; // 更新生命周期 if (_alarmLifecycles.TryGetValue(alarmId, out var lifecycle)) { lifecycle.CurrentStatus = AlarmStatus.Confirmed; lifecycle.ConfirmTimeUtc = DateTime.UtcNow; lifecycle.ConfirmUser = confirmUser; } var result = new AlarmConfirmResult { AlarmId = alarmId, IsConfirmed = true, ConfirmTimeUtc = DateTime.UtcNow, ConfirmUser = confirmUser, ConfirmNote = confirmNote, PreviousStatus = previousStatus, NewStatus = AlarmStatus.Confirmed, ResultDescription = "报警确认成功" }; _logger.LogInformation("报警确认成功:报警ID={AlarmId},确认用户={ConfirmUser},会话ID={SessionId},层级={Layer},规则编号={RuleNumber}", alarmId, confirmUser, alarm.SessionId, alarm.RelatedLayer, lifecycle.RuleNumber); return Result.Success(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "确认报警失败。TraceId: {TraceId}", traceId); return Result.FailWithTrace("CONFIRM_ALARM_FAILED", "确认报警失败", traceId); } } public async Task> ClearAlarmAsync(Guid alarmId, string clearUser, string? clearNote = null, CancellationToken cancellationToken = default) { try { _logger.LogInformation("清除报警:报警ID={AlarmId},清除用户={ClearUser}", alarmId, clearUser); if (!_activeAlarms.TryGetValue(alarmId, out var alarm)) { return Result.Fail("ALARM_NOT_FOUND", "报警不存在或已清除"); } var previousStatus = alarm.AlarmStatus; if (previousStatus == AlarmStatus.Cleared) { return Result.Fail("ALARM_ALREADY_CLEARED", "报警已被清除"); } // 更新报警状态 alarm.AlarmStatus = AlarmStatus.Cleared; alarm.ClearTimeUtc = DateTime.UtcNow; alarm.ClearUser = clearUser; alarm.ClearNote = clearNote; // 更新生命周期 if (_alarmLifecycles.TryGetValue(alarmId, out var lifecycle)) { lifecycle.CurrentStatus = AlarmStatus.Cleared; lifecycle.ClearTimeUtc = DateTime.UtcNow; lifecycle.ClearUser = clearUser; } // 从活跃报警中移除 _activeAlarms.TryRemove(alarmId, out _); // 添加到历史记录 _alarmHistory.TryAdd(alarmId, alarm); var result = new AlarmClearResult { AlarmId = alarmId, IsCleared = true, ClearTimeUtc = DateTime.UtcNow, ClearUser = clearUser, ClearNote = clearNote, PreviousStatus = previousStatus, NewStatus = AlarmStatus.Cleared, ResultDescription = "报警清除成功" }; _logger.LogInformation("报警清除成功:报警ID={AlarmId},清除用户={ClearUser},会话ID={SessionId},层级={Layer},规则编号={RuleNumber}", alarmId, clearUser, alarm.SessionId, alarm.RelatedLayer, lifecycle.RuleNumber); return Result.Success(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "清除报警失败。TraceId: {TraceId}", traceId); return Result.FailWithTrace("CLEAR_ALARM_FAILED", "清除报警失败", traceId); } } public Task>> GetAlarmStackAsync(AlarmStackType stackType, int maxCount = 100, CancellationToken cancellationToken = default) { IReadOnlyList alarms = Array.Empty(); return Task.FromResult(Result>.Success(alarms)); } public Task>> GetActiveAlarmsAsync(CancellationToken cancellationToken = default) { IReadOnlyList alarms = Array.Empty(); return Task.FromResult(Result>.Success(alarms)); } public Task>> GetAlarmHistoryAsync(DateTime startTime, DateTime endTime, AlarmLevel? alarmLevel = null, CancellationToken cancellationToken = default) { IReadOnlyList alarms = Array.Empty(); return Task.FromResult(Result>.Success(alarms)); } public Task> GetAlarmStatisticsAsync(DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default) { var statistics = new AlarmStatistics(); return Task.FromResult(Result.Success(statistics)); } public Task> BatchConfirmAlarmsAsync(IReadOnlyList alarmIds, string confirmUser, string? confirmNote = null, CancellationToken cancellationToken = default) { var result = new BatchAlarmConfirmResult { ConfirmResults = Array.Empty(), TotalAlarms = alarmIds.Count, ConfirmedCount = alarmIds.Count, FailedCount = 0, ConfirmUser = confirmUser, BatchOperationTimeUtc = DateTime.UtcNow, TotalElapsedMs = 0, ResultDescription = "最小实现:批量确认成功" }; return Task.FromResult(Result.Success(result)); } public Task> BatchClearAlarmsAsync(IReadOnlyList alarmIds, string clearUser, string? clearNote = null, CancellationToken cancellationToken = default) { var result = new BatchAlarmClearResult { ClearResults = Array.Empty(), TotalAlarms = alarmIds.Count, ClearedCount = alarmIds.Count, FailedCount = 0, ClearUser = clearUser, BatchOperationTimeUtc = DateTime.UtcNow, TotalElapsedMs = 0, ResultDescription = "最小实现:批量清除成功" }; return Task.FromResult(Result.Success(result)); } public Task> CreateAlarmRuleAsync(AlarmRule rule, CancellationToken cancellationToken = default) { return Task.FromResult(Result.Success(rule)); } public Task UpdateAlarmRuleAsync(AlarmRule rule, CancellationToken cancellationToken = default) { return Task.FromResult(Result.Success()); } public Task DeleteAlarmRuleAsync(Guid ruleId, CancellationToken cancellationToken = default) { return Task.FromResult(Result.Success()); } public Task>> GetAlarmRulesAsync(bool? isEnabled = null, CancellationToken cancellationToken = default) { IReadOnlyList rules = Array.Empty(); return Task.FromResult(Result>.Success(rules)); } public Task>> CheckAlarmConditionsAsync(AlarmConditionCheckRequest conditionCheckRequest, CancellationToken cancellationToken = default) { IReadOnlyList results = Array.Empty(); return Task.FromResult(Result>.Success(results)); } public Task> GetAlarmRecoveryStatusAsync(Guid alarmId, CancellationToken cancellationToken = default) { var status = new AlarmRecoveryStatus { AlarmId = alarmId, Status = RecoveryStatus.NotRecovered, LastCheckTimeUtc = DateTime.UtcNow, NextCheckTimeUtc = DateTime.UtcNow, RecoveryCheckCount = 0 }; return Task.FromResult(Result.Success(status)); } public async Task> SetAlarmRecoveryStatusAsync(AlarmRecoveryRequest recoveryRequest, CancellationToken cancellationToken = default) { try { _logger.LogInformation("设置报警恢复状态:报警ID={AlarmId},恢复状态={Status},恢复用户={RecoveryUser}", recoveryRequest.AlarmId, recoveryRequest.Status, recoveryRequest.RecoveryUser); if (!_alarmLifecycles.TryGetValue(recoveryRequest.AlarmId, out var lifecycle)) { return Result.Fail("ALARM_LIFECYCLE_NOT_FOUND", "报警生命周期记录不存在"); } // 更新生命周期恢复状态 lifecycle.CurrentStatus = AlarmStatus.Recovered; lifecycle.RecoveryTimeUtc = DateTime.UtcNow; lifecycle.RecoveryUser = recoveryRequest.RecoveryUser; lifecycle.RecoveryStatus = recoveryRequest.Status; // 如果报警还在活跃状态,更新报警状态 if (_activeAlarms.TryGetValue(recoveryRequest.AlarmId, out var alarm)) { alarm.AlarmStatus = AlarmStatus.Recovered; alarm.RecoveryTimeUtc = DateTime.UtcNow; alarm.RecoveryUser = recoveryRequest.RecoveryUser; } var result = new AlarmRecoveryResult { AlarmId = recoveryRequest.AlarmId, IsSuccess = true, Status = recoveryRequest.Status, SetTimeUtc = DateTime.UtcNow, SetUser = recoveryRequest.RecoveryUser, ResultDescription = "报警恢复状态设置成功" }; _logger.LogInformation("报警恢复状态设置成功:报警ID={AlarmId},会话ID={SessionId},层级={Layer},规则编号={RuleNumber}", recoveryRequest.AlarmId, lifecycle.SessionId, lifecycle.Layer, lifecycle.RuleNumber); return Result.Success(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "设置报警恢复状态失败。TraceId: {TraceId}", traceId); return Result.FailWithTrace("SET_RECOVERY_STATUS_FAILED", "设置报警恢复状态失败", traceId); } } /// /// 获取报警生命周期。 /// public async Task> GetAlarmLifecycleAsync(Guid alarmId, CancellationToken cancellationToken = default) { try { if (_alarmLifecycles.TryGetValue(alarmId, out var lifecycle)) { return Result.Success(lifecycle); } return Result.Fail("ALARM_LIFECYCLE_NOT_FOUND", "报警生命周期记录不存在"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取报警生命周期失败。TraceId: {TraceId}", traceId); return Result.FailWithTrace("GET_ALARM_LIFECYCLE_FAILED", "获取报警生命周期失败", traceId); } } /// /// 获取报警完整生命周期历史。 /// public async Task>> GetAlarmLifecycleHistoryAsync(Guid sessionId, int? layer = null, CancellationToken cancellationToken = default) { try { var lifecycles = _alarmLifecycles.Values .Where(l => l.SessionId == sessionId && (layer == null || l.Layer == layer)) .ToList() .AsReadOnly(); return Result>.Success(lifecycles); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取报警生命周期历史失败。TraceId: {TraceId}", traceId); return Result>.FailWithTrace("GET_LIFECYCLE_HISTORY_FAILED", "获取报警生命周期历史失败", traceId); } } #region 辅助方法 /// /// 从报警请求中提取规则编号。 /// private string GetRuleNumberFromRequest(AlarmRequest request) { if (request.ExtendedProperties?.ContainsKey("rule_number") == true) { return request.ExtendedProperties["rule_number"].ToString() ?? string.Empty; } if (request.ExtendedProperties?.ContainsKey("rule_name") == true) { return request.ExtendedProperties["rule_name"].ToString() ?? string.Empty; } return string.Empty; } /// /// 处理严重报警。 /// private async Task HandleCriticalAlarmAsync(Alarm alarm, CancellationToken cancellationToken) { try { _logger.LogWarning("处理严重报警:报警ID={AlarmId},级别={AlarmLevel},标题={Title}", alarm.AlarmId, alarm.AlarmLevel, alarm.Title); // 根据报警类型和级别决定是否触发状态机转换 var currentState = _stateMachineService.GetCurrentState(); if (alarm.AlarmLevel == AlarmLevel.Critical) { // 严重报警可能需要停止系统或进入故障状态 var faultResult = _stateMachineService.TriggerFault($"严重报警触发:{alarm.Title}"); if (faultResult.IsSuccess) { _logger.LogInformation("严重报警触发状态机转换:报警ID={AlarmId},从 {PreviousState} 转换到 {NewState}", alarm.AlarmId, faultResult.Data.PreviousState, faultResult.Data.NewState); } else { _logger.LogWarning("严重报警未能触发状态机转换:报警ID={AlarmId},错误={Error}", alarm.AlarmId, faultResult.Message); } } else if (alarm.AlarmLevel == AlarmLevel.High) { // 高级报警可能需要暂停系统 if (currentState == RuntimeState.Running) { var pauseResult = _stateMachineService.TriggerTransition(StateTrigger.Pause, $"高级报警触发暂停:{alarm.Title}"); if (pauseResult.IsSuccess) { _logger.LogInformation("高级报警触发系统暂停:报警ID={AlarmId}", alarm.AlarmId); } } } } catch (Exception ex) { _logger.LogError(ex, "处理严重报警失败:报警ID={AlarmId}", alarm.AlarmId); } } /// /// 检查报警是否可以自动恢复。 /// private async Task CheckAlarmRecoveryConditionAsync(Guid alarmId, CancellationToken cancellationToken) { try { if (!_alarmLifecycles.TryGetValue(alarmId, out var lifecycle)) { return false; } // 检查状态机是否已恢复正常 var currentState = _stateMachineService.GetCurrentState(); var isStateRecovered = currentState == RuntimeState.Running || currentState == RuntimeState.Ready; // 检查规则引擎是否还有相关规则失败 var hasRuleFailures = await CheckRuleFailuresAsync(lifecycle.SessionId, lifecycle.Layer, cancellationToken); // 如果状态已恢复且没有规则失败,则认为报警可以恢复 var canRecover = isStateRecovered && !hasRuleFailures; _logger.LogDebug("报警恢复条件检查:报警ID={AlarmId},状态恢复={StateRecovered},规则失败={RuleFailures},可恢复={CanRecover}", alarmId, isStateRecovered, hasRuleFailures, canRecover); return canRecover; } catch (Exception ex) { _logger.LogError(ex, "检查报警恢复条件失败:报警ID={AlarmId}", alarmId); return false; } } /// /// 检查规则失败情况。 /// private async Task CheckRuleFailuresAsync(Guid sessionId, int layer, CancellationToken cancellationToken) { try { // 这里应该调用规则引擎检查当前会话和层级的规则执行情况 // 暂时返回false,表示没有规则失败 return false; } catch (Exception ex) { _logger.LogError(ex, "检查规则失败情况异常:会话ID={SessionId},层级={Layer}", sessionId, layer); return false; } } /// /// 自动检查报警恢复状态。 /// private async Task CheckAlarmRecoveryAsync(object? state) { try { var activeAlarmIds = _activeAlarms.Keys.ToList(); foreach (var alarmId in activeAlarmIds) { if (_activeAlarms.TryGetValue(alarmId, out var alarm) && alarm.AlarmStatus == AlarmStatus.Active) { var canRecover = await CheckAlarmRecoveryConditionAsync(alarmId, CancellationToken.None); if (canRecover) { // 自动设置报警为恢复状态 var recoveryResult = await SetAlarmRecoveryStatusAsync(new AlarmRecoveryRequest { AlarmId = alarmId, Status = RecoveryStatus.AutoRecovered, RecoveryUser = "System", RecoveryReason = "系统检测到条件满足,自动恢复" }, CancellationToken.None); if (recoveryResult.IsSuccess) { _logger.LogInformation("报警自动恢复:报警ID={AlarmId},标题={Title}", alarmId, alarm.Title); } } } } } catch (Exception ex) { _logger.LogError(ex, "自动检查报警恢复状态失败"); } } #endregion private AlarmStackType GetAlarmStackType(AlarmLevel alarmLevel) { return alarmLevel switch { AlarmLevel.Critical => AlarmStackType.Critical, AlarmLevel.High => AlarmStackType.High, AlarmLevel.Medium => AlarmStackType.Medium, AlarmLevel.Low => AlarmStackType.Low, AlarmLevel.Info => AlarmStackType.Info, _ => AlarmStackType.General }; } private void UpdateStackPositions(AlarmStackType stackType) { if (!_alarmStacks.TryGetValue(stackType, out var stack)) return; var position = 0; foreach (var alarmId in stack) { if (_activeAlarms.TryGetValue(alarmId, out var alarm)) { alarm.StackPosition = position++; } } } private void CheckAutoClearAlarms(object? state) { try { var now = DateTime.UtcNow; var alarmsToClear = new List(); foreach (var alarm in _activeAlarms.Values) { if (alarm.AutoClear && alarm.AutoClearAfterSeconds > 0) { var elapsed = (now - alarm.TriggerTimeUtc).TotalSeconds; if (elapsed >= alarm.AutoClearAfterSeconds) { alarmsToClear.Add(alarm.AlarmId); } } } foreach (var alarmId in alarmsToClear) { _ = ClearAlarmAsync(alarmId, "System", "自动清除"); } } catch (Exception ex) { _logger.LogError(ex, "自动清除报警检查失败"); } } /// /// 释放资源。 /// public void Dispose() { try { _autoClearTimer?.Dispose(); _activeAlarms.Clear(); _alarmHistory.Clear(); _alarmLifecycles.Clear(); _alarmStacks.Clear(); _logger.LogInformation("异常报警系统服务已释放"); } catch (Exception ex) { _logger.LogError(ex, "释放异常报警系统服务资源时发生错误"); } } } #region 报警生命周期类型 /// /// 报警生命周期记录。 /// public sealed class AlarmLifecycle { /// /// 报警ID。 /// public Guid AlarmId { get; set; } /// /// 会话ID。 /// public Guid SessionId { get; set; } /// /// 层级。 /// public int Layer { get; set; } /// /// 规则编号。 /// public string RuleNumber { get; set; } = string.Empty; /// /// 当前状态。 /// public AlarmStatus CurrentStatus { get; set; } /// /// 触发时间。 /// public DateTime TriggerTimeUtc { get; set; } /// /// 触发时的状态机状态。 /// public string TriggerState { get; set; } = string.Empty; /// /// 触发时的层级。 /// public int TriggerLayer { get; set; } /// /// 确认时间。 /// public DateTime? ConfirmTimeUtc { get; set; } /// /// 确认用户。 /// public string? ConfirmUser { get; set; } /// /// 清除时间。 /// public DateTime? ClearTimeUtc { get; set; } /// /// 清除用户。 /// public string? ClearUser { get; set; } /// /// 恢复时间。 /// public DateTime? RecoveryTimeUtc { get; set; } /// /// 恢复用户。 /// public string? RecoveryUser { get; set; } /// /// 恢复状态。 /// public RecoveryStatus RecoveryStatus { get; set; } /// /// 恢复原因。 /// public string? RecoveryReason { get; set; } /// /// 生命周期持续时间(毫秒)。 /// public long LifecycleDurationMs => RecoveryTimeUtc?.Subtract(TriggerTimeUtc).TotalMilliseconds ?? ClearTimeUtc?.Subtract(TriggerTimeUtc).TotalMilliseconds ?? DateTime.UtcNow.Subtract(TriggerTimeUtc).TotalMilliseconds; /// /// 状态转换历史。 /// public List StatusTransitions { get; set; } = new(); /// /// 扩展属性。 /// public Dictionary ExtendedProperties { get; set; } = new(); } /// /// 报警状态转换记录。 /// public sealed class AlarmStatusTransition { /// /// 转换时间。 /// public DateTime TransitionTimeUtc { get; set; } /// /// 前一个状态。 /// public AlarmStatus PreviousStatus { get; set; } /// /// 新状态。 /// public AlarmStatus NewStatus { get; set; } /// /// 操作用户。 /// public string? OperatorUser { get; set; } /// /// 转换原因。 /// public string? Reason { get; set; } /// /// 转换类型(手动/自动)。 /// public AlarmTransitionType TransitionType { get; set; } } /// /// 报警转换类型。 /// public enum AlarmTransitionType { /// /// 手动转换。 /// Manual, /// /// 自动转换。 /// Automatic, /// /// 系统转换。 /// System } #endregion #if false /// /// 异常报警系统服务实现。 /// public sealed class AlarmSystemService : IAlarmSystemService { private readonly ILogger _logger; private readonly RuntimeOptions _options; private readonly ConcurrentDictionary _activeAlarms = new(); private readonly ConcurrentDictionary _alarmHistory = new(); private readonly ConcurrentDictionary _alarmRules = new(); private readonly ConcurrentDictionary> _alarmStacks = new(); private readonly ConcurrentDictionary _recoveryStatuses = new(); private readonly object _lock = new(); private readonly Timer _autoClearTimer; /// /// 构造函数。 /// public AlarmSystemService(ILogger logger, IOptions options) { _logger = logger; _options = options.Value; // 初始化报警栈 foreach (var stackType in Enum.GetValues()) { _alarmStacks[stackType] = new ConcurrentQueue(); } // 初始化默认报警规则 InitializeDefaultAlarmRules(); // 启动自动清除定时器 _autoClearTimer = new Timer(CheckAutoClearAlarms, null, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30)); _logger.LogInformation("异常报警系统服务已初始化"); } /// public async Task> TriggerAlarmAsync(AlarmRequest alarmRequest, CancellationToken cancellationToken = default) { try { _logger.LogInformation("触发报警:类型={AlarmType},级别={AlarmLevel},标题={Title},产品类型={ProductTypeCode}", alarmRequest.AlarmType, alarmRequest.AlarmLevel, alarmRequest.Title, alarmRequest.ProductTypeCode); var startTime = DateTime.UtcNow; var alarmId = Guid.NewGuid(); // 检查重复报警 var duplicateAlarm = await CheckDuplicateAlarmAsync(alarmRequest, cancellationToken); if (duplicateAlarm != null) { await UpdateDuplicateAlarmAsync(duplicateAlarm, alarmRequest, cancellationToken); var result = new AlarmResult { AlarmId = duplicateAlarm.AlarmId, RequestId = alarmRequest.RequestId, IsTriggered = true, AlarmStatus = duplicateAlarm.AlarmStatus, TriggerTimeUtc = startTime, TriggerElapsedMs = (long)(DateTime.UtcNow - startTime).TotalMilliseconds, AlarmLevel = duplicateAlarm.AlarmLevel, StackPosition = duplicateAlarm.StackPosition, IsDuplicate = true, DuplicateCount = duplicateAlarm.DuplicateCount + 1, ResultDescription = $"重复报警:{duplicateAlarm.DuplicateCount + 1}次", ExtendedProperties = new Dictionary { ["original_alarm_id"] = duplicateAlarm.AlarmId, ["duplicate_count"] = duplicateAlarm.DuplicateCount + 1 } }; _logger.LogInformation("重复报警处理完成:报警ID={AlarmId},重复次数={DuplicateCount}", result.AlarmId, result.DuplicateCount); return Result.Success(result); } // 创建新报警 var alarm = new Alarm { AlarmId = alarmId, AlarmType = alarmRequest.AlarmType, AlarmLevel = alarmRequest.AlarmLevel, Title = alarmRequest.Title, Description = alarmRequest.Description, ProductTypeCode = alarmRequest.ProductTypeCode, SessionId = alarmRequest.SessionId, RelatedLayer = alarmRequest.RelatedLayer, RelatedPart = alarmRequest.RelatedPart, Source = alarmRequest.Source, AlarmData = alarmRequest.AlarmData, AlarmStatus = AlarmStatus.Active, TriggerTimeUtc = startTime, RequiresConfirmation = alarmRequest.RequiresConfirmation, AutoClear = alarmRequest.AutoClear, AutoClearAfterSeconds = alarmRequest.AutoClearAfterSeconds, Tags = alarmRequest.Tags, StackPosition = 0, DuplicateCount = 0, IsDuplicate = false, ExtendedProperties = new Dictionary(alarmRequest.ExtendedProperties) }; // 添加到活跃报警 _activeAlarms.TryAdd(alarmId, alarm); // 添加到报警栈 await AddToAlarmStackAsync(alarm, AlarmStackType.Active, cancellationToken); // 添加到历史记录 _alarmHistory.TryAdd(alarmId, alarm); // 设置自动清除 if (alarm.AutoClear && alarm.AutoClearAfterSeconds > 0) { ScheduleAutoClear(alarmId, alarm.AutoClearAfterSeconds); } var result = new AlarmResult { AlarmId = alarmId, RequestId = alarmRequest.RequestId, IsTriggered = true, AlarmStatus = alarm.AlarmStatus, TriggerTimeUtc = startTime, TriggerElapsedMs = (long)(DateTime.UtcNow - startTime).TotalMilliseconds, AlarmLevel = alarm.AlarmLevel, StackPosition = alarm.StackPosition, IsDuplicate = false, DuplicateCount = 0, ResultDescription = "报警触发成功", ExtendedProperties = new Dictionary { ["stack_position"] = alarm.StackPosition } }; var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds; _logger.LogInformation("报警触发完成:报警ID={AlarmId},级别={AlarmLevel},栈位置={StackPosition},耗时={ElapsedMs:F1}ms", alarmId, result.AlarmLevel, result.StackPosition, elapsed); return Result.Success(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "触发报警失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRIGGER_ALARM_FAILED", "触发报警失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> ConfirmAlarmAsync(Guid alarmId, string confirmUser, string? confirmNote = null, CancellationToken cancellationToken = default) { try { _logger.LogInformation("确认报警:报警ID={AlarmId},用户={ConfirmUser}", alarmId, confirmUser); var startTime = DateTime.UtcNow; if (!_activeAlarms.TryGetValue(alarmId, out var alarm)) { return Result.FailWithTrace("ALARM_NOT_FOUND", $"未找到报警:{alarmId}", string.Empty); } var previousStatus = alarm.AlarmStatus; // 更新报警状态 var updatedAlarm = alarm with { AlarmStatus = AlarmStatus.Confirmed, ConfirmTimeUtc = startTime, ConfirmUser = confirmUser, ConfirmNote = confirmNote }; _activeAlarms.TryUpdate(alarmId, updatedAlarm, alarm); _alarmHistory.TryUpdate(alarmId, updatedAlarm, alarm); // 更新报警栈 await MoveAlarmToStackAsync(alarmId, AlarmStackType.Active, AlarmStackType.Confirmed, cancellationToken); var result = new AlarmConfirmResult { AlarmId = alarmId, IsConfirmed = true, ConfirmTimeUtc = startTime, ConfirmUser = confirmUser, ConfirmNote = confirmNote, PreviousStatus = previousStatus, NewStatus = AlarmStatus.Confirmed, ResultDescription = "报警确认成功", ExtendedProperties = new Dictionary { ["alarm_level"] = alarm.AlarmLevel, ["alarm_type"] = alarm.AlarmType } }; var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds; _logger.LogInformation("报警确认完成:报警ID={AlarmId},用户={ConfirmUser},耗时={ElapsedMs:F1}ms", alarmId, confirmUser, elapsed); return Result.Success(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "确认报警失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "CONFIRM_ALARM_FAILED", "确认报警失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> ClearAlarmAsync(Guid alarmId, string clearUser, string? clearNote = null, CancellationToken cancellationToken = default) { try { _logger.LogInformation("清除报警:报警ID={AlarmId},用户={ClearUser}", alarmId, clearUser); var startTime = DateTime.UtcNow; if (!_activeAlarms.TryGetValue(alarmId, out var alarm)) { return Result.FailWithTrace("ALARM_NOT_FOUND", $"未找到报警:{alarmId}", string.Empty); } var previousStatus = alarm.AlarmStatus; // 更新报警状态 var updatedAlarm = alarm with { AlarmStatus = AlarmStatus.Cleared, ClearTimeUtc = startTime, ClearUser = clearUser, ClearNote = clearNote }; _activeAlarms.TryRemove(alarmId, out _); _alarmHistory.TryUpdate(alarmId, updatedAlarm, alarm); // 更新报警栈 await MoveAlarmToStackAsync(alarmId, GetStackTypeByStatus(previousStatus), AlarmStackType.Cleared, cancellationToken); // 清除恢复状态 _recoveryStatuses.TryRemove(alarmId, out _); var result = new AlarmClearResult { AlarmId = alarmId, IsCleared = true, ClearTimeUtc = startTime, ClearUser = clearUser, ClearNote = clearNote, PreviousStatus = previousStatus, NewStatus = AlarmStatus.Cleared, ResultDescription = "报警清除成功", ExtendedProperties = new Dictionary { ["alarm_level"] = alarm.AlarmLevel, ["alarm_type"] = alarm.AlarmType, ["active_duration_minutes"] = (startTime - alarm.TriggerTimeUtc).TotalMinutes } }; var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds; _logger.LogInformation("报警清除完成:报警ID={AlarmId},用户={ClearUser},耗时={ElapsedMs:F1}ms", alarmId, clearUser, elapsed); return Result.Success(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "清除报警失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "CLEAR_ALARM_FAILED", "清除报警失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task>> GetAlarmStackAsync(AlarmStackType stackType, int maxCount = 100, CancellationToken cancellationToken = default) { try { _logger.LogDebug("获取报警栈:栈类型={StackType},最大数量={MaxCount}", stackType, maxCount); if (!_alarmStacks.TryGetValue(stackType, out var stack)) { return Result.Success>(Array.Empty()); } var alarmIds = stack.ToArray().Take(maxCount).ToList(); var alarms = new List(); foreach (var alarmId in alarmIds) { if (_alarmHistory.TryGetValue(alarmId, out var alarm)) { alarms.Add(alarm); } } alarms = alarms.OrderByDescending(a => a.TriggerTimeUtc).ToList(); _logger.LogDebug("获取报警栈完成:栈类型={StackType},报警数量={AlarmCount}", stackType, alarms.Count); return Result.Success>(alarms); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取报警栈失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "GET_ALARM_STACK_FAILED", "获取报警栈失败", traceId); return Result.FailWithTrace>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task>> GetActiveAlarmsAsync(CancellationToken cancellationToken = default) { try { _logger.LogDebug("获取活跃报警"); var activeAlarms = _activeAlarms.Values .OrderByDescending(a => a.TriggerTimeUtc) .ToList(); _logger.LogDebug("获取活跃报警完成:数量={AlarmCount}", activeAlarms.Count); return Result.Success>(activeAlarms); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取活跃报警失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "GET_ACTIVE_ALARMS_FAILED", "获取活跃报警失败", traceId); return Result.FailWithTrace>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task>> GetAlarmHistoryAsync(DateTime startTime, DateTime endTime, AlarmLevel? alarmLevel = null, CancellationToken cancellationToken = default) { try { _logger.LogDebug("获取报警历史:开始时间={StartTime},结束时间={EndTime},级别={AlarmLevel}", startTime, endTime, alarmLevel); var history = _alarmHistory.Values .Where(h => h.TriggerTimeUtc >= startTime && h.TriggerTimeUtc <= endTime) .AsEnumerable(); if (alarmLevel.HasValue) { history = history.Where(h => h.AlarmLevel == alarmLevel.Value); } var result = history.OrderByDescending(h => h.TriggerTimeUtc).ToList(); _logger.LogDebug("获取报警历史完成:记录数量={Count}", result.Count); return Result.Success>(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取报警历史失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "GET_ALARM_HISTORY_FAILED", "获取报警历史失败", traceId); return Result.FailWithTrace>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> GetAlarmStatisticsAsync(DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default) { try { _logger.LogDebug("获取报警统计信息:开始时间={StartTime},结束时间={EndTime}", startTime, endTime); var history = _alarmHistory.Values .Where(h => h.TriggerTimeUtc >= startTime && h.TriggerTimeUtc <= endTime) .ToList(); var statistics = new AlarmStatistics { StartTimeUtc = startTime, EndTimeUtc = endTime, TotalAlarms = history.Count, ActiveAlarms = history.Count(h => h.AlarmStatus == AlarmStatus.Active), ConfirmedAlarms = history.Count(h => h.AlarmStatus == AlarmStatus.Confirmed), ClearedAlarms = history.Count(h => h.AlarmStatus == AlarmStatus.Cleared) }; // 按报警类型分组统计 var typeGroups = history.GroupBy(h => h.AlarmType); foreach (var group in typeGroups) { statistics.ByAlarmType[group.Key] = new AlarmTypeStatistics { AlarmType = group.Key, AlarmCount = group.Count(), Percentage = (double)group.Count() / history.Count * 100, AverageLevel = group.Average(h => (double)h.AlarmLevel) }; } // 按报警级别分组统计 var levelGroups = history.GroupBy(h => h.AlarmLevel); foreach (var group in levelGroups) { statistics.ByAlarmLevel[group.Key] = new AlarmLevelStatistics { AlarmLevel = group.Key, AlarmCount = group.Count(), Percentage = (double)group.Count() / history.Count * 100 }; } // 按报警状态分组统计 var statusGroups = history.GroupBy(h => h.AlarmStatus); foreach (var group in statusGroups) { statistics.ByAlarmStatus[group.Key] = new AlarmStatusStatistics { AlarmStatus = group.Key, AlarmCount = group.Count(), Percentage = (double)group.Count() / history.Count * 100 }; } // 按产品类型分组统计 var productTypeGroups = history.GroupBy(h => h.ProductTypeCode); foreach (var group in productTypeGroups) { statistics.ByProductType[group.Key] = new ProductTypeAlarmStatistics { ProductTypeCode = group.Key, AlarmCount = group.Count(), Percentage = (double)group.Count() / history.Count * 100, AverageLevel = group.Average(h => (double)h.AlarmLevel) }; } // 按报警源分组统计 var sourceGroups = history.GroupBy(h => h.Source); foreach (var group in sourceGroups) { statistics.ByAlarmSource[group.Key] = new AlarmSourceStatistics { AlarmSource = group.Key, AlarmCount = group.Count(), Percentage = (double)group.Count() / history.Count * 100 }; } // 重复报警统计 var duplicateAlarms = history.Where(h => h.IsDuplicate).ToList(); statistics.DuplicateAlarms = new DuplicateAlarmStatistics { DuplicateAlarmCount = duplicateAlarms.Count, DuplicatePercentage = history.Count > 0 ? (double)duplicateAlarms.Count / history.Count * 100 : 0, AverageDuplicateCount = duplicateAlarms.Any() ? duplicateAlarms.Average(h => h.DuplicateCount) : 0 }; // 平均确认和清除时间 var confirmedAlarms = history.Where(h => h.ConfirmTimeUtc.HasValue).ToList(); statistics.AverageConfirmTimeMinutes = confirmedAlarms.Any() ? confirmedAlarms.Average(h => (h.ConfirmTimeUtc!.Value - h.TriggerTimeUtc).TotalMinutes) : 0; var clearedAlarms = history.Where(h => h.ClearTimeUtc.HasValue).ToList(); statistics.AverageClearTimeMinutes = clearedAlarms.Any() ? clearedAlarms.Average(h => (h.ClearTimeUtc!.Value - h.TriggerTimeUtc).TotalMinutes) : 0; _logger.LogInformation("报警统计信息获取完成:总报警数={Total},活跃数={Active},确认数={Confirmed},清除数={Cleared}", statistics.TotalAlarms, statistics.ActiveAlarms, statistics.ConfirmedAlarms, statistics.ClearedAlarms); return Result.Success(statistics); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取报警统计信息失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "GET_ALARM_STATISTICS_FAILED", "获取报警统计信息失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> BatchConfirmAlarmsAsync(IReadOnlyList alarmIds, string confirmUser, string? confirmNote = null, CancellationToken cancellationToken = default) { try { _logger.LogInformation("批量确认报警:报警数量={AlarmCount},用户={ConfirmUser}", alarmIds.Count, confirmUser); var startTime = DateTime.UtcNow; var confirmResults = new List(); var confirmedCount = 0; var failedCount = 0; foreach (var alarmId in alarmIds) { var confirmResult = await ConfirmAlarmAsync(alarmId, confirmUser, confirmNote, cancellationToken); confirmResults.Add(confirmResult.IsSuccess ? confirmResult.Data : new AlarmConfirmResult { AlarmId = alarmId, IsConfirmed = false, ConfirmTimeUtc = DateTime.UtcNow, ConfirmUser = confirmUser, ConfirmNote = confirmNote, ResultDescription = confirmResult.Message }); if (confirmResult.IsSuccess) { confirmedCount++; } else { failedCount++; } } var elapsed = DateTime.UtcNow - startTime; var result = new BatchAlarmConfirmResult { ConfirmResults = confirmResults, TotalAlarms = alarmIds.Count, ConfirmedCount = confirmedCount, FailedCount = failedCount, ConfirmUser = confirmUser, BatchOperationTimeUtc = startTime, TotalElapsedMs = (long)elapsed.TotalMilliseconds, ResultDescription = $"批量确认完成:总数={alarmIds.Count},成功={confirmedCount},失败={failedCount}", ExtendedProperties = new Dictionary { ["success_rate"] = alarmIds.Count > 0 ? (double)confirmedCount / alarmIds.Count * 100 : 0 } }; _logger.LogInformation("批量确认报警完成:总数={Total},成功={Success},失败={Failed},耗时={ElapsedMs}ms", result.TotalAlarms, result.ConfirmedCount, result.FailedCount, result.TotalElapsedMs); return Result.Success(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "批量确认报警失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "BATCH_CONFIRM_ALARMS_FAILED", "批量确认报警失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> BatchClearAlarmsAsync(IReadOnlyList alarmIds, string clearUser, string? clearNote = null, CancellationToken cancellationToken = default) { try { _logger.LogInformation("批量清除报警:报警数量={AlarmCount},用户={ClearUser}", alarmIds.Count, clearUser); var startTime = DateTime.UtcNow; var clearResults = new List(); var clearedCount = 0; var failedCount = 0; foreach (var alarmId in alarmIds) { var clearResult = await ClearAlarmAsync(alarmId, clearUser, clearNote, cancellationToken); clearResults.Add(clearResult.IsSuccess ? clearResult.Data : new AlarmClearResult { AlarmId = alarmId, IsCleared = false, ClearTimeUtc = DateTime.UtcNow, ClearUser = clearUser, ClearNote = clearNote, ResultDescription = clearResult.Message }); if (clearResult.IsSuccess) { clearedCount++; } else { failedCount++; } } var elapsed = DateTime.UtcNow - startTime; var result = new BatchAlarmClearResult { ClearResults = clearResults, TotalAlarms = alarmIds.Count, ClearedCount = clearedCount, FailedCount = failedCount, ClearUser = clearUser, BatchOperationTimeUtc = startTime, TotalElapsedMs = (long)elapsed.TotalMilliseconds, ResultDescription = $"批量清除完成:总数={alarmIds.Count},成功={clearedCount},失败={failedCount}", ExtendedProperties = new Dictionary { ["success_rate"] = alarmIds.Count > 0 ? (double)clearedCount / alarmIds.Count * 100 : 0 } }; _logger.LogInformation("批量清除报警完成:总数={Total},成功={Success},失败={Failed},耗时={ElapsedMs}ms", result.TotalAlarms, result.ClearedCount, result.FailedCount, result.TotalElapsedMs); return Result.Success(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "批量清除报警失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "BATCH_CLEAR_ALARMS_FAILED", "批量清除报警失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> CreateAlarmRuleAsync(AlarmRule rule, CancellationToken cancellationToken = default) { try { _logger.LogInformation("创建报警规则:规则名称={RuleName},报警类型={AlarmType},报警级别={AlarmLevel}", rule.RuleName, rule.AlarmType, rule.AlarmLevel); lock (_lock) { rule.RuleId = Guid.NewGuid(); rule.CreatedAtUtc = DateTime.UtcNow; rule.UpdatedAtUtc = DateTime.UtcNow; rule.Version = "1.0"; _alarmRules[rule.RuleId] = rule; } _logger.LogInformation("报警规则创建成功:规则ID={RuleId},规则名称={RuleName}", rule.RuleId, rule.RuleName); return Result.Success(rule); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "创建报警规则失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "CREATE_ALARM_RULE_FAILED", "创建报警规则失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task UpdateAlarmRuleAsync(AlarmRule rule, CancellationToken cancellationToken = default) { try { _logger.LogInformation("更新报警规则:规则ID={RuleId},规则名称={RuleName}", rule.RuleId, rule.RuleName); lock (_lock) { if (_alarmRules.ContainsKey(rule.RuleId)) { rule.UpdatedAtUtc = DateTime.UtcNow; _alarmRules[rule.RuleId] = rule; } else { return Result.Fail("RULE_NOT_FOUND", $"未找到规则:{rule.RuleId}"); } } _logger.LogInformation("报警规则更新成功:规则ID={RuleId}", rule.RuleId); return Result.Success(); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "更新报警规则失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "UPDATE_ALARM_RULE_FAILED", "更新报警规则失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task DeleteAlarmRuleAsync(Guid ruleId, CancellationToken cancellationToken = default) { try { _logger.LogInformation("删除报警规则:规则ID={RuleId}", ruleId); lock (_lock) { if (_alarmRules.TryRemove(ruleId, out _)) { _logger.LogInformation("报警规则删除成功:规则ID={RuleId}", ruleId); return Result.Success(); } else { return Result.Fail("RULE_NOT_FOUND", $"未找到规则:{ruleId}"); } } } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "删除报警规则失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "DELETE_ALARM_RULE_FAILED", "删除报警规则失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task>> GetAlarmRulesAsync(bool? isEnabled = null, CancellationToken cancellationToken = default) { try { _logger.LogDebug("获取报警规则列表:是否启用={IsEnabled}", isEnabled); var rules = _alarmRules.Values.AsEnumerable(); if (isEnabled.HasValue) { rules = rules.Where(r => r.IsEnabled == isEnabled.Value); } var result = rules.OrderBy(r => r.Priority).ThenBy(r => r.RuleName).ToList(); _logger.LogDebug("获取报警规则列表完成:规则数量={RuleCount}", result.Count); return Result.Success>(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取报警规则列表失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "GET_ALARM_RULES_FAILED", "获取报警规则列表失败", traceId); return Result.FailWithTrace>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task>> CheckAlarmConditionsAsync(AlarmConditionCheckRequest conditionCheckRequest, CancellationToken cancellationToken = default) { try { _logger.LogDebug("检查报警条件:产品类型={ProductTypeCode},会话={SessionId}", conditionCheckRequest.ProductTypeCode, conditionCheckRequest.SessionId); var checkResults = new List(); var rules = _alarmRules.Values.Where(r => r.IsEnabled).ToList(); if (conditionCheckRequest.RuleIds?.Any() == true) { rules = rules.Where(r => conditionCheckRequest.RuleIds!.Contains(r.RuleId)).ToList(); } foreach (var rule in rules) { var checkResult = await CheckSingleAlarmConditionAsync(rule, conditionCheckRequest, cancellationToken); checkResults.Add(checkResult); } _logger.LogDebug("报警条件检查完成:规则数量={RuleCount},应触发报警数量={TriggerCount}", checkResults.Count, checkResults.Count(r => r.ShouldTriggerAlarm)); return Result.Success>(checkResults); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "检查报警条件失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "CHECK_ALARM_CONDITIONS_FAILED", "检查报警条件失败", traceId); return Result.FailWithTrace>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> GetAlarmRecoveryStatusAsync(Guid alarmId, CancellationToken cancellationToken = default) { try { _logger.LogDebug("获取报警恢复状态:报警ID={AlarmId}", alarmId); if (_recoveryStatuses.TryGetValue(alarmId, out var recoveryStatus)) { return Result.Success(recoveryStatus); } return Result.FailWithTrace("RECOVERY_STATUS_NOT_FOUND", $"未找到恢复状态:{alarmId}", string.Empty); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取报警恢复状态失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "GET_RECOVERY_STATUS_FAILED", "获取报警恢复状态失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> SetAlarmRecoveryStatusAsync(AlarmRecoveryRequest recoveryRequest, CancellationToken cancellationToken = default) { try { _logger.LogInformation("设置报警恢复状态:报警ID={AlarmId},状态={Status},用户={RecoveryUser}", recoveryRequest.AlarmId, recoveryRequest.Status, recoveryRequest.RecoveryUser); var startTime = DateTime.UtcNow; var recoveryStatus = new AlarmRecoveryStatus { AlarmId = recoveryRequest.AlarmId, Status = recoveryRequest.Status, RecoveryTimeUtc = recoveryRequest.Status == RecoveryStatus.Recovered ? startTime : null, RecoveryReason = recoveryRequest.RecoveryReason, RecoveryUser = recoveryRequest.RecoveryUser, RecoveryCheckCount = 0, LastCheckTimeUtc = startTime, NextCheckTimeUtc = startTime.AddSeconds(recoveryRequest.RecoveryCheckIntervalSeconds), ExtendedProperties = new Dictionary(recoveryRequest.ExtendedProperties) }; _recoveryStatuses.TryAdd(recoveryRequest.AlarmId, recoveryStatus); var result = new AlarmRecoveryResult { AlarmId = recoveryRequest.AlarmId, IsSuccess = true, Status = recoveryRequest.Status, SetTimeUtc = startTime, SetUser = recoveryRequest.RecoveryUser, ResultDescription = "恢复状态设置成功", ExtendedProperties = new Dictionary { ["is_auto_recovery"] = recoveryRequest.IsAutoRecovery, ["check_interval_seconds"] = recoveryRequest.RecoveryCheckIntervalSeconds } }; _logger.LogInformation("报警恢复状态设置完成:报警ID={AlarmId},状态={Status}", recoveryRequest.AlarmId, recoveryRequest.Status); return Result.Success(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "设置报警恢复状态失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "SET_RECOVERY_STATUS_FAILED", "设置报警恢复状态失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } #region 私有方法 /// /// 初始化默认报警规则。 /// private void InitializeDefaultAlarmRules() { var defaultRules = new List { new() { RuleId = Guid.NewGuid(), RuleName = "系统错误报警", RuleDescription = "系统发生错误时触发", AlarmType = AlarmType.System, AlarmLevel = AlarmLevel.Error, TriggerCondition = "system_error", TriggerThreshold = 1.0, ComparisonOperator = ComparisonOperator.GreaterThanOrEqual, IsEnabled = true, RequiresConfirmation = true, AutoClear = false, Priority = 1, CreatedAtUtc = DateTime.UtcNow, UpdatedAtUtc = DateTime.UtcNow, Version = "1.0" }, new() { RuleId = Guid.NewGuid(), RuleName = "设备故障报警", RuleDescription = "设备发生故障时触发", AlarmType = AlarmType.Equipment, AlarmLevel = AlarmLevel.Critical, TriggerCondition = "equipment_failure", TriggerThreshold = 1.0, ComparisonOperator = ComparisonOperator.GreaterThanOrEqual, IsEnabled = true, RequiresConfirmation = true, AutoClear = false, Priority = 1, CreatedAtUtc = DateTime.UtcNow, UpdatedAtUtc = DateTime.UtcNow, Version = "1.0" }, new() { RuleId = Guid.NewGuid(), RuleName = "质量异常报警", RuleDescription = "检测到质量异常时触发", AlarmType = AlarmType.Quality, AlarmLevel = AlarmLevel.Warning, TriggerCondition = "quality_anomaly", TriggerThreshold = 0.8, ComparisonOperator = ComparisonOperator.GreaterThanOrEqual, IsEnabled = true, RequiresConfirmation = true, AutoClear = true, AutoClearAfterSeconds = 300, Priority = 2, CreatedAtUtc = DateTime.UtcNow, UpdatedAtUtc = DateTime.UtcNow, Version = "1.0" }, new() { RuleId = Guid.NewGuid(), RuleName = "性能下降报警", RuleDescription = "系统性能下降时触发", AlarmType = AlarmType.Performance, AlarmLevel = AlarmLevel.Info, TriggerCondition = "performance_degradation", TriggerThreshold = 0.7, ComparisonOperator = ComparisonOperator.LessThan, IsEnabled = true, RequiresConfirmation = false, AutoClear = true, AutoClearAfterSeconds = 180, Priority = 3, CreatedAtUtc = DateTime.UtcNow, UpdatedAtUtc = DateTime.UtcNow, Version = "1.0" } }; foreach (var rule in defaultRules) { _alarmRules[rule.RuleId] = rule; } } /// /// 检查重复报警。 /// private async Task CheckDuplicateAlarmAsync(AlarmRequest request, CancellationToken cancellationToken = default) { await Task.Delay(1, cancellationToken); var duplicateAlarms = _activeAlarms.Values .Where(a => a.AlarmType == request.AlarmType && a.AlarmLevel == request.AlarmLevel && a.Title == request.Title && a.ProductTypeCode == request.ProductTypeCode && a.SessionId == request.SessionId && a.AlarmStatus == AlarmStatus.Active) .ToList(); return duplicateAlarms.FirstOrDefault(); } /// /// 更新重复报警。 /// private async Task UpdateDuplicateAlarmAsync(Alarm existingAlarm, AlarmRequest request, CancellationToken cancellationToken = default) { await Task.Run(() => { var updatedAlarm = existingAlarm with { DuplicateCount = existingAlarm.DuplicateCount + 1, Description = $"{existingAlarm.Description}\n重复报警 #{existingAlarm.DuplicateCount + 1}: {request.Description}", TriggerTimeUtc = DateTime.UtcNow }; _activeAlarms.TryUpdate(existingAlarm.AlarmId, updatedAlarm, existingAlarm); _alarmHistory.TryUpdate(existingAlarm.AlarmId, updatedAlarm, existingAlarm); }, cancellationToken); } /// /// 添加到报警栈。 /// private async Task AddToAlarmStackAsync(Alarm alarm, AlarmStackType stackType, CancellationToken cancellationToken = default) { await Task.Run(() => { if (_alarmStacks.TryGetValue(stackType, out var stack)) { stack.Enqueue(alarm.AlarmId); // 限制栈大小 while (stack.Count > _options.MaxAlarmStackSize) { stack.TryDequeue(out _); } } // 更新栈位置 var stackPosition = GetAlarmStackPosition(alarm.AlarmId, stackType); var updatedAlarm = alarm with { StackPosition = stackPosition }; _activeAlarms.TryUpdate(alarm.AlarmId, updatedAlarm, alarm); _alarmHistory.TryUpdate(alarm.AlarmId, updatedAlarm, alarm); }, cancellationToken); } /// /// 移动报警到另一个栈。 /// private async Task MoveAlarmToStackAsync(Guid alarmId, AlarmStackType fromStackType, AlarmStackType toStackType, CancellationToken cancellationToken = default) { await Task.Run(() => { // 从原栈中移除 if (_alarmStacks.TryGetValue(fromStackType, out var fromStack)) { var newFromStack = new ConcurrentQueue(); while (fromStack.TryDequeue(out var id)) { if (id != alarmId) { newFromStack.Enqueue(id); } } _alarmStacks[fromStackType] = newFromStack; } // 添加到目标栈 if (_alarmStacks.TryGetValue(toStackType, out var toStack)) { toStack.Enqueue(alarmId); // 限制栈大小 while (toStack.Count > _options.MaxAlarmStackSize) { toStack.TryDequeue(out _); } } }, cancellationToken); } /// /// 获取报警栈位置。 /// private int GetAlarmStackPosition(Guid alarmId, AlarmStackType stackType) { if (_alarmStacks.TryGetValue(stackType, out var stack)) { var stackArray = stack.ToArray(); for (int i = 0; i < stackArray.Length; i++) { if (stackArray[i] == alarmId) { return i + 1; } } } return 0; } /// /// 根据状态获取栈类型。 /// private AlarmStackType GetStackTypeByStatus(AlarmStatus status) { return status switch { AlarmStatus.Active => AlarmStackType.Active, AlarmStatus.Confirmed => AlarmStackType.Confirmed, AlarmStatus.Cleared => AlarmStackType.Cleared, _ => AlarmStackType.History }; } /// /// 检查单个报警条件。 /// private async Task CheckSingleAlarmConditionAsync(AlarmRule rule, AlarmConditionCheckRequest request, CancellationToken cancellationToken = default) { await Task.Delay(1, cancellationToken); // 简化处理:基于规则类型和阈值进行条件检查 var actualValue = GetActualValueForCondition(rule.TriggerCondition, request); var shouldTrigger = EvaluateCondition(actualValue, rule.TriggerThreshold, rule.ComparisonOperator); return new AlarmConditionCheckResult { RuleId = rule.RuleId, RuleName = rule.RuleName, ShouldTriggerAlarm = shouldTrigger, ActualValue = actualValue, Threshold = rule.TriggerThreshold, CheckTimeUtc = request.CheckTimeUtc, CheckDetails = shouldTrigger ? $"条件满足:实际值{actualValue:F2}{GetComparisonDescription(rule.ComparisonOperator)}{rule.TriggerThreshold:F2}" : $"条件不满足:实际值{actualValue:F2}{GetComparisonDescription(rule.ComparisonOperator)}{rule.TriggerThreshold:F2}", ExtendedProperties = new Dictionary { ["alarm_type"] = rule.AlarmType, ["alarm_level"] = rule.AlarmLevel } }; } /// /// 获取条件检查的实际值。 /// private double GetActualValueForCondition(string condition, AlarmConditionCheckRequest request) { // 简化处理:基于条件类型返回模拟值 return condition switch { "system_error" => 1.0, "equipment_failure" => 0.5, "quality_anomaly" => 0.6, "performance_degradation" => 0.8, _ => 0.0 }; } /// /// 评估条件。 /// private bool EvaluateCondition(double actualValue, double threshold, ComparisonOperator comparisonOperator) { return comparisonOperator switch { ComparisonOperator.Equal => Math.Abs(actualValue - threshold) < 0.001, ComparisonOperator.NotEqual => Math.Abs(actualValue - threshold) >= 0.001, ComparisonOperator.GreaterThan => actualValue > threshold, ComparisonOperator.GreaterThanOrEqual => actualValue >= threshold, ComparisonOperator.LessThan => actualValue < threshold, ComparisonOperator.LessThanOrEqual => actualValue <= threshold, _ => false }; } /// /// 获取比较描述。 /// private string GetComparisonDescription(ComparisonOperator comparisonOperator) { return comparisonOperator switch { ComparisonOperator.Equal => "==", ComparisonOperator.NotEqual => "!=", ComparisonOperator.GreaterThan => ">", ComparisonOperator.GreaterThanOrEqual => ">=", ComparisonOperator.LessThan => "<", ComparisonOperator.LessThanOrEqual => "<=", _ => "?" }; } /// /// 安排自动清除。 /// private void ScheduleAutoClear(Guid alarmId, int delaySeconds) { Task.Delay(TimeSpan.FromSeconds(delaySeconds)).ContinueWith(async _ => { if (_activeAlarms.TryGetValue(alarmId, out var alarm) && alarm.AutoClear) { await ClearAlarmAsync(alarmId, "system", "自动清除"); _logger.LogInformation("自动清除报警:报警ID={AlarmId}", alarmId); } }); } /// /// 检查自动清除报警。 /// private async void CheckAutoClearAlarms(object? state) { try { var now = DateTime.UtcNow; var alarmsToClear = _activeAlarms.Values .Where(a => a.AutoClear && a.AutoClearAfterSeconds > 0 && (now - a.TriggerTimeUtc).TotalSeconds >= a.AutoClearAfterSeconds) .ToList(); foreach (var alarm in alarmsToClear) { await ClearAlarmAsync(alarm.AlarmId, "system", "自动清除"); _logger.LogInformation("定时自动清除报警:报警ID={AlarmId}", alarm.AlarmId); } } catch (Exception ex) { _logger.LogError(ex, "检查自动清除报警失败"); } } /// /// 释放资源。 /// public void Dispose() { try { _autoClearTimer?.Dispose(); _activeAlarms.Clear(); _alarmHistory.Clear(); _alarmRules.Clear(); _alarmStacks.Clear(); _recoveryStatuses.Clear(); _logger.LogInformation("异常报警系统服务已释放"); } catch (Exception ex) { _logger.LogError(ex, "释放异常报警系统服务资源时发生错误"); } } #endregion } #endif #endif