Files
OrpaonVision/OrpaonVision.SiteApp/Runtime/Services/AlarmSystemService.cs
2026-04-12 22:34:46 +08:00

2119 lines
83 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
/// <summary>
/// 异常报警系统实现,支持完整的报警生命周期。
/// </summary>
public sealed class AlarmSystemService : IAlarmSystemService
{
private readonly ILogger<AlarmSystemService> _logger;
private readonly RuntimeOptions _options;
private readonly IRuleEngineService _ruleEngineService;
private readonly IRuntimeStateMachineService _stateMachineService;
private readonly ConcurrentDictionary<Guid, Alarm> _activeAlarms = new();
private readonly ConcurrentDictionary<Guid, Alarm> _alarmHistory = new();
private readonly ConcurrentDictionary<Guid, AlarmLifecycle> _alarmLifecycles = new();
private readonly ConcurrentDictionary<AlarmStackType, ConcurrentQueue<Guid>> _alarmStacks = new();
private readonly object _lock = new();
private readonly Timer _autoClearTimer;
public AlarmSystemService(
ILogger<AlarmSystemService> logger,
IOptions<RuntimeOptions> options,
IRuleEngineService ruleEngineService,
IRuntimeStateMachineService stateMachineService)
{
_logger = logger;
_options = options.Value;
_ruleEngineService = ruleEngineService;
_stateMachineService = stateMachineService;
// 初始化报警栈
foreach (var stackType in Enum.GetValues<AlarmStackType>())
{
_alarmStacks[stackType] = new ConcurrentQueue<Guid>();
}
// 启动自动清除定时器
_autoClearTimer = new Timer(CheckAutoClearAlarms, null,
TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
_logger.LogInformation("异常报警系统服务已初始化");
}
public async Task<Result<AlarmResult>> 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<string, object>(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<string, object>
{
["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<AlarmResult>.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "触发报警失败。TraceId: {TraceId}", traceId);
return Result<AlarmResult>.FailWithTrace("TRIGGER_ALARM_FAILED", "触发报警失败", traceId);
}
}
public async Task<Result<AlarmConfirmResult>> 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<AlarmConfirmResult>.Fail("ALARM_NOT_FOUND", "报警不存在或已清除");
}
var previousStatus = alarm.AlarmStatus;
if (previousStatus != AlarmStatus.Active)
{
return Result<AlarmConfirmResult>.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<AlarmConfirmResult>.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "确认报警失败。TraceId: {TraceId}", traceId);
return Result<AlarmConfirmResult>.FailWithTrace("CONFIRM_ALARM_FAILED", "确认报警失败", traceId);
}
}
public async Task<Result<AlarmClearResult>> 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<AlarmClearResult>.Fail("ALARM_NOT_FOUND", "报警不存在或已清除");
}
var previousStatus = alarm.AlarmStatus;
if (previousStatus == AlarmStatus.Cleared)
{
return Result<AlarmClearResult>.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<AlarmClearResult>.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "清除报警失败。TraceId: {TraceId}", traceId);
return Result<AlarmClearResult>.FailWithTrace("CLEAR_ALARM_FAILED", "清除报警失败", traceId);
}
}
public Task<Result<IReadOnlyList<Alarm>>> GetAlarmStackAsync(AlarmStackType stackType, int maxCount = 100, CancellationToken cancellationToken = default)
{
IReadOnlyList<Alarm> alarms = Array.Empty<Alarm>();
return Task.FromResult(Result<IReadOnlyList<Alarm>>.Success(alarms));
}
public Task<Result<IReadOnlyList<Alarm>>> GetActiveAlarmsAsync(CancellationToken cancellationToken = default)
{
IReadOnlyList<Alarm> alarms = Array.Empty<Alarm>();
return Task.FromResult(Result<IReadOnlyList<Alarm>>.Success(alarms));
}
public Task<Result<IReadOnlyList<Alarm>>> GetAlarmHistoryAsync(DateTime startTime, DateTime endTime, AlarmLevel? alarmLevel = null, CancellationToken cancellationToken = default)
{
IReadOnlyList<Alarm> alarms = Array.Empty<Alarm>();
return Task.FromResult(Result<IReadOnlyList<Alarm>>.Success(alarms));
}
public Task<Result<AlarmStatistics>> GetAlarmStatisticsAsync(DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default)
{
var statistics = new AlarmStatistics();
return Task.FromResult(Result<AlarmStatistics>.Success(statistics));
}
public Task<Result<BatchAlarmConfirmResult>> BatchConfirmAlarmsAsync(IReadOnlyList<Guid> alarmIds, string confirmUser, string? confirmNote = null, CancellationToken cancellationToken = default)
{
var result = new BatchAlarmConfirmResult
{
ConfirmResults = Array.Empty<AlarmConfirmResult>(),
TotalAlarms = alarmIds.Count,
ConfirmedCount = alarmIds.Count,
FailedCount = 0,
ConfirmUser = confirmUser,
BatchOperationTimeUtc = DateTime.UtcNow,
TotalElapsedMs = 0,
ResultDescription = "最小实现:批量确认成功"
};
return Task.FromResult(Result<BatchAlarmConfirmResult>.Success(result));
}
public Task<Result<BatchAlarmClearResult>> BatchClearAlarmsAsync(IReadOnlyList<Guid> alarmIds, string clearUser, string? clearNote = null, CancellationToken cancellationToken = default)
{
var result = new BatchAlarmClearResult
{
ClearResults = Array.Empty<AlarmClearResult>(),
TotalAlarms = alarmIds.Count,
ClearedCount = alarmIds.Count,
FailedCount = 0,
ClearUser = clearUser,
BatchOperationTimeUtc = DateTime.UtcNow,
TotalElapsedMs = 0,
ResultDescription = "最小实现:批量清除成功"
};
return Task.FromResult(Result<BatchAlarmClearResult>.Success(result));
}
public Task<Result<AlarmRule>> CreateAlarmRuleAsync(AlarmRule rule, CancellationToken cancellationToken = default)
{
return Task.FromResult(Result<AlarmRule>.Success(rule));
}
public Task<Result> UpdateAlarmRuleAsync(AlarmRule rule, CancellationToken cancellationToken = default)
{
return Task.FromResult(Result.Success());
}
public Task<Result> DeleteAlarmRuleAsync(Guid ruleId, CancellationToken cancellationToken = default)
{
return Task.FromResult(Result.Success());
}
public Task<Result<IReadOnlyList<AlarmRule>>> GetAlarmRulesAsync(bool? isEnabled = null, CancellationToken cancellationToken = default)
{
IReadOnlyList<AlarmRule> rules = Array.Empty<AlarmRule>();
return Task.FromResult(Result<IReadOnlyList<AlarmRule>>.Success(rules));
}
public Task<Result<IReadOnlyList<AlarmConditionCheckResult>>> CheckAlarmConditionsAsync(AlarmConditionCheckRequest conditionCheckRequest, CancellationToken cancellationToken = default)
{
IReadOnlyList<AlarmConditionCheckResult> results = Array.Empty<AlarmConditionCheckResult>();
return Task.FromResult(Result<IReadOnlyList<AlarmConditionCheckResult>>.Success(results));
}
public Task<Result<AlarmRecoveryStatus>> 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<AlarmRecoveryStatus>.Success(status));
}
public async Task<Result<AlarmRecoveryResult>> 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<AlarmRecoveryResult>.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<AlarmRecoveryResult>.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "设置报警恢复状态失败。TraceId: {TraceId}", traceId);
return Result<AlarmRecoveryResult>.FailWithTrace("SET_RECOVERY_STATUS_FAILED", "设置报警恢复状态失败", traceId);
}
}
/// <summary>
/// 获取报警生命周期。
/// </summary>
public async Task<Result<AlarmLifecycle>> GetAlarmLifecycleAsync(Guid alarmId, CancellationToken cancellationToken = default)
{
try
{
if (_alarmLifecycles.TryGetValue(alarmId, out var lifecycle))
{
return Result<AlarmLifecycle>.Success(lifecycle);
}
return Result<AlarmLifecycle>.Fail("ALARM_LIFECYCLE_NOT_FOUND", "报警生命周期记录不存在");
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取报警生命周期失败。TraceId: {TraceId}", traceId);
return Result<AlarmLifecycle>.FailWithTrace("GET_ALARM_LIFECYCLE_FAILED", "获取报警生命周期失败", traceId);
}
}
/// <summary>
/// 获取报警完整生命周期历史。
/// </summary>
public async Task<Result<IReadOnlyList<AlarmLifecycle>>> 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<IReadOnlyList<AlarmLifecycle>>.Success(lifecycles);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取报警生命周期历史失败。TraceId: {TraceId}", traceId);
return Result<IReadOnlyList<AlarmLifecycle>>.FailWithTrace("GET_LIFECYCLE_HISTORY_FAILED", "获取报警生命周期历史失败", traceId);
}
}
#region
/// <summary>
/// 从报警请求中提取规则编号。
/// </summary>
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;
}
/// <summary>
/// 处理严重报警。
/// </summary>
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);
}
}
/// <summary>
/// 检查报警是否可以自动恢复。
/// </summary>
private async Task<bool> 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;
}
}
/// <summary>
/// 检查规则失败情况。
/// </summary>
private async Task<bool> CheckRuleFailuresAsync(Guid sessionId, int layer, CancellationToken cancellationToken)
{
try
{
// 这里应该调用规则引擎检查当前会话和层级的规则执行情况
// 暂时返回false表示没有规则失败
return false;
}
catch (Exception ex)
{
_logger.LogError(ex, "检查规则失败情况异常会话ID={SessionId},层级={Layer}", sessionId, layer);
return false;
}
}
/// <summary>
/// 自动检查报警恢复状态。
/// </summary>
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<Guid>();
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, "自动清除报警检查失败");
}
}
/// <summary>
/// 释放资源。
/// </summary>
public void Dispose()
{
try
{
_autoClearTimer?.Dispose();
_activeAlarms.Clear();
_alarmHistory.Clear();
_alarmLifecycles.Clear();
_alarmStacks.Clear();
_logger.LogInformation("异常报警系统服务已释放");
}
catch (Exception ex)
{
_logger.LogError(ex, "释放异常报警系统服务资源时发生错误");
}
}
}
#region
/// <summary>
/// 报警生命周期记录。
/// </summary>
public sealed class AlarmLifecycle
{
/// <summary>
/// 报警ID。
/// </summary>
public Guid AlarmId { get; set; }
/// <summary>
/// 会话ID。
/// </summary>
public Guid SessionId { get; set; }
/// <summary>
/// 层级。
/// </summary>
public int Layer { get; set; }
/// <summary>
/// 规则编号。
/// </summary>
public string RuleNumber { get; set; } = string.Empty;
/// <summary>
/// 当前状态。
/// </summary>
public AlarmStatus CurrentStatus { get; set; }
/// <summary>
/// 触发时间。
/// </summary>
public DateTime TriggerTimeUtc { get; set; }
/// <summary>
/// 触发时的状态机状态。
/// </summary>
public string TriggerState { get; set; } = string.Empty;
/// <summary>
/// 触发时的层级。
/// </summary>
public int TriggerLayer { get; set; }
/// <summary>
/// 确认时间。
/// </summary>
public DateTime? ConfirmTimeUtc { get; set; }
/// <summary>
/// 确认用户。
/// </summary>
public string? ConfirmUser { get; set; }
/// <summary>
/// 清除时间。
/// </summary>
public DateTime? ClearTimeUtc { get; set; }
/// <summary>
/// 清除用户。
/// </summary>
public string? ClearUser { get; set; }
/// <summary>
/// 恢复时间。
/// </summary>
public DateTime? RecoveryTimeUtc { get; set; }
/// <summary>
/// 恢复用户。
/// </summary>
public string? RecoveryUser { get; set; }
/// <summary>
/// 恢复状态。
/// </summary>
public RecoveryStatus RecoveryStatus { get; set; }
/// <summary>
/// 恢复原因。
/// </summary>
public string? RecoveryReason { get; set; }
/// <summary>
/// 生命周期持续时间(毫秒)。
/// </summary>
public long LifecycleDurationMs =>
RecoveryTimeUtc?.Subtract(TriggerTimeUtc).TotalMilliseconds ??
ClearTimeUtc?.Subtract(TriggerTimeUtc).TotalMilliseconds ??
DateTime.UtcNow.Subtract(TriggerTimeUtc).TotalMilliseconds;
/// <summary>
/// 状态转换历史。
/// </summary>
public List<AlarmStatusTransition> StatusTransitions { get; set; } = new();
/// <summary>
/// 扩展属性。
/// </summary>
public Dictionary<string, object> ExtendedProperties { get; set; } = new();
}
/// <summary>
/// 报警状态转换记录。
/// </summary>
public sealed class AlarmStatusTransition
{
/// <summary>
/// 转换时间。
/// </summary>
public DateTime TransitionTimeUtc { get; set; }
/// <summary>
/// 前一个状态。
/// </summary>
public AlarmStatus PreviousStatus { get; set; }
/// <summary>
/// 新状态。
/// </summary>
public AlarmStatus NewStatus { get; set; }
/// <summary>
/// 操作用户。
/// </summary>
public string? OperatorUser { get; set; }
/// <summary>
/// 转换原因。
/// </summary>
public string? Reason { get; set; }
/// <summary>
/// 转换类型(手动/自动)。
/// </summary>
public AlarmTransitionType TransitionType { get; set; }
}
/// <summary>
/// 报警转换类型。
/// </summary>
public enum AlarmTransitionType
{
/// <summary>
/// 手动转换。
/// </summary>
Manual,
/// <summary>
/// 自动转换。
/// </summary>
Automatic,
/// <summary>
/// 系统转换。
/// </summary>
System
}
#endregion
#if false
/// <summary>
/// 异常报警系统服务实现。
/// </summary>
public sealed class AlarmSystemService : IAlarmSystemService
{
private readonly ILogger<AlarmSystemService> _logger;
private readonly RuntimeOptions _options;
private readonly ConcurrentDictionary<Guid, Alarm> _activeAlarms = new();
private readonly ConcurrentDictionary<Guid, Alarm> _alarmHistory = new();
private readonly ConcurrentDictionary<Guid, AlarmRule> _alarmRules = new();
private readonly ConcurrentDictionary<AlarmStackType, ConcurrentQueue<Guid>> _alarmStacks = new();
private readonly ConcurrentDictionary<Guid, AlarmRecoveryStatus> _recoveryStatuses = new();
private readonly object _lock = new();
private readonly Timer _autoClearTimer;
/// <summary>
/// 构造函数。
/// </summary>
public AlarmSystemService(ILogger<AlarmSystemService> logger, IOptions<RuntimeOptions> options)
{
_logger = logger;
_options = options.Value;
// 初始化报警栈
foreach (var stackType in Enum.GetValues<AlarmStackType>())
{
_alarmStacks[stackType] = new ConcurrentQueue<Guid>();
}
// 初始化默认报警规则
InitializeDefaultAlarmRules();
// 启动自动清除定时器
_autoClearTimer = new Timer(CheckAutoClearAlarms, null,
TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
_logger.LogInformation("异常报警系统服务已初始化");
}
/// <inheritdoc />
public async Task<Result<AlarmResult>> 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<string, object>
{
["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<string, object>(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<string, object>
{
["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<AlarmResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<AlarmConfirmResult>> 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<AlarmConfirmResult>("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<string, object>
{
["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<AlarmConfirmResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<AlarmClearResult>> 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<AlarmClearResult>("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<string, object>
{
["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<AlarmClearResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<IReadOnlyList<Alarm>>> 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<IReadOnlyList<Alarm>>(Array.Empty<Alarm>());
}
var alarmIds = stack.ToArray().Take(maxCount).ToList();
var alarms = new List<Alarm>();
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<IReadOnlyList<Alarm>>(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<IReadOnlyList<Alarm>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<IReadOnlyList<Alarm>>> GetActiveAlarmsAsync(CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("获取活跃报警");
var activeAlarms = _activeAlarms.Values
.OrderByDescending(a => a.TriggerTimeUtc)
.ToList();
_logger.LogDebug("获取活跃报警完成:数量={AlarmCount}", activeAlarms.Count);
return Result.Success<IReadOnlyList<Alarm>>(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<IReadOnlyList<Alarm>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<IReadOnlyList<Alarm>>> 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<IReadOnlyList<Alarm>>(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<IReadOnlyList<Alarm>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<AlarmStatistics>> 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<AlarmStatistics>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<BatchAlarmConfirmResult>> BatchConfirmAlarmsAsync(IReadOnlyList<Guid> 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<AlarmConfirmResult>();
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<string, object>
{
["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<BatchAlarmConfirmResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<BatchAlarmClearResult>> BatchClearAlarmsAsync(IReadOnlyList<Guid> 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<AlarmClearResult>();
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<string, object>
{
["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<BatchAlarmClearResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<AlarmRule>> 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<AlarmRule>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result> 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());
}
}
/// <inheritdoc />
public async Task<Result> 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());
}
}
/// <inheritdoc />
public async Task<Result<IReadOnlyList<AlarmRule>>> 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<IReadOnlyList<AlarmRule>>(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<IReadOnlyList<AlarmRule>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<IReadOnlyList<AlarmConditionCheckResult>>> CheckAlarmConditionsAsync(AlarmConditionCheckRequest conditionCheckRequest, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("检查报警条件:产品类型={ProductTypeCode},会话={SessionId}",
conditionCheckRequest.ProductTypeCode, conditionCheckRequest.SessionId);
var checkResults = new List<AlarmConditionCheckResult>();
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<IReadOnlyList<AlarmConditionCheckResult>>(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<IReadOnlyList<AlarmConditionCheckResult>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<AlarmRecoveryStatus>> 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<AlarmRecoveryStatus>("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<AlarmRecoveryStatus>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<AlarmRecoveryResult>> 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<string, object>(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<string, object>
{
["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<AlarmRecoveryResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
#region
/// <summary>
/// 初始化默认报警规则。
/// </summary>
private void InitializeDefaultAlarmRules()
{
var defaultRules = new List<AlarmRule>
{
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;
}
}
/// <summary>
/// 检查重复报警。
/// </summary>
private async Task<Alarm?> 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();
}
/// <summary>
/// 更新重复报警。
/// </summary>
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);
}
/// <summary>
/// 添加到报警栈。
/// </summary>
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);
}
/// <summary>
/// 移动报警到另一个栈。
/// </summary>
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<Guid>();
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);
}
/// <summary>
/// 获取报警栈位置。
/// </summary>
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;
}
/// <summary>
/// 根据状态获取栈类型。
/// </summary>
private AlarmStackType GetStackTypeByStatus(AlarmStatus status)
{
return status switch
{
AlarmStatus.Active => AlarmStackType.Active,
AlarmStatus.Confirmed => AlarmStackType.Confirmed,
AlarmStatus.Cleared => AlarmStackType.Cleared,
_ => AlarmStackType.History
};
}
/// <summary>
/// 检查单个报警条件。
/// </summary>
private async Task<AlarmConditionCheckResult> 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<string, object>
{
["alarm_type"] = rule.AlarmType,
["alarm_level"] = rule.AlarmLevel
}
};
}
/// <summary>
/// 获取条件检查的实际值。
/// </summary>
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
};
}
/// <summary>
/// 评估条件。
/// </summary>
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
};
}
/// <summary>
/// 获取比较描述。
/// </summary>
private string GetComparisonDescription(ComparisonOperator comparisonOperator)
{
return comparisonOperator switch
{
ComparisonOperator.Equal => "==",
ComparisonOperator.NotEqual => "!=",
ComparisonOperator.GreaterThan => ">",
ComparisonOperator.GreaterThanOrEqual => ">=",
ComparisonOperator.LessThan => "<",
ComparisonOperator.LessThanOrEqual => "<=",
_ => "?"
};
}
/// <summary>
/// 安排自动清除。
/// </summary>
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);
}
});
}
/// <summary>
/// 检查自动清除报警。
/// </summary>
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, "检查自动清除报警失败");
}
}
/// <summary>
/// 释放资源。
/// </summary>
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