diff --git a/seyren-api/pom.xml b/seyren-api/pom.xml index 9f570232..8a6f80ab 100755 --- a/seyren-api/pom.xml +++ b/seyren-api/pom.xml @@ -30,6 +30,36 @@ + + com.google.collections + google-collections + 1.0 + jar + + + org.springframework + spring-core + 4.1.4.RELEASE + jar + + + com.google.guava + guava + 18.0 + jar + + + joda-time + joda-time + 2.6 + jar + + + org.slf4j + slf4j-api + 1.7.9 + jar + diff --git a/seyren-api/src/main/java/com/seyren/api/bean/ChartsBean.java b/seyren-api/src/main/java/com/seyren/api/bean/ChartsBean.java index 6ff6d3af..c6fbfd1c 100644 --- a/seyren-api/src/main/java/com/seyren/api/bean/ChartsBean.java +++ b/seyren-api/src/main/java/com/seyren/api/bean/ChartsBean.java @@ -48,21 +48,20 @@ public Response getChart(String checkId, int width, int height, String from, Str if (check == null) { return Response.status(Status.NOT_FOUND).build(); } - + String target = check.getTarget(); if (hideThresholds) { - return getChart(target, width, height, from, to, null, null, hideLegend, hideAxes); + return getChart(check.getGraphiteSourceUrl(), target, width, height, from, to, null, null, hideLegend, hideAxes); } else { - return getChart(target, width, height, from, to, check.getWarn(), check.getError(), hideLegend, hideAxes); + return getChart(check.getGraphiteSourceUrl(), target, width, height, from, to, check.getWarn(), check.getError(), hideLegend, hideAxes); } - } @Override - public Response getCustomChart(String target, int width, int height, String from, String to, String warnThreshold, String errorThreshold, boolean hideLegend, + public Response getCustomChart(String target, String graphiteSourceUrl, int width, int height, String from, String to, String warnThreshold, String errorThreshold, boolean hideLegend, boolean hideAxes) { - + BigDecimal warn; if (StringUtils.isEmpty(warnThreshold)) { warn = null; @@ -77,11 +76,10 @@ public Response getCustomChart(String target, int width, int height, String from error = new BigDecimal(errorThreshold); } - return getChart(target, width, height, from, to, warn, error, hideLegend, hideAxes); - + return getChart(graphiteSourceUrl, target, width, height, from, to, warn, error, hideLegend, hideAxes); } - private Response getChart(String target, int width, int height, String from, String to, BigDecimal warnThreshold, BigDecimal errorThreshold, boolean hideLegend, + private Response getChart(String graphiteSource, String target, int width, int height, String from, String to, BigDecimal warnThreshold, BigDecimal errorThreshold, boolean hideLegend, boolean hideAxes) { LegendState legendState; @@ -99,12 +97,10 @@ private Response getChart(String target, int width, int height, String from, Str } try { - byte[] bytes = graphiteHttpClient.getChart(target, width, height, from, to, legendState, axesState, warnThreshold, errorThreshold); + byte[] bytes = graphiteHttpClient.getChart(graphiteSource, target, width, height, from, to, legendState, axesState, warnThreshold, errorThreshold); return Response.ok(bytes, "image/png").build(); } catch (Exception e) { return Response.serverError().build(); - } - + } } - } diff --git a/seyren-api/src/main/java/com/seyren/api/jaxrs/ChartsResource.java b/seyren-api/src/main/java/com/seyren/api/jaxrs/ChartsResource.java index 74283c3d..0576255d 100644 --- a/seyren-api/src/main/java/com/seyren/api/jaxrs/ChartsResource.java +++ b/seyren-api/src/main/java/com/seyren/api/jaxrs/ChartsResource.java @@ -40,6 +40,7 @@ Response getChart(@PathParam("checkId") String checkId, @Produces("image/png") @Path("/chart/{target}") Response getCustomChart(@PathParam("target") String target, + @QueryParam("graphiteSourceUrl") String graphiteSourceUrl, @QueryParam("width") @DefaultValue("1200") int width, @QueryParam("height") @DefaultValue("350") int height, @QueryParam("from") @DefaultValue("-24hours") String from, diff --git a/seyren-core/pom.xml b/seyren-core/pom.xml index 7ab12bb1..75ffb0a3 100755 --- a/seyren-core/pom.xml +++ b/seyren-core/pom.xml @@ -104,10 +104,10 @@ org.springframework spring-context-support - + com.opsgenie.integration sdk - + diff --git a/seyren-core/src/main/java/com/seyren/core/domain/Check.java b/seyren-core/src/main/java/com/seyren/core/domain/Check.java index 1a36ecde..923c389f 100644 --- a/seyren-core/src/main/java/com/seyren/core/domain/Check.java +++ b/seyren-core/src/main/java/com/seyren/core/domain/Check.java @@ -51,6 +51,7 @@ public class Check { private AlertType state; private DateTime lastCheck; private List subscriptions = new ArrayList(); + private String graphiteSourceUrl; public String getId() { return id; @@ -239,4 +240,16 @@ public Check withSubscriptions(List subscriptions) { return this; } + public String getGraphiteSourceUrl() { + return graphiteSourceUrl; + } + + public void setGraphiteSourceUrl(String graphiteSourceUrl) { + this.graphiteSourceUrl = graphiteSourceUrl; + } + + public Check withGraphiteSourceUrl(String graphiteSourceUrl) { + setGraphiteSourceUrl(graphiteSourceUrl); + return this; + } } diff --git a/seyren-core/src/main/java/com/seyren/core/service/checker/GraphiteTargetChecker.java b/seyren-core/src/main/java/com/seyren/core/service/checker/GraphiteTargetChecker.java index 2013bbaa..6f113da4 100644 --- a/seyren-core/src/main/java/com/seyren/core/service/checker/GraphiteTargetChecker.java +++ b/seyren-core/src/main/java/com/seyren/core/service/checker/GraphiteTargetChecker.java @@ -47,7 +47,8 @@ public Map> check(Check check) throws Exception { Map> targetValues = new HashMap>(); try { - JsonNode node = graphiteHttpClient.getTargetJson(check.getTarget(), check.getFrom(), check.getUntil()); + JsonNode node = graphiteHttpClient.getTargetJson(check.getGraphiteSourceUrl(), check.getTarget(), check.getFrom(), check.getUntil()); + for (JsonNode metric : node) { String target = metric.path("target").asText(); try { diff --git a/seyren-core/src/main/java/com/seyren/core/service/live/server/PickleHandler.java b/seyren-core/src/main/java/com/seyren/core/service/live/server/PickleHandler.java index 52fb7f7e..6a3349c4 100644 --- a/seyren-core/src/main/java/com/seyren/core/service/live/server/PickleHandler.java +++ b/seyren-core/src/main/java/com/seyren/core/service/live/server/PickleHandler.java @@ -54,6 +54,7 @@ public class PickleHandler implements Runnable { public PickleHandler(Socket socket, Executor executor, ChecksStore checksStore, CheckRunnerFactory checkRunnerFactory) { this.socket = socket; this.executor = executor; + this.executor = executor; this.checksStore = checksStore; this.checkRunnerFactory = checkRunnerFactory; } diff --git a/seyren-core/src/main/java/com/seyren/core/service/notification/OpsGenieNotificationService.java b/seyren-core/src/main/java/com/seyren/core/service/notification/OpsGenieNotificationService.java index 822c29b2..a913e733 100644 --- a/seyren-core/src/main/java/com/seyren/core/service/notification/OpsGenieNotificationService.java +++ b/seyren-core/src/main/java/com/seyren/core/service/notification/OpsGenieNotificationService.java @@ -152,4 +152,4 @@ public boolean canHandle(SubscriptionType subscriptionType) { return subscriptionType == SubscriptionType.OPSGENIE; } -} +} \ No newline at end of file diff --git a/seyren-core/src/main/java/com/seyren/core/service/notification/SnmpTrapNotificationService.java b/seyren-core/src/main/java/com/seyren/core/service/notification/SnmpTrapNotificationService.java index f17a7c37..a823bb28 100644 --- a/seyren-core/src/main/java/com/seyren/core/service/notification/SnmpTrapNotificationService.java +++ b/seyren-core/src/main/java/com/seyren/core/service/notification/SnmpTrapNotificationService.java @@ -146,4 +146,4 @@ private OctetString octetString(String value) { private String url(Check check) { return String.format("%s/#/checks/%s", seyrenConfig.getBaseUrl(), check.getName()); } -} +} \ No newline at end of file diff --git a/seyren-core/src/main/java/com/seyren/core/util/config/SeyrenConfig.java b/seyren-core/src/main/java/com/seyren/core/util/config/SeyrenConfig.java index 9c221c1c..59cb9365 100644 --- a/seyren-core/src/main/java/com/seyren/core/util/config/SeyrenConfig.java +++ b/seyren-core/src/main/java/com/seyren/core/util/config/SeyrenConfig.java @@ -79,6 +79,7 @@ public class SeyrenConfig { private final Integer snmpPort; private final String snmpCommunity; private final String snmpOID; + private final String snmpSource; private final String victorOpsRestAPIEndpoint; private final String emailTemplateFileName; private final String emailSubjectTemplateFileName; @@ -158,6 +159,7 @@ public SeyrenConfig() { this.snmpPort = Integer.parseInt(configOrDefault("SNMP_PORT", "162")); this.snmpCommunity = configOrDefault("SNMP_COMMUNITY", "public"); this.snmpOID = configOrDefault("SNMP_OID", "1.3.6.1.4.1.32473.1"); + this.snmpSource = configOrDefault("SNMP_SOURCE", "localhost"); //VictorOps this.victorOpsRestAPIEndpoint = configOrDefault("VICTOROPS_REST_ENDPOINT", ""); @@ -315,7 +317,12 @@ public String getSnmpCommunity() { public String getSnmpOID() { return snmpOID; } - + + @JsonIgnore + public String getSnmpSource() { + return snmpSource; + } + @JsonIgnore public String getGraphiteUrl() { return graphiteUrl; diff --git a/seyren-core/src/main/java/com/seyren/core/util/graphite/GraphiteHttpClient.java b/seyren-core/src/main/java/com/seyren/core/util/graphite/GraphiteHttpClient.java index ce3fba8b..d3b90b94 100644 --- a/seyren-core/src/main/java/com/seyren/core/util/graphite/GraphiteHttpClient.java +++ b/seyren-core/src/main/java/com/seyren/core/util/graphite/GraphiteHttpClient.java @@ -62,6 +62,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.seyren.core.service.checker.JsonNodeResponseHandler; import com.seyren.core.util.config.SeyrenConfig; +import com.seyren.core.domain.Check; @Named public class GraphiteHttpClient { @@ -72,9 +73,9 @@ public class GraphiteHttpClient { private final JsonNodeResponseHandler jsonNodeHandler = new JsonNodeResponseHandler(); private final ByteArrayResponseHandler chartBytesHandler = new ByteArrayResponseHandler(); - private final String graphiteScheme; - private final String graphiteHost; - private final String graphitePath; + private String graphiteScheme; + private String graphiteHost; + private String graphitePath; private final String graphiteUsername; private final String graphitePassword; private final String graphiteKeyStore; @@ -107,20 +108,28 @@ public GraphiteHttpClient(SeyrenConfig seyrenConfig) { * @deprecated Use {link}getTargetJson(String target, String from, String until){link} instead. */ @Deprecated - public JsonNode getTargetJson(String target) throws Exception { - return getTargetJson(target, null, null); + public JsonNode getTargetJson(String graphiteSource, String target) throws Exception { + return getTargetJson(graphiteSource, target, null, null); } - public JsonNode getTargetJson(String target, String from, String until) throws Exception { + public JsonNode getTargetJson(String graphiteSource, String target, String from, String until) throws Exception { + String graphiteDomain; // Default values for from/until preserve hard-coded functionality - // seyren had before from/until were fields that could be specified. + // seyren had before from/until were fields that could be specified if (from == null) { from = "-11minutes"; } if (until == null) { until = "-1minutes"; } - URI baseUri = new URI(graphiteScheme, graphiteHost, graphitePath + "/render/", null, null); + + if (graphiteSource != null) { + graphiteDomain = graphiteSource; + } else { + graphiteDomain = GraphiteHttpClient.this.graphiteHost; + } + + URI baseUri = new URI(graphiteScheme, graphiteDomain, graphitePath + "/render/", null, null); URI uri = new URIBuilder(baseUri) .addParameter("from", from) .addParameter("until", until) @@ -139,13 +148,21 @@ public JsonNode getTargetJson(String target, String from, String until) throws E } } - public byte[] getChart(String target, int width, int height, String from, String to, LegendState legendState, AxesState axesState) throws Exception { - return getChart(target, width, height, from, to, legendState, axesState, null, null); + public byte[] getChart(String graphiteSource, String target, int width, int height, String from, String to, LegendState legendState, AxesState axesState) throws Exception { + return getChart(graphiteSource, target, width, height, from, to, legendState, axesState, null, null); } - public byte[] getChart(String target, int width, int height, String from, String to, LegendState legendState, AxesState axesState, + public byte[] getChart(String graphiteSource, String target, int width, int height, String from, String to, LegendState legendState, AxesState axesState, BigDecimal warnThreshold, BigDecimal errorThreshold) throws Exception { - URI baseUri = new URI(graphiteScheme, graphiteHost, graphitePath + "/render/", null, null); + String graphiteDomain; + + if (graphiteSource != null) { + graphiteDomain = graphiteSource; + } else { + graphiteDomain = GraphiteHttpClient.this.graphiteHost; + } + + URI baseUri = new URI(graphiteScheme, graphiteDomain, graphitePath + "/render/", null, null); URIBuilder uriBuilder = new URIBuilder(baseUri) .addParameter("target", target) .addParameter("from", from) @@ -162,7 +179,7 @@ public byte[] getChart(String target, int width, int height, String from, String if (errorThreshold != null) { uriBuilder.addParameter("target", String.format(THRESHOLD_TARGET, errorThreshold.toString(), "red", "error level")); } - + HttpGet get = new HttpGet(uriBuilder.build()); try { diff --git a/seyren-core/src/test/java/com/seyren/core/service/checker/GraphiteTargetCheckerTest.java b/seyren-core/src/test/java/com/seyren/core/service/checker/GraphiteTargetCheckerTest.java index e47e8e94..4c0df65d 100644 --- a/seyren-core/src/test/java/com/seyren/core/service/checker/GraphiteTargetCheckerTest.java +++ b/seyren-core/src/test/java/com/seyren/core/service/checker/GraphiteTargetCheckerTest.java @@ -58,7 +58,7 @@ public void after() { public void singleValidTargetIsPresent() throws Exception { JsonNode node = MAPPER.readTree("[{\"target\": \"service.error.1MinuteRate\", \"datapoints\": [[0.06, 1337453460]]}]"); - when(mockGraphiteHttpClient.getTargetJson("service.error.1MinuteRate", null, null)).thenReturn(node); + when(mockGraphiteHttpClient.getTargetJson(null,"service.error.1MinuteRate", null, null)).thenReturn(node); Map> values = checker.check(check()); @@ -69,7 +69,7 @@ public void singleValidTargetIsPresent() throws Exception { public void singleValidTargetHasCorrectValue() throws Exception { JsonNode node = MAPPER.readTree("[{\"target\": \"service.error.1MinuteRate\", \"datapoints\": [[0.06, 1337453460]]}]"); - when(mockGraphiteHttpClient.getTargetJson("service.error.1MinuteRate", null, null)).thenReturn(node); + when(mockGraphiteHttpClient.getTargetJson(null,"service.error.1MinuteRate", null, null)).thenReturn(node); Map> values = checker.check(check()); @@ -81,7 +81,7 @@ public void singleValidTargetHasCorrectValue() throws Exception { public void valueIsDeterminedByGoingThroughDatapointsInReverserOrder() throws Exception { JsonNode node = MAPPER.readTree("[{\"target\": \"service.error.1MinuteRate\", \"datapoints\": [[0.20, 1337453460],[0.01, 1337453463]]}]"); - when(mockGraphiteHttpClient.getTargetJson("service.error.1MinuteRate", null, null)).thenReturn(node); + when(mockGraphiteHttpClient.getTargetJson(null,"service.error.1MinuteRate", null, null)).thenReturn(node); Map> values = checker.check(check()); @@ -92,7 +92,7 @@ public void valueIsDeterminedByGoingThroughDatapointsInReverserOrder() throws Ex public void valueIsDeterminedBySkippingNullValues() throws Exception { JsonNode node = MAPPER.readTree("[{\"target\": \"service.error.1MinuteRate\", \"datapoints\": [[0.17, 1337453460],[null, 1337453463]]}]"); - when(mockGraphiteHttpClient.getTargetJson("service.error.1MinuteRate", null, null)).thenReturn(node); + when(mockGraphiteHttpClient.getTargetJson(null,"service.error.1MinuteRate", null, null)).thenReturn(node); Map> values = checker.check(check()); @@ -103,7 +103,7 @@ public void valueIsDeterminedBySkippingNullValues() throws Exception { public void targetWhichOnlyHasNullValuesIsAbsent() throws Exception { JsonNode node = MAPPER.readTree("[{\"target\": \"service.error.1MinuteRate\", \"datapoints\": [[null, 1337453460],[null, 1337453463]]}]"); - when(mockGraphiteHttpClient.getTargetJson("service.error.1MinuteRate", null, null)).thenReturn(node); + when(mockGraphiteHttpClient.getTargetJson(null,"service.error.1MinuteRate", null, null)).thenReturn(node); Map> values = checker.check(check()); @@ -117,7 +117,7 @@ public void multipleTargetsAreHandledCorrectly() throws Exception { "{\"target\": \"service.warn.1MinuteRate\", \"datapoints\": [[0.56, 1337453460],[0.78, 1337453463]]}" + "]"); - when(mockGraphiteHttpClient.getTargetJson("service.*.1MinuteRate", null, null)).thenReturn(node); + when(mockGraphiteHttpClient.getTargetJson(null,"service.*.1MinuteRate", null, null)).thenReturn(node); Map> values = checker.check(checkWithTarget("service.*.1MinuteRate")); @@ -128,12 +128,12 @@ public void multipleTargetsAreHandledCorrectly() throws Exception { @Test public void exceptionGettingDataFromGraphiteIsHandled() throws Exception { - when(mockGraphiteHttpClient.getTargetJson("service.*.1MinuteRate", null, null)).thenThrow(new GraphiteReadException("Graphite bad times", new RuntimeException("Bad times"))); + when(mockGraphiteHttpClient.getTargetJson(null,"service.*.1MinuteRate", null, null)).thenThrow(new GraphiteReadException("Graphite bad times", new RuntimeException("Bad times"))); Map> values = checker.check(checkWithTarget("service.*.1MinuteRate")); assertThat(values.size(), is(0)); - } + } private Check check() { return checkWithTarget("service.error.1MinuteRate"); @@ -146,5 +146,4 @@ private Check checkWithTarget(String target) { .withWarn(new BigDecimal("0.15")) .withError(new BigDecimal("0.20")); } - } diff --git a/seyren-core/src/test/java/com/seyren/core/util/graphite/GraphiteHttpClientTest.java b/seyren-core/src/test/java/com/seyren/core/util/graphite/GraphiteHttpClientTest.java index ad7d7410..6d477d3b 100644 --- a/seyren-core/src/test/java/com/seyren/core/util/graphite/GraphiteHttpClientTest.java +++ b/seyren-core/src/test/java/com/seyren/core/util/graphite/GraphiteHttpClientTest.java @@ -44,10 +44,13 @@ public class GraphiteHttpClientTest { public ClientDriverRule clientDriver = new ClientDriverRule(); private GraphiteHttpClient graphiteHttpClient; + private GraphiteHttpClient graphiteHttpClient2; + @Before public void before() { graphiteHttpClient = new GraphiteHttpClient(seyrenConfig(clientDriver.getBaseUrl())); + graphiteHttpClient2 = new GraphiteHttpClient(seyrenConfig("localhost:80")); } @After @@ -58,7 +61,7 @@ public void after() { @Test public void requestingJsonCallsThroughToGraphiteCorrectly() throws Exception { String response = "[{\"target\": \"service.error.1MinuteRate\", \"datapoints\": [[0.06, 1337453460]]}]"; - + clientDriver.addExpectation( onRequestTo("/render/") .withParam("from", "-11minutes") @@ -68,7 +71,10 @@ public void requestingJsonCallsThroughToGraphiteCorrectly() throws Exception { .withParam("target", "service.error.1MinuteRate"), giveResponse(response, "application/json")); - JsonNode node = graphiteHttpClient.getTargetJson("service.error.1MinuteRate"); + String from = "-11minutes"; + String until = "-1minutes"; + + JsonNode node = graphiteHttpClient.getTargetJson(null, "service.error.1MinuteRate",from,until); assertThat(node, is(MAPPER.readTree(response))); } @@ -86,7 +92,7 @@ public void requestingJsonCallsWithFromAndUntilThroughToGraphiteCorrectly() thro .withParam("target", "service.error.count"), giveResponse(response, "application/json")); - JsonNode node = graphiteHttpClient.getTargetJson("service.error.count", "-5minutes", "now"); + JsonNode node = graphiteHttpClient.getTargetJson(null,"service.error.count", "-5minutes", "now"); assertThat(node, is(MAPPER.readTree(response))); } @@ -96,7 +102,7 @@ public void exceptionGettingDataFromGraphiteIsHandled() throws Exception { thrown.expect(GraphiteReadException.class); graphiteHttpClient = new GraphiteHttpClient(seyrenConfig("http://unknown")); - graphiteHttpClient.getTargetJson("service.*.1MinuteRate"); + graphiteHttpClient.getTargetJson(null,"service.*.1MinuteRate",null,null); } @Test @@ -117,11 +123,11 @@ public void authIsAddedWhenUsernameAndPasswordAreProvided() throws Exception { .withHeader("Authorization", "Basic c2V5cmVuOnMzeXIzTg=="), giveResponse(response, "application/json")); - graphiteHttpClient.getTargetJson("service.error.1MinuteRate"); + graphiteHttpClient.getTargetJson(null,"service.error.1MinuteRate",null,null); System.clearProperty("GRAPHITE_USERNAME"); System.clearProperty("GRAPHITE_PASSWORD"); - } + } @Test public void gettingChartFromGraphiteIsHandledWhenThresholdsAreNotProvided() throws Exception { @@ -139,7 +145,7 @@ public void gettingChartFromGraphiteIsHandledWhenThresholdsAreNotProvided() thro .withParam("hideAxes", false), giveResponseAsBytes(response, "image/png")); - byte[] actualBytes = graphiteHttpClient.getChart("hello.world", 300, 200, "-1hours", null, LegendState.SHOW, AxesState.SHOW); + byte[] actualBytes = graphiteHttpClient.getChart(null, "hello.world", 300, 200, "-1hours", null, LegendState.SHOW, AxesState.SHOW); assertThat(actualBytes, is(bytes)); } @@ -160,7 +166,7 @@ public void legendCanBeHiddenWhenGettingChartFromGraphite() throws Exception { .withParam("hideAxes", false), giveResponseAsBytes(response, "image/png")); - byte[] actualBytes = graphiteHttpClient.getChart("hello.world", 300, 200, "-1hours", null, LegendState.HIDE, AxesState.SHOW); + byte[] actualBytes = graphiteHttpClient.getChart(null,"hello.world", 300, 200, "-1hours", null, LegendState.HIDE, AxesState.SHOW); assertThat(actualBytes, is(bytes)); } @@ -181,7 +187,7 @@ public void axesCanBeHiddenWhenGettingChartFromGraphite() throws Exception { .withParam("hideAxes", true), giveResponseAsBytes(response, "image/png")); - byte[] actualBytes = graphiteHttpClient.getChart("hello.world", 300, 200, "-90minutes", null, LegendState.SHOW, AxesState.HIDE); + byte[] actualBytes = graphiteHttpClient.getChart(null,"hello.world", 300, 200, "-90minutes", null, LegendState.SHOW, AxesState.HIDE); assertThat(actualBytes, is(bytes)); } @@ -203,7 +209,7 @@ public void gettingChartFromGraphiteIsHandledWhenWarnThresholdIsProvided() throw .withParam("target", "alias(dashed(color(constantLine(3.2),\"yellow\")),\"warn level\")"), giveResponseAsBytes(response, "image/png")); - byte[] actualBytes = graphiteHttpClient.getChart("hello.world", 300, 200, "-1hours", null, LegendState.SHOW, AxesState.SHOW, new BigDecimal("3.2"), null); + byte[] actualBytes = graphiteHttpClient.getChart(null,"hello.world", 300, 200, "-1hours", null, LegendState.SHOW, AxesState.SHOW, new BigDecimal("3.2"), null); assertThat(actualBytes, is(bytes)); } @@ -225,7 +231,7 @@ public void gettingChartFromGraphiteIsHandledWhenErrorThresholdIsProvided() thro .withParam("target", "alias(dashed(color(constantLine(5.6),\"red\")),\"error level\")"), giveResponseAsBytes(response, "image/png")); - byte[] actualBytes = graphiteHttpClient.getChart("hello.world", 300, 200, "-1hours", null, LegendState.SHOW, AxesState.SHOW, null, new BigDecimal("5.6")); + byte[] actualBytes = graphiteHttpClient.getChart(null,"hello.world", 300, 200, "-1hours", null, LegendState.SHOW, AxesState.SHOW, null, new BigDecimal("5.6")); assertThat(actualBytes, is(bytes)); } @@ -248,10 +254,10 @@ public void gettingChartFromGraphiteIsHandledWhenBothThresholdsAreProvided() thr .withParam("target", "alias(dashed(color(constantLine(5.6),\"red\")),\"error level\")"), giveResponseAsBytes(response, "image/png")); - byte[] actualBytes = graphiteHttpClient.getChart("hello.world", 300, 200, "-1hours", null, LegendState.SHOW, AxesState.SHOW, new BigDecimal("3.2"), new BigDecimal("5.6")); + byte[] actualBytes = graphiteHttpClient.getChart(null,"hello.world", 300, 200, "-1hours", null, LegendState.SHOW, AxesState.SHOW, new BigDecimal("3.2"), new BigDecimal("5.6")); assertThat(actualBytes, is(bytes)); - } + } @Test public void authIsUsedGettingChartFromGraphite() throws Exception { @@ -274,13 +280,13 @@ public void authIsUsedGettingChartFromGraphite() throws Exception { .withHeader("Authorization", "Basic c2V5cmVuOnMzeXIzTg=="), giveResponseAsBytes(response, "image/png")); - byte[] actualBytes = graphiteHttpClient.getChart("hello.world", 300, 200, "-1hours", null, LegendState.SHOW, AxesState.SHOW); + byte[] actualBytes = graphiteHttpClient.getChart(null,"hello.world", 300, 200, "-1hours", null, LegendState.SHOW, AxesState.SHOW); assertThat(actualBytes, is(bytes)); System.clearProperty("GRAPHITE_USERNAME"); System.clearProperty("GRAPHITE_PASSWORD"); - } + } private SeyrenConfig seyrenConfig(String graphiteUrl) { System.setProperty("GRAPHITE_URL", graphiteUrl); diff --git a/seyren-integration-tests/src/test/e2e/scenarios.js b/seyren-integration-tests/src/test/e2e/scenarios.js index 0d1f66f3..b57a3525 100644 --- a/seyren-integration-tests/src/test/e2e/scenarios.js +++ b/seyren-integration-tests/src/test/e2e/scenarios.js @@ -23,7 +23,7 @@ describe('home page', function () { expect(element('table:eq(0) thead tr th:eq(4)').text()).toBe('Enabled'); expect(element('table:eq(0) tbody tr').count()).toBe(1); - expect(element('table:eq(0) tbody tr td:eq(0) a').text()).toBe('load longterm usage'); + expect(element('table:eq(0) tbody tr td:eq(0)').text()).toBe('load longterm usage'); expect(element('table:eq(0) tbody tr td:eq(1) span:visible').text()).toBe('WARN'); expect(element('table:eq(0) tbody tr td:eq(2)').text()).toBe('0.5'); expect(element('table:eq(0) tbody tr td:eq(3)').text()).toBe('2.0'); @@ -48,7 +48,7 @@ describe('home page', function () { expect(element('table:eq(1) tbody tr').count()).toBe(1); expect(element('table:eq(1) tbody tr td:eq(0)').text()).toMatch('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}'); expect(element('table:eq(1) tbody tr td:eq(1)').text()).toMatch('^.*ago$'); - expect(element('table:eq(1) tbody tr td:eq(2) a').text()).toBe('load longterm usage'); + expect(element('table:eq(1) tbody tr td:eq(2)').text()).toBe('load longterm usage'); expect(element('table:eq(1) tbody tr td:eq(3)').text()).toBe('0.8'); expect(element('table:eq(1) tbody tr td:eq(4)').text()).toBe('0.5'); expect(element('table:eq(1) tbody tr td:eq(5)').text()).toBe('2'); @@ -129,7 +129,7 @@ describe('check page', function () { }); it('should have a \'Details\' informations', function () { - expect(element('div.col-lg-6 div.col-lg-10').count()).toBe(12); + expect(element('div.col-lg-6 div.col-lg-10').count()).toBe(13); expect(element('div.col-lg-6 div.detail-form:eq(0) label').text()).toBe('Name:'); expect(element('div.col-lg-6 div.detail-form:eq(0) p').text()).toBe('load longterm usage'); @@ -139,33 +139,36 @@ describe('check page', function () { expect(element('div.col-lg-6 div.detail-form:eq(2) label').text()).toBe('State:'); expect(element('div.col-lg-6 div.detail-form:eq(2) p span:visible').text()).toBe('WARN'); + + expect(element('div.col-lg-6 div.detail-form:eq(3) label').text()).toBe('Graphite source:'); + expect(element('div.col-lg-6 div.detail-form:eq(3) p').text()).toBe(''); - expect(element('div.col-lg-6 div.detail-form:eq(3) label').text()).toBe('Target:'); - expect(element('div.col-lg-6 div.detail-form:eq(3) p').text()).toBe('prod.host1.load.longterm'); - - expect(element('div.col-lg-6 div.detail-form:eq(4) label').text()).toBe('From:'); - expect(element('div.col-lg-6 div.detail-form:eq(4) p').text()).toBe(''); + expect(element('div.col-lg-6 div.detail-form:eq(4) label').text()).toBe('Target:'); + expect(element('div.col-lg-6 div.detail-form:eq(4) p').text()).toBe('prod.host1.load.longterm'); - expect(element('div.col-lg-6 div.detail-form:eq(5) label').text()).toBe('Until:'); + expect(element('div.col-lg-6 div.detail-form:eq(5) label').text()).toBe('From:'); expect(element('div.col-lg-6 div.detail-form:eq(5) p').text()).toBe(''); - expect(element('div.col-lg-6 div.detail-form:eq(6) label').text()).toBe('Warn:'); - expect(element('div.col-lg-6 div.detail-form:eq(6) p').text()).toBe('0.5'); + expect(element('div.col-lg-6 div.detail-form:eq(6) label').text()).toBe('Until:'); + expect(element('div.col-lg-6 div.detail-form:eq(6) p').text()).toBe(''); - expect(element('div.col-lg-6 div.detail-form:eq(7) label').text()).toBe('Error:'); - expect(element('div.col-lg-6 div.detail-form:eq(7) p').text()).toBe('2.0'); + expect(element('div.col-lg-6 div.detail-form:eq(7) label').text()).toBe('Warn:'); + expect(element('div.col-lg-6 div.detail-form:eq(7) p').text()).toBe('0.5'); - expect(element('div.col-lg-6 div.detail-form:eq(8) label').text()).toBe('Enabled:'); - expect(element('div.col-lg-6 div.detail-form:eq(8) p input:checked').val()).toBe('on'); + expect(element('div.col-lg-6 div.detail-form:eq(8) label').text()).toBe('Error:'); + expect(element('div.col-lg-6 div.detail-form:eq(8) p').text()).toBe('2.0'); - expect(element('div.col-lg-6 div.detail-form:eq(9) label').text()).toBe('Live:'); - expect(element('div.col-lg-6 div.detail-form:eq(9) p input:not(:checked)').val()).toBe('on'); + expect(element('div.col-lg-6 div.detail-form:eq(9) label').text()).toBe('Enabled:'); + expect(element('div.col-lg-6 div.detail-form:eq(9) p input:checked').val()).toBe('on'); - expect(element('div.col-lg-6 div.detail-form:eq(10) label').text()).toBe('Allow no data:'); + expect(element('div.col-lg-6 div.detail-form:eq(10) label').text()).toBe('Live:'); expect(element('div.col-lg-6 div.detail-form:eq(10) p input:not(:checked)').val()).toBe('on'); - expect(element('div.col-lg-6 div.detail-form:eq(11) label').text()).toBe('Last check:'); - expect(element('div.col-lg-6 div.detail-form:eq(11) p').text()).toMatch('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}'); + expect(element('div.col-lg-6 div.detail-form:eq(11) label').text()).toBe('Allow no data:'); + expect(element('div.col-lg-6 div.detail-form:eq(11) p input:not(:checked)').val()).toBe('on'); + + expect(element('div.col-lg-6 div.detail-form:eq(12) label').text()).toBe('Last check:'); + expect(element('div.col-lg-6 div.detail-form:eq(12) p').text()).toMatch('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}'); }); it('should have \'Graphs\' thumbnail', function () { @@ -220,7 +223,7 @@ describe('edit check', function () { }); it('edit and submit check', function () { - expect(element('div.col-lg-6 div.col-lg-10').count()).toBe(12); + expect(element('div.col-lg-6 div.col-lg-10').count()).toBe(13); expect(element('a:contains("edit")').count()).toBe(1); expect(element('div#editCheckModal:visible').count()).toBe(0); diff --git a/seyren-integration-tests/src/test/resources/com/seyren/integrationtests/mongo/checks/checks_1.json b/seyren-integration-tests/src/test/resources/com/seyren/integrationtests/mongo/checks/checks_1.json index 31d4ac79..71c3f5af 100644 --- a/seyren-integration-tests/src/test/resources/com/seyren/integrationtests/mongo/checks/checks_1.json +++ b/seyren-integration-tests/src/test/resources/com/seyren/integrationtests/mongo/checks/checks_1.json @@ -1,12 +1,13 @@ { "_id" : "5205121fccf2a07eacba64da", - name: "load longterm usage", - description: "Load longterm of host host1", - target: "prod.host1.load.longterm", - warn: "0.5", - error: "2.0", - enabled: true, - state: "WARN", + "name": "load longterm usage", + "description": "Load longterm of host host1", + "target": "prod.host1.load.longterm", + "warn": "0.5", + "error": "2.0", + "enabled": true, + "state": "WARN", + "graphiteSourceUrl": "", "lastCheck": { "$date": "2013-07-12T10:10:00.000Z"}, - subscriptions: [ ] + "subscriptions": [ ] } \ No newline at end of file diff --git a/seyren-mongo/pom.xml b/seyren-mongo/pom.xml index e845cc6f..78a64fc3 100755 --- a/seyren-mongo/pom.xml +++ b/seyren-mongo/pom.xml @@ -35,7 +35,30 @@ org.mongodb mongo-java-driver - + + javax.inject + javax.inject + 1 + jar + + + commons-lang + commons-lang + 2.6 + jar + + + joda-time + joda-time + 2.6 + jar + + + org.slf4j + slf4j-api + 1.7.9 + jar + diff --git a/seyren-mongo/src/main/java/com/seyren/mongo/MongoMapper.java b/seyren-mongo/src/main/java/com/seyren/mongo/MongoMapper.java index f4f7e1cd..d1647cab 100644 --- a/seyren-mongo/src/main/java/com/seyren/mongo/MongoMapper.java +++ b/seyren-mongo/src/main/java/com/seyren/mongo/MongoMapper.java @@ -55,6 +55,7 @@ public Check checkFrom(DBObject dbo) { for (Object o : list) { subscriptions.add(subscriptionFrom((DBObject) o)); } + String graphiteSourceUrl = getString(dbo, "graphiteSourceUrl"); return new Check().withId(id) .withName(name) @@ -69,7 +70,8 @@ public Check checkFrom(DBObject dbo) { .withAllowNoData(allowNoData) .withState(state) .withLastCheck(lastCheck) - .withSubscriptions(subscriptions); + .withSubscriptions(subscriptions) + .withGraphiteSourceUrl(graphiteSourceUrl); } public Subscription subscriptionFrom(DBObject dbo) { @@ -178,6 +180,7 @@ private Map propertiesToMap(Check check) { map.put("subscriptions", dbSubscriptions); } + map.put("graphiteSourceUrl",check.getGraphiteSourceUrl()); return map; } diff --git a/seyren-mongo/src/main/java/com/seyren/mongo/MongoStore.java b/seyren-mongo/src/main/java/com/seyren/mongo/MongoStore.java index 34adbdae..419374ca 100644 --- a/seyren-mongo/src/main/java/com/seyren/mongo/MongoStore.java +++ b/seyren-mongo/src/main/java/com/seyren/mongo/MongoStore.java @@ -246,7 +246,8 @@ public Check saveCheck(Check check) { .with("live", check.isLive()) .with("allowNoData", check.isAllowNoData()) .with("lastCheck", lastCheck == null ? null : new Date(lastCheck.getMillis())) - .with("state", check.getState().toString()); + .with("state", check.getState().toString()) + .with("graphiteSourceUrl", check.getGraphiteSourceUrl()); DBObject setObject = object("$set", partialObject); @@ -356,5 +357,4 @@ public void updateSubscription(String checkId, Subscription subscription) { DBObject updateObject = object("$set", object("subscriptions.$", subscriptionObject)); getChecksCollection().update(checkFindObject, updateObject); } - } diff --git a/seyren-web/src/main/webapp/html/check.html b/seyren-web/src/main/webapp/html/check.html index bc1f9232..9d7eea3a 100644 --- a/seyren-web/src/main/webapp/html/check.html +++ b/seyren-web/src/main/webapp/html/check.html @@ -42,6 +42,12 @@

Details [ +
+ +
+

{{check.graphiteSourceUrl}}

+
+
diff --git a/seyren-web/src/main/webapp/html/home.html b/seyren-web/src/main/webapp/html/home.html index 31858ee3..b9b79d0f 100755 --- a/seyren-web/src/main/webapp/html/home.html +++ b/seyren-web/src/main/webapp/html/home.html @@ -13,9 +13,7 @@

Checks in an unhealthy state

- -
{{ check.name }} - + {{ check.name }} {{ check.state }} {{ check.state }} @@ -25,7 +23,7 @@

Checks in an unhealthy state

{{ check.warn }} {{ check.error }} - + @@ -51,9 +49,7 @@

Recent alerts

{{ alert.timestamp | date: 'yyyy-MM-dd HH:mm:ss' }} - - {{ checkNames[alert.checkId] }} - + {{ checkNames[alert.checkId] }} {{ alert.value }} {{ alert.warn }} {{ alert.error }} diff --git a/seyren-web/src/main/webapp/html/modal-partial-check.html b/seyren-web/src/main/webapp/html/modal-partial-check.html index 55366a8d..f843013a 100644 --- a/seyren-web/src/main/webapp/html/modal-partial-check.html +++ b/seyren-web/src/main/webapp/html/modal-partial-check.html @@ -20,6 +20,15 @@
+
+ +
+ +
+
+ +
+
diff --git a/seyren-web/src/main/webapp/js/check-edit-controller.js b/seyren-web/src/main/webapp/js/check-edit-controller.js index 9b64224b..389b282f 100644 --- a/seyren-web/src/main/webapp/js/check-edit-controller.js +++ b/seyren-web/src/main/webapp/js/check-edit-controller.js @@ -13,7 +13,8 @@ enabled: true, live: false, allowNoData: false, - totalMetric: '-' + totalMetric: '-', + graphiteSourceUrl: null }; $('#editCheckModal').on('shown.bs.modal', function () { @@ -22,6 +23,10 @@ placement: 'right', title: 'Setting your warn level higher than your error level will result in Seyren generating alerts when the target value goes below the threshold.' }); + $('#check\\.graphiteSourceUrl\\.hint').tooltip({ + placement: 'right', + title: 'In this field you can define a different graphite source than the default.' + }); }); $scope.create = function () { @@ -70,7 +75,6 @@ } }); - $scope.$watch('check.target', function(value) { if (value) { Metrics.totalMetric({target: value}, function (data) { @@ -81,7 +85,5 @@ }); } }); - }); - }()); diff --git a/seyren-web/src/main/webapp/js/home-controller.js b/seyren-web/src/main/webapp/js/home-controller.js index 1e3ed788..4f81d3ed 100755 --- a/seyren-web/src/main/webapp/js/home-controller.js +++ b/seyren-web/src/main/webapp/js/home-controller.js @@ -2,7 +2,7 @@ (function () { 'use strict'; - seyrenApp.controller('HomeController', function HomeController($scope, $rootScope, $location, Checks, Alerts, Seyren) { + seyrenApp.controller('HomeController', function HomeController($scope, $rootScope, $location, Checks, Alerts) { $scope.pollAlertsInSeconds = 5; $scope.checkNames = {}; @@ -45,10 +45,6 @@ }); }; - $scope.swapCheckEnabled = function (check) { - Seyren.swapCheckEnabled(check); - }; - $scope.countdownToRefresh = function () { $scope.loadUnhealthyChecks(); $scope.loadAlertStream(); diff --git a/seyren-web/src/main/webapp/js/services.js b/seyren-web/src/main/webapp/js/services.js index f541c467..cf24116a 100644 --- a/seyren-web/src/main/webapp/js/services.js +++ b/seyren-web/src/main/webapp/js/services.js @@ -92,6 +92,10 @@ if (chart.uniq) { result += '&uniq=' + chart.uniq; } + if (chart.graphiteSourceUrl) { + result += '&graphiteSourceUrl=' + chart.graphiteSourceUrl; + } + return result; }; return { @@ -103,7 +107,8 @@ height: 70, warn: check.warn, error: check.error, - hideLegend: true + hideLegend: true, + graphiteSourceUrl: check.graphiteSourceUrl }); } },