|
|
|
@ -0,0 +1,401 @@
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
using Dapper;
|
|
|
|
|
|
|
|
using MySqlConnector;
|
|
|
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
|
|
|
using CncModels.Entity;
|
|
|
|
|
|
|
|
using log4net;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace CncCollector.Core
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// 采集分析引擎。
|
|
|
|
|
|
|
|
/// 在每次采集周期后,对比每台机床的当前数据与上一次采集数据,
|
|
|
|
|
|
|
|
/// 生成分析记录(log_collect_analysis)和周期汇总(log_collect_cycle)。
|
|
|
|
|
|
|
|
/// 异常类分析自动写入告警表(cnc_alert)。
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
public class AnalysisEngine
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
private static readonly ILog _log = LogManager.GetLogger(typeof(AnalysisEngine));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>业务库连接字符串(写告警用)</summary>
|
|
|
|
|
|
|
|
private readonly string _businessConnStr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>日志库连接字符串(写分析/周期表用)</summary>
|
|
|
|
|
|
|
|
private readonly string _logConnStr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>内存缓存:machineId → 上一次采集状态快照</summary>
|
|
|
|
|
|
|
|
private readonly ConcurrentDictionary<int, MachineSnapshot> _lastSnapshot = new ConcurrentDictionary<int, MachineSnapshot>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// 采集缓存快照(每台机床的上一次状态)
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
public class MachineSnapshot
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
public string ProgramName { get; set; }
|
|
|
|
|
|
|
|
public decimal? PartCount { get; set; }
|
|
|
|
|
|
|
|
public string DeviceStatus { get; set; }
|
|
|
|
|
|
|
|
public DateTime CollectTime { get; set; }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// 初始化分析引擎
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
/// <param name="businessConnStr">业务库连接字符串</param>
|
|
|
|
|
|
|
|
/// <param name="logConnStr">日志库连接字符串</param>
|
|
|
|
|
|
|
|
public AnalysisEngine(string businessConnStr, string logConnStr)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
_businessConnStr = businessConnStr ?? throw new ArgumentNullException(nameof(businessConnStr));
|
|
|
|
|
|
|
|
_logConnStr = logConnStr ?? throw new ArgumentNullException(nameof(logConnStr));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// 分析一次采集周期的所有设备数据,写入分析记录和周期汇总。
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
/// <param name="rawLogId">本次原始日志ID(log_collect_raw.id)</param>
|
|
|
|
|
|
|
|
/// <param name="collectAddressId">采集地址ID</param>
|
|
|
|
|
|
|
|
/// <param name="addressName">采集地址名称</param>
|
|
|
|
|
|
|
|
/// <param name="records">本次采集的结构化记录列表</param>
|
|
|
|
|
|
|
|
/// <param name="machineDict">device_code → Machine 的查找字典</param>
|
|
|
|
|
|
|
|
/// <param name="cycleStartTime">周期开始时间</param>
|
|
|
|
|
|
|
|
/// <param name="durationMs">本次采集耗时(毫秒)</param>
|
|
|
|
|
|
|
|
public void AnalyzeAndRecord(long rawLogId, int collectAddressId, string addressName,
|
|
|
|
|
|
|
|
List<CollectRecord> records, Dictionary<string, Machine> machineDict,
|
|
|
|
|
|
|
|
DateTime cycleStartTime, long durationMs)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (records == null || records.Count == 0) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
var analysisTime = DateTime.Now;
|
|
|
|
|
|
|
|
var hasAnomaly = false;
|
|
|
|
|
|
|
|
var changeDistribution = new Dictionary<string, int>();
|
|
|
|
|
|
|
|
int successCount = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建 machineId → Machine 查找字典
|
|
|
|
|
|
|
|
var machineById = new Dictionary<int, Machine>();
|
|
|
|
|
|
|
|
foreach (var m in machineDict.Values)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
machineById[m.Id] = m;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 逐条分析
|
|
|
|
|
|
|
|
foreach (var rec in records)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 获取机床信息
|
|
|
|
|
|
|
|
Machine machine = null;
|
|
|
|
|
|
|
|
machineById.TryGetValue(rec.MachineId, out machine);
|
|
|
|
|
|
|
|
string machineName = machine?.Name ?? ("机床" + rec.MachineId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 当前值
|
|
|
|
|
|
|
|
string currentProgram = rec.ProgramName;
|
|
|
|
|
|
|
|
decimal? currentPartCount = rec.PartCount;
|
|
|
|
|
|
|
|
string currentStatus = rec.DeviceStatus;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取上次快照
|
|
|
|
|
|
|
|
MachineSnapshot prev;
|
|
|
|
|
|
|
|
_lastSnapshot.TryGetValue(rec.MachineId, out prev);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算分析类型和摘要
|
|
|
|
|
|
|
|
string analysisType;
|
|
|
|
|
|
|
|
string summary;
|
|
|
|
|
|
|
|
bool needAlert = false;
|
|
|
|
|
|
|
|
string alertType = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DetermineAnalysis(prev, currentProgram, currentPartCount, currentStatus,
|
|
|
|
|
|
|
|
machineName, out analysisType, out summary, out needAlert, out alertType);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算变化量
|
|
|
|
|
|
|
|
decimal? partCountDelta = null;
|
|
|
|
|
|
|
|
if (currentPartCount.HasValue && prev != null && prev.PartCount.HasValue)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
partCountDelta = currentPartCount.Value - prev.PartCount.Value;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建分析明细JSON
|
|
|
|
|
|
|
|
var detail = new
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
previous = prev != null ? new
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
program = prev.ProgramName,
|
|
|
|
|
|
|
|
partCount = prev.PartCount,
|
|
|
|
|
|
|
|
status = prev.DeviceStatus
|
|
|
|
|
|
|
|
} : null,
|
|
|
|
|
|
|
|
current = new
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
program = currentProgram,
|
|
|
|
|
|
|
|
partCount = currentPartCount,
|
|
|
|
|
|
|
|
status = currentStatus
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
delta = new { partCount = partCountDelta },
|
|
|
|
|
|
|
|
collectTime = rec.CollectTime.ToString("yyyy-MM-dd HH:mm:ss")
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
string detailJson = JsonConvert.SerializeObject(detail);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 写入分析记录
|
|
|
|
|
|
|
|
WriteAnalysis(new CncModels.Entity.CollectAnalysis
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
AnalysisTime = analysisTime,
|
|
|
|
|
|
|
|
RawLogId = rawLogId,
|
|
|
|
|
|
|
|
CollectAddressId = collectAddressId,
|
|
|
|
|
|
|
|
MachineId = rec.MachineId,
|
|
|
|
|
|
|
|
AnalysisType = analysisType,
|
|
|
|
|
|
|
|
PreviousProgram = prev?.ProgramName,
|
|
|
|
|
|
|
|
CurrentProgram = currentProgram,
|
|
|
|
|
|
|
|
PreviousPartCount = prev?.PartCount,
|
|
|
|
|
|
|
|
CurrentPartCount = currentPartCount,
|
|
|
|
|
|
|
|
PartCountDelta = partCountDelta,
|
|
|
|
|
|
|
|
PreviousStatus = prev?.DeviceStatus,
|
|
|
|
|
|
|
|
CurrentStatus = currentStatus,
|
|
|
|
|
|
|
|
AnalysisSummary = summary,
|
|
|
|
|
|
|
|
AnalysisDetail = detailJson
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 更新快照
|
|
|
|
|
|
|
|
_lastSnapshot[rec.MachineId] = new MachineSnapshot
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ProgramName = currentProgram,
|
|
|
|
|
|
|
|
PartCount = currentPartCount,
|
|
|
|
|
|
|
|
DeviceStatus = currentStatus,
|
|
|
|
|
|
|
|
CollectTime = rec.CollectTime
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 统计分布
|
|
|
|
|
|
|
|
if (changeDistribution.ContainsKey(analysisType))
|
|
|
|
|
|
|
|
changeDistribution[analysisType]++;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
changeDistribution[analysisType] = 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 异常告警
|
|
|
|
|
|
|
|
if (needAlert)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
hasAnomaly = true;
|
|
|
|
|
|
|
|
WriteAlert(alertType, rec.MachineId, collectAddressId, summary, detailJson);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 统计成功数(非异常即为成功)
|
|
|
|
|
|
|
|
if (analysisType != "COLLECTION_FAILED" && analysisType != "DATA_ANOMALY")
|
|
|
|
|
|
|
|
successCount++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
_log.Error($"分析单条记录失败(machineId={rec.MachineId})", ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 写入周期汇总
|
|
|
|
|
|
|
|
WriteCycleSummary(new CncModels.Entity.CollectCycle
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
CycleTime = cycleStartTime,
|
|
|
|
|
|
|
|
CollectAddressId = collectAddressId,
|
|
|
|
|
|
|
|
RawLogId = rawLogId,
|
|
|
|
|
|
|
|
EndTime = analysisTime,
|
|
|
|
|
|
|
|
DurationMs = (int)durationMs,
|
|
|
|
|
|
|
|
TotalMachines = records.Count,
|
|
|
|
|
|
|
|
SuccessCount = successCount,
|
|
|
|
|
|
|
|
FailCount = records.Count - successCount,
|
|
|
|
|
|
|
|
ChangeDistribution = JsonConvert.SerializeObject(changeDistribution),
|
|
|
|
|
|
|
|
HasAnomaly = hasAnomaly ? 1 : 0,
|
|
|
|
|
|
|
|
CycleSummary = $"共{records.Count}台机床完成分析" + (hasAnomaly ? ",存在异常" : "")
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
_log.Error($"采集分析失败(地址={addressName}, rawLogId={rawLogId})", ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// 根据前后状态对比,确定分析类型
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
private void DetermineAnalysis(MachineSnapshot prev, string currentProgram, decimal? currentPartCount,
|
|
|
|
|
|
|
|
string currentStatus, string machineName, out string analysisType, out string summary,
|
|
|
|
|
|
|
|
out bool needAlert, out string alertType)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
needAlert = false;
|
|
|
|
|
|
|
|
alertType = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 无历史快照 → 首次上线
|
|
|
|
|
|
|
|
if (prev == null)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
analysisType = "DEVICE_ONLINE";
|
|
|
|
|
|
|
|
summary = $"机床{machineName}首次上线,程序={currentProgram ?? "未知"}";
|
|
|
|
|
|
|
|
needAlert = true;
|
|
|
|
|
|
|
|
alertType = "unknown_device";
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string prevProgram = prev.ProgramName;
|
|
|
|
|
|
|
|
decimal? prevPartCount = prev.PartCount;
|
|
|
|
|
|
|
|
string prevStatus = prev.DeviceStatus;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检测程序切换
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(currentProgram) && !string.IsNullOrEmpty(prevProgram) &&
|
|
|
|
|
|
|
|
!string.Equals(prevProgram, currentProgram, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
analysisType = "PROGRAM_SWITCH";
|
|
|
|
|
|
|
|
summary = $"机床{machineName}程序切换: {prevProgram} → {currentProgram}";
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检测手动清零(同程序下零件数下降)
|
|
|
|
|
|
|
|
if (currentPartCount.HasValue && prevPartCount.HasValue &&
|
|
|
|
|
|
|
|
currentPartCount.Value < prevPartCount.Value)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
analysisType = "MANUAL_RESET";
|
|
|
|
|
|
|
|
summary = $"机床{machineName}零件计数手动清零: {prevPartCount} → {currentPartCount}";
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检测零件数增加
|
|
|
|
|
|
|
|
if (currentPartCount.HasValue && prevPartCount.HasValue &&
|
|
|
|
|
|
|
|
currentPartCount.Value > prevPartCount.Value)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
decimal delta = currentPartCount.Value - prevPartCount.Value;
|
|
|
|
|
|
|
|
analysisType = "PART_COUNT_INCREASE";
|
|
|
|
|
|
|
|
summary = $"机床{machineName}新增{delta}个零件({prevPartCount} → {currentPartCount})";
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检测设备离线/告警
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(currentStatus) &&
|
|
|
|
|
|
|
|
(currentStatus.Equals("OFFLINE", StringComparison.OrdinalIgnoreCase) ||
|
|
|
|
|
|
|
|
currentStatus.Equals("ALARM", StringComparison.OrdinalIgnoreCase) ||
|
|
|
|
|
|
|
|
currentStatus.Equals("EMERGENCY", StringComparison.OrdinalIgnoreCase)))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
analysisType = "DEVICE_OFFLINE";
|
|
|
|
|
|
|
|
summary = $"机床{machineName}设备离线/告警: {currentStatus}";
|
|
|
|
|
|
|
|
needAlert = true;
|
|
|
|
|
|
|
|
alertType = "device_offline";
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检测数据异常(关键字段缺失但设备应该在线)
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(currentProgram) && !string.IsNullOrEmpty(currentStatus) &&
|
|
|
|
|
|
|
|
!currentStatus.Equals("OFFLINE", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
analysisType = "DATA_ANOMALY";
|
|
|
|
|
|
|
|
summary = $"机床{machineName}数据异常: 缺少程序名字段";
|
|
|
|
|
|
|
|
needAlert = true;
|
|
|
|
|
|
|
|
alertType = "data_anomaly";
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 无重大变化
|
|
|
|
|
|
|
|
analysisType = "NORMAL_UNCHANGED";
|
|
|
|
|
|
|
|
summary = $"机床{machineName}数据无重大变化";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// 写入单条分析记录到 log_collect_analysis
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
private void WriteAnalysis(CncModels.Entity.CollectAnalysis entity)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
using (var conn = new MySqlConnection(_logConnStr))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
conn.Execute(@"INSERT INTO log_collect_analysis
|
|
|
|
|
|
|
|
(analysis_time, raw_log_id, collect_address_id, machine_id, analysis_type,
|
|
|
|
|
|
|
|
previous_program, current_program, previous_part_count, current_part_count,
|
|
|
|
|
|
|
|
part_count_delta, previous_status, current_status, analysis_summary,
|
|
|
|
|
|
|
|
analysis_detail, created_at)
|
|
|
|
|
|
|
|
VALUES (@AnalysisTime, @RawLogId, @CollectAddressId, @MachineId, @AnalysisType,
|
|
|
|
|
|
|
|
@PreviousProgram, @CurrentProgram, @PreviousPartCount, @CurrentPartCount,
|
|
|
|
|
|
|
|
@PartCountDelta, @PreviousStatus, @CurrentStatus, @AnalysisSummary,
|
|
|
|
|
|
|
|
@AnalysisDetail, NOW())",
|
|
|
|
|
|
|
|
new
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
entity.AnalysisTime,
|
|
|
|
|
|
|
|
entity.RawLogId,
|
|
|
|
|
|
|
|
entity.CollectAddressId,
|
|
|
|
|
|
|
|
entity.MachineId,
|
|
|
|
|
|
|
|
entity.AnalysisType,
|
|
|
|
|
|
|
|
entity.PreviousProgram,
|
|
|
|
|
|
|
|
entity.CurrentProgram,
|
|
|
|
|
|
|
|
entity.PreviousPartCount,
|
|
|
|
|
|
|
|
entity.CurrentPartCount,
|
|
|
|
|
|
|
|
entity.PartCountDelta,
|
|
|
|
|
|
|
|
entity.PreviousStatus,
|
|
|
|
|
|
|
|
entity.CurrentStatus,
|
|
|
|
|
|
|
|
entity.AnalysisSummary,
|
|
|
|
|
|
|
|
entity.AnalysisDetail
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
_log.Error($"写入分析记录失败(machineId={entity.MachineId})", ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// 写入周期汇总到 log_collect_cycle
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
private void WriteCycleSummary(CncModels.Entity.CollectCycle entity)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
using (var conn = new MySqlConnection(_logConnStr))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
conn.Execute(@"INSERT INTO log_collect_cycle
|
|
|
|
|
|
|
|
(cycle_time, collect_address_id, raw_log_id, end_time, duration_ms,
|
|
|
|
|
|
|
|
total_machines, success_count, fail_count, change_distribution,
|
|
|
|
|
|
|
|
has_anomaly, cycle_summary, created_at)
|
|
|
|
|
|
|
|
VALUES (@CycleTime, @CollectAddressId, @RawLogId, @EndTime, @DurationMs,
|
|
|
|
|
|
|
|
@TotalMachines, @SuccessCount, @FailCount, @ChangeDistribution,
|
|
|
|
|
|
|
|
@HasAnomaly, @CycleSummary, NOW())",
|
|
|
|
|
|
|
|
new
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
entity.CycleTime,
|
|
|
|
|
|
|
|
entity.CollectAddressId,
|
|
|
|
|
|
|
|
entity.RawLogId,
|
|
|
|
|
|
|
|
entity.EndTime,
|
|
|
|
|
|
|
|
entity.DurationMs,
|
|
|
|
|
|
|
|
entity.TotalMachines,
|
|
|
|
|
|
|
|
entity.SuccessCount,
|
|
|
|
|
|
|
|
entity.FailCount,
|
|
|
|
|
|
|
|
entity.ChangeDistribution,
|
|
|
|
|
|
|
|
entity.HasAnomaly,
|
|
|
|
|
|
|
|
entity.CycleSummary
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
_log.Error("写入周期汇总失败", ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// 写入告警到 cnc_alert(业务库)
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
private void WriteAlert(string alertType, int machineId, int collectAddressId, string title, string detail)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
using (var conn = new MySqlConnection(_businessConnStr))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
conn.Execute(@"INSERT INTO cnc_alert (alert_type, machine_id, collect_address_id, title, detail, is_resolved, created_at)
|
|
|
|
|
|
|
|
VALUES (@AlertType, @MachineId, @AddressId, @Title, @Detail, 0, NOW())",
|
|
|
|
|
|
|
|
new
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
AlertType = alertType,
|
|
|
|
|
|
|
|
MachineId = machineId,
|
|
|
|
|
|
|
|
AddressId = collectAddressId,
|
|
|
|
|
|
|
|
Title = title,
|
|
|
|
|
|
|
|
Detail = detail
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
_log.Error($"写入告警失败(alertType={alertType}, machineId={machineId})", ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|