| | |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.Locale; |
| | | import com.alibaba.fastjson2.JSON; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | } |
| | | } |
| | | |
| | | /** 仅对成功接收的非空测量值判定阈值,并聚合更新开放异常及规则快照。 */ |
| | | /** 在持有测试事务锁时,对接收中的成功实时测量聚合开放异常,不受采样入库周期限制。 */ |
| | | public void evaluate(TTest test, String sourceType, String sourceIdentity, String metricCode, BigDecimal value, String unit, Date occurredAt) { |
| | | if (value == null || test == null || test.getThresholds() == null) return; |
| | | for (TTestWarningThreshold rule : test.getThresholds()) { |
| | | if (rule == null || rule.getMetricCode() == null || !matches(rule.getMetricCode(), metricCode) |
| | | || !outside(value, rule.getMinValue(), rule.getMaxValue())) continue; |
| | | for (TTestWarningThreshold rule : exceededRules(test, metricCode, value)) { |
| | | mapper.upsertWarningException(test.getTestId(), rule.getThresholdId(), sourceType, sourceIdentity, metricCode, value, unit, |
| | | JSON.toJSONString(rule), rule.getSeverity(), occurredAt == null ? new Date() : occurredAt); |
| | | } |
| | | } |
| | | |
| | | static List<TTestWarningThreshold> exceededRules(TTest test, String metricCode, BigDecimal value) { |
| | | if (value == null || test == null || test.getThresholds() == null |
| | | || !"RUNNING".equals(test.getTestStatus()) || !"RECEIVING".equals(test.getReceptionStatus())) return List.of(); |
| | | return test.getThresholds().stream().filter(rule -> rule != null |
| | | && matchesMetric(rule.getMetricCode(), metricCode) |
| | | && outside(value, rule.getMinValue(), rule.getMaxValue())).toList(); |
| | | } |
| | | |
| | | /** 由测试负责人关闭开放异常,处理内容保存在异常事实中。 */ |
| | |
| | | int rows = mapper.closeWarningException(exceptionId, actorId, actorName, new Date(), handlingNote); |
| | | return rows; |
| | | } |
| | | private boolean outside(BigDecimal value, BigDecimal min, BigDecimal max) { return (min != null && value.compareTo(min) < 0) || (max != null && value.compareTo(max) > 0); } |
| | | private boolean matches(String configured, String actual) { |
| | | if (actual == null) return false; |
| | | private static boolean outside(BigDecimal value, BigDecimal min, BigDecimal max) { return (min != null && value.compareTo(min) < 0) || (max != null && value.compareTo(max) > 0); } |
| | | static boolean matchesCollectorMetric(String configured, String actual) { |
| | | if (configured == null || actual == null) return false; |
| | | String role = configured.toUpperCase(Locale.ROOT), metric = actual.toUpperCase(Locale.ROOT); |
| | | return role.equals(metric) || List.of("TEMPERATURE", "POSITIVE_POTENTIAL", "NEGATIVE_POTENTIAL").stream() |
| | | .anyMatch(code -> metric.equals(code) && role.contains(code)); |
| | | } |
| | | |
| | | static boolean matchesMetric(String configured, String actual) { |
| | | if (configured == null || actual == null) return false; |
| | | if (configured.equalsIgnoreCase(actual)) return true; |
| | | String c = configured.toUpperCase(), a = actual.toUpperCase(); |
| | | String c = configured.toUpperCase(Locale.ROOT), a = actual.toUpperCase(Locale.ROOT); |
| | | return (c.contains("VOLTAGE") && a.contains("VOLTAGE")) || (c.contains("CURRENT") && a.contains("CURRENT")) |
| | | || (c.contains("CAPACITY") && a.contains("CAPACITY")) || (c.contains("ENERGY") && a.contains("ENERGY")) |
| | | || (c.contains("TEMPERATURE") && a.contains("TEMPERATURE")) || (c.contains("POSITIVE_POTENTIAL") && a.contains("POSITIVE_POTENTIAL")) |