From c35f739e2ec384e8901af61f34452a985a4a97e0 Mon Sep 17 00:00:00 2001 From: chenson42 Date: Thu, 17 Jul 2008 15:01:26 +0000 Subject: [PATCH] check the stat thresholds and publish jmx notification --- .../model/StatisticAlertThresholds.java | 149 ++++++++++++++---- .../service/impl/StatisticService.java | 20 +-- .../symmetric/statistic/StatisticManager.java | 19 ++- symmetric/src/main/resources/ddl-config.xml | 10 +- .../resources/sql/statistic-service-sql.xml | 12 +- .../service/impl/StatisticServiceTest.java | 50 +++++- 6 files changed, 206 insertions(+), 54 deletions(-) diff --git a/symmetric/src/main/java/org/jumpmind/symmetric/model/StatisticAlertThresholds.java b/symmetric/src/main/java/org/jumpmind/symmetric/model/StatisticAlertThresholds.java index 26b3e4a2cf..323332722c 100644 --- a/symmetric/src/main/java/org/jumpmind/symmetric/model/StatisticAlertThresholds.java +++ b/symmetric/src/main/java/org/jumpmind/symmetric/model/StatisticAlertThresholds.java @@ -1,29 +1,57 @@ +/* + * SymmetricDS is an open source database synchronization solution. + * + * Copyright (C) Chris Henson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * . + */ package org.jumpmind.symmetric.model; import java.math.BigDecimal; +import javax.management.Notification; + import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; +import org.jumpmind.symmetric.statistic.Statistic; public class StatisticAlertThresholds { String statisticName; - BigDecimal threshholdTotalMax; - Long threshholdCountMax; - BigDecimal threshholdTotalMin; - Long threshholdCountMin; + BigDecimal thresholdTotalMax; + Long thresholdCountMax; + BigDecimal thresholdTotalMin; + Long thresholdCountMin; + BigDecimal thresholdAvgMax; + BigDecimal thresholdAvgMin; + static long sequenceNumber = System.currentTimeMillis(); public StatisticAlertThresholds() { } public StatisticAlertThresholds(String statisticName, BigDecimal threshholdTotalMax, Long threshholdCountMax, - BigDecimal threshholdTotalMin, Long threshholdCountMin) { + BigDecimal threshholdTotalMin, Long threshholdCountMin, BigDecimal threshholdAvgMax, + BigDecimal threshholdAvgMin) { super(); this.statisticName = statisticName; - this.threshholdTotalMax = threshholdTotalMax; - this.threshholdCountMax = threshholdCountMax; - this.threshholdTotalMin = threshholdTotalMin; - this.threshholdCountMin = threshholdCountMin; + this.thresholdTotalMax = threshholdTotalMax; + this.thresholdCountMax = threshholdCountMax; + this.thresholdTotalMin = threshholdTotalMin; + this.thresholdCountMin = threshholdCountMin; + this.thresholdAvgMax = threshholdAvgMax; + this.thresholdAvgMin = threshholdAvgMin; } public String getStatisticName() { @@ -34,42 +62,100 @@ public void setStatisticName(String statisticName) { this.statisticName = statisticName; } - public BigDecimal getThreshholdTotalMax() { - return threshholdTotalMax; + public BigDecimal getThresholdTotalMax() { + return thresholdTotalMax == null ? BigDecimal.ZERO : thresholdTotalMax; + } + + public void setThresholdTotalMax(BigDecimal threshholdTotalMax) { + this.thresholdTotalMax = threshholdTotalMax; + } + + public Long getThresholdCountMax() { + return thresholdCountMax == null ? 0l : thresholdCountMax; + } + + public void setThresholdCountMax(Long threshholdCountMax) { + this.thresholdCountMax = threshholdCountMax; } - public void setThreshholdTotalMax(BigDecimal threshholdTotalMax) { - this.threshholdTotalMax = threshholdTotalMax; + public BigDecimal getThresholdTotalMin() { + return thresholdTotalMin == null ? BigDecimal.ZERO : thresholdTotalMin; } - public Long getThreshholdCountMax() { - return threshholdCountMax; + public void setThresholdTotalMin(BigDecimal threshholdTotalMin) { + this.thresholdTotalMin = threshholdTotalMin; } - public void setThreshholdCountMax(Long threshholdCountMax) { - this.threshholdCountMax = threshholdCountMax; + public Long getThresholdCountMin() { + return thresholdCountMin == null ? 0l : thresholdCountMin; + } + + public void setThresholdCountMin(Long threshholdCountMin) { + this.thresholdCountMin = threshholdCountMin; + } + + public Notification outsideOfBoundsNotification(Statistic stats) { + if (stats != null && stats.getName().name().equals(statisticName)) { + boolean createNotification = false; + StringBuilder msg = new StringBuilder(statisticName); + long count = stats.getCount(); + BigDecimal total = stats.getTotal(); + BigDecimal avg = stats.getAverageValue(); + if ((thresholdCountMax != null && thresholdCountMax > 0 && count > thresholdCountMax) + || (thresholdCountMin != null && thresholdCountMin > 0 && count < thresholdCountMin)) { + msg.append(":count="); + msg.append(count); + createNotification = true; + } + + if ((thresholdTotalMax != null && thresholdTotalMax.compareTo(BigDecimal.ZERO) > 0 && total + .compareTo(thresholdTotalMax) > 0) + || (thresholdTotalMin != null && thresholdTotalMin.compareTo(BigDecimal.ZERO) > 0 && total + .compareTo(thresholdTotalMin) < 0)) { + msg.append(":total="); + msg.append(total); + createNotification = true; + } + + if ((thresholdAvgMax != null && thresholdAvgMax.compareTo(BigDecimal.ZERO) > 0 && avg + .compareTo(thresholdAvgMax) > 0) + || (thresholdAvgMin != null && thresholdAvgMin.compareTo(BigDecimal.ZERO) > 0 && avg + .compareTo(thresholdAvgMin) < 0)) { + msg.append(":avg="); + msg.append(avg); + createNotification = true; + } + + if (createNotification) { + return new Notification("SymmetricDS:Alert", stats, sequenceNumber++, System.currentTimeMillis(), msg + .toString()); + } + + } + return null; } - public BigDecimal getThreshholdTotalMin() { - return threshholdTotalMin; + public BigDecimal getThresholdAvgMax() { + return thresholdAvgMax == null ? BigDecimal.ZERO : thresholdAvgMax; } - public void setThreshholdTotalMin(BigDecimal threshholdTotalMin) { - this.threshholdTotalMin = threshholdTotalMin; + public void setThresholdAvgMax(BigDecimal threshholdAvgMax) { + this.thresholdAvgMax = threshholdAvgMax; } - public Long getThreshholdCountMin() { - return threshholdCountMin; + public BigDecimal getThresholdAvgMin() { + return thresholdAvgMin == null ? BigDecimal.ZERO : thresholdAvgMin; } - public void setThreshholdCountMin(Long threshholdCountMin) { - this.threshholdCountMin = threshholdCountMin; + public void setThresholdAvgMin(BigDecimal threshholdAvgMin) { + this.thresholdAvgMin = threshholdAvgMin; } @Override public int hashCode() { - return new HashCodeBuilder(17, 37).append(statisticName).append(threshholdTotalMax).append(threshholdCountMax) - .append(threshholdTotalMin).append(threshholdCountMin).toHashCode(); + return new HashCodeBuilder(17, 37).append(statisticName).append(getThresholdTotalMax()).append( + getThresholdCountMax()).append(getThresholdTotalMin()).append(getThresholdCountMin()).append( + getThresholdAvgMax()).append(getThresholdAvgMin()).toHashCode(); } @@ -82,10 +168,11 @@ public boolean equals(Object obj) { return true; } StatisticAlertThresholds rhs = (StatisticAlertThresholds) obj; - return new EqualsBuilder().append(statisticName, rhs.statisticName).append( - threshholdTotalMax, rhs.threshholdTotalMax).append(threshholdCountMax, rhs.threshholdCountMax).append( - threshholdTotalMin, rhs.threshholdTotalMin).append(threshholdCountMin, rhs.threshholdCountMin) - .isEquals(); + return new EqualsBuilder().append(statisticName, rhs.statisticName).append(getThresholdTotalMax(), + rhs.getThresholdTotalMax()).append(getThresholdCountMax(), rhs.getThresholdCountMax()).append( + getThresholdTotalMin(), rhs.getThresholdTotalMin()).append(getThresholdCountMin(), + rhs.getThresholdCountMin()).append(getThresholdAvgMax(), rhs.getThresholdAvgMax()).append( + getThresholdAvgMin(), rhs.getThresholdAvgMin()).isEquals(); } } diff --git a/symmetric/src/main/java/org/jumpmind/symmetric/service/impl/StatisticService.java b/symmetric/src/main/java/org/jumpmind/symmetric/service/impl/StatisticService.java index 52b78951b1..8f977eb165 100644 --- a/symmetric/src/main/java/org/jumpmind/symmetric/service/impl/StatisticService.java +++ b/symmetric/src/main/java/org/jumpmind/symmetric/service/impl/StatisticService.java @@ -49,25 +49,27 @@ public List getAlertThresholds() { new ParameterizedRowMapper() { public StatisticAlertThresholds mapRow(ResultSet rs, int rowNum) throws SQLException { return new StatisticAlertThresholds(rs.getString("statistic_name"), rs - .getBigDecimal("threshhold_total_max"), rs.getLong("threshhold_count_max"), rs - .getBigDecimal("threshhold_total_min"), rs.getLong("threshhold_count_min")); + .getBigDecimal("threshold_total_max"), rs.getLong("threshold_count_max"), rs + .getBigDecimal("threshold_total_min"), rs.getLong("threshold_count_min"), rs + .getBigDecimal("threshold_avg_max"), rs.getBigDecimal("threshold_avg_min")); } }); } public void saveStatisticAlertThresholds(StatisticAlertThresholds threshold) { SimpleJdbcTemplate template = getSimpleTemplate(); - int updated = template.update(getSql("updateAlertThresholdsSql"), threshold.getThreshholdTotalMax(), threshold - .getThreshholdCountMax(), threshold.getThreshholdTotalMin(), threshold.getThreshholdCountMin(), - threshold.getStatisticName()); + int updated = template.update(getSql("updateAlertThresholdsSql"), threshold.getThresholdTotalMax(), threshold + .getThresholdCountMax(), threshold.getThresholdAvgMax(), threshold.getThresholdTotalMin(), threshold + .getThresholdCountMin(), threshold.getThresholdAvgMin(), threshold.getStatisticName()); if (updated == 0) { template.update(getSql("insertAlertThresholdsSql"), threshold.getStatisticName(), threshold - .getThreshholdTotalMax(), threshold.getThreshholdCountMax(), threshold.getThreshholdTotalMin(), - threshold.getThreshholdCountMin()); + .getThresholdTotalMax(), threshold.getThresholdCountMax(), threshold.getThresholdAvgMax(), + threshold.getThresholdTotalMin(), threshold.getThresholdCountMin(), threshold + .getThresholdAvgMin()); } } - + public boolean removeStatisticAlertThresholds(String statisticName) { - return 1 == getSimpleTemplate().update(getSql("deleteAlertThresholdsSql"), statisticName); + return 1 == getSimpleTemplate().update(getSql("deleteAlertThresholdsSql"), statisticName); } } diff --git a/symmetric/src/main/java/org/jumpmind/symmetric/statistic/StatisticManager.java b/symmetric/src/main/java/org/jumpmind/symmetric/statistic/StatisticManager.java index 5ea6955439..366867fd49 100644 --- a/symmetric/src/main/java/org/jumpmind/symmetric/statistic/StatisticManager.java +++ b/symmetric/src/main/java/org/jumpmind/symmetric/statistic/StatisticManager.java @@ -21,10 +21,14 @@ import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Map; +import javax.management.Notification; + import org.jumpmind.symmetric.common.ParameterConstants; import org.jumpmind.symmetric.model.Node; +import org.jumpmind.symmetric.model.StatisticAlertThresholds; import org.jumpmind.symmetric.service.INodeService; import org.jumpmind.symmetric.service.INotificationService; import org.jumpmind.symmetric.service.IParameterService; @@ -62,8 +66,19 @@ synchronized public void flush() { * alert thresholds and publish alerts if we fall outside the range. */ synchronized protected void publishAlerts() { - if (parameterService.is(ParameterConstants.STATISTIC_THRESHOLD_ALERTS_ENABLED)) { - // TODO + if (parameterService.is(ParameterConstants.STATISTIC_THRESHOLD_ALERTS_ENABLED) && statistics != null) { + List thresholds = statisticService.getAlertThresholds(); + if (thresholds != null) { + for (StatisticAlertThresholds statisticAlertThresholds : thresholds) { + StatisticName name = StatisticName.valueOf(statisticAlertThresholds.getStatisticName()); + if (name != null) { + Notification event = statisticAlertThresholds.outsideOfBoundsNotification(statistics.get(name)); + if (event != null) { + notificationService.sendNotification(event); + } + } + } + } } } diff --git a/symmetric/src/main/resources/ddl-config.xml b/symmetric/src/main/resources/ddl-config.xml index e59a776aad..6abb0646bd 100644 --- a/symmetric/src/main/resources/ddl-config.xml +++ b/symmetric/src/main/resources/ddl-config.xml @@ -237,10 +237,12 @@ - - - - + + + + + +
diff --git a/symmetric/src/main/resources/sql/statistic-service-sql.xml b/symmetric/src/main/resources/sql/statistic-service-sql.xml index 18231cce08..85171621bc 100644 --- a/symmetric/src/main/resources/sql/statistic-service-sql.xml +++ b/symmetric/src/main/resources/sql/statistic-service-sql.xml @@ -19,24 +19,24 @@ diff --git a/symmetric/src/test/java/org/jumpmind/symmetric/service/impl/StatisticServiceTest.java b/symmetric/src/test/java/org/jumpmind/symmetric/service/impl/StatisticServiceTest.java index 3b52c6f7af..548218049d 100644 --- a/symmetric/src/test/java/org/jumpmind/symmetric/service/impl/StatisticServiceTest.java +++ b/symmetric/src/test/java/org/jumpmind/symmetric/service/impl/StatisticServiceTest.java @@ -3,10 +3,14 @@ import java.math.BigDecimal; import java.util.List; +import javax.management.Notification; + import org.jumpmind.symmetric.AbstractDatabaseTest; import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.model.StatisticAlertThresholds; import org.jumpmind.symmetric.service.IStatisticService; +import org.jumpmind.symmetric.statistic.Statistic; +import org.jumpmind.symmetric.statistic.StatisticName; import org.jumpmind.symmetric.util.AppUtils; import org.testng.Assert; import org.testng.annotations.BeforeTest; @@ -28,7 +32,7 @@ public void testSaveAlerts() throws Exception { statisticService.removeStatisticAlertThresholds(TEST_STAT_NAME); StatisticAlertThresholds thresholds = new StatisticAlertThresholds(TEST_STAT_NAME, new BigDecimal(10), - new Long(2), new BigDecimal(0), new Long(0)); + new Long(2), new BigDecimal(0), new Long(0), new BigDecimal(0), new BigDecimal(0)); List list = statisticService.getAlertThresholds(); Assert.assertFalse(list.contains(thresholds)); @@ -38,7 +42,7 @@ public void testSaveAlerts() throws Exception { list = statisticService.getAlertThresholds(); Assert.assertTrue(list.contains(thresholds)); - thresholds.setThreshholdCountMin(-100l); + thresholds.setThresholdCountMin(-100l); Assert.assertFalse(list.contains(thresholds)); statisticService.saveStatisticAlertThresholds(thresholds); @@ -48,4 +52,46 @@ public void testSaveAlerts() throws Exception { statisticService.removeStatisticAlertThresholds(TEST_STAT_NAME); } + + @Test(groups = "continuous") + public void testSaveAlertsWithNulls() throws Exception { + statisticService.removeStatisticAlertThresholds(TEST_STAT_NAME); + + StatisticAlertThresholds thresholds = new StatisticAlertThresholds(TEST_STAT_NAME, new BigDecimal(10), + new Long(2), null, new Long(0), null, null); + + List list = statisticService.getAlertThresholds(); + Assert.assertFalse(list.contains(thresholds)); + + statisticService.saveStatisticAlertThresholds(thresholds); + + list = statisticService.getAlertThresholds(); + Assert.assertTrue(list.contains(thresholds)); + + thresholds.setThresholdCountMin(-100l); + Assert.assertFalse(list.contains(thresholds)); + + statisticService.saveStatisticAlertThresholds(thresholds); + + list = statisticService.getAlertThresholds(); + Assert.assertTrue(list.contains(thresholds)); + + statisticService.removeStatisticAlertThresholds(TEST_STAT_NAME); + } + + @Test(groups = "continuous") + public void testNotificationCreationForTotals() throws Exception { + Statistic stat = new Statistic(StatisticName.INCOMING_BATCH_COUNT, "010101"); + StatisticAlertThresholds thresholds = new StatisticAlertThresholds(StatisticName.INCOMING_BATCH_COUNT.name(), + new BigDecimal(10), null, new BigDecimal(1), null, null, null); + Assert.assertNotNull(thresholds.outsideOfBoundsNotification(stat)); + stat.add(new BigDecimal(1)); + Assert.assertNull(thresholds.outsideOfBoundsNotification(stat)); + stat.add(new BigDecimal(9)); + Assert.assertNull(thresholds.outsideOfBoundsNotification(stat));stat.add(new BigDecimal(1)); + Notification event = thresholds.outsideOfBoundsNotification(stat); + Assert.assertNotNull(event); + String expectedMsg = stat.getName().name() + ":total=11"; + Assert.assertEquals(event.getMessage(), expectedMsg); + } }