#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