Skip to content

Commit

Permalink
Merge pull request #55 from jshaughn/jshaughn/severity
Browse files Browse the repository at this point in the history
Jshaughn/severity
  • Loading branch information
jshaughn committed Jun 5, 2015
2 parents 8dee6bc + bc52911 commit 8949597
Show file tree
Hide file tree
Showing 19 changed files with 301 additions and 65 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hawkular.alerts.api.model;

/**
* Severity set for a {@link org.hawkular.alerts.api.model.trigger.Trigger} and assigned to an
* {@link org.hawkular.alerts.api.model.condition.Alert} it generates.
*
* @author jay shaughnessy
* @author lucac ponce
*/
public enum Severity {
LOW, MEDIUM, HIGH, CRITICAL
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import java.util.List;
import java.util.Set;

import org.hawkular.alerts.api.model.Severity;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;

Expand Down Expand Up @@ -63,6 +65,9 @@ public enum Status {
@Thin
private List<Set<ConditionEval>> evalSets;

@JsonInclude
private Severity severity;

@JsonInclude
private Status status;

Expand Down Expand Up @@ -92,9 +97,10 @@ public Alert() {
// for json assembly
}

public Alert(String tenantId, String triggerId, List<Set<ConditionEval>> evalSets) {
public Alert(String tenantId, String triggerId, Severity severity, List<Set<ConditionEval>> evalSets) {
this.tenantId = tenantId;
this.triggerId = triggerId;
this.severity = (null == severity) ? Severity.MEDIUM : severity;
this.evalSets = evalSets;
this.ctime = System.currentTimeMillis();
this.status = Status.OPEN;
Expand Down Expand Up @@ -142,6 +148,14 @@ public void setTriggerId(String triggerId) {
this.triggerId = triggerId;
}

public Severity getSeverity() {
return severity;
}

public void setSeverity(Severity severity) {
this.severity = severity;
}

public Status getStatus() {
return status;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.Map;
import java.util.Set;

import org.hawkular.alerts.api.model.Severity;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;

Expand Down Expand Up @@ -51,6 +53,9 @@ public enum Match {
@JsonInclude
private boolean autoResolveAlerts;

@JsonInclude
private Severity severity;

/** A map with key based on actionPlugin and value a set of action's ids */
@JsonInclude(Include.NON_EMPTY)
private Map<String, Set<String>> actions;
Expand All @@ -67,6 +72,7 @@ public TriggerTemplate(String name) {
this.autoDisable = false;
this.autoResolve = false;
this.autoResolveAlerts = true;
this.severity = Severity.MEDIUM;
this.firingMatch = Match.ALL;
this.autoResolveMatch = Match.ALL;
this.actions = new HashMap<>();
Expand Down Expand Up @@ -115,6 +121,14 @@ public void setAutoResolveAlerts(boolean autoResolveAlerts) {
this.autoResolveAlerts = autoResolveAlerts;
}

public Severity getSeverity() {
return severity;
}

public void setSeverity(Severity severity) {
this.severity = severity;
}

public Match getFiringMatch() {
return firingMatch;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@

import java.util.Collection;

import org.hawkular.alerts.api.model.Severity;
import org.hawkular.alerts.api.model.condition.Alert;
import org.hawkular.alerts.api.model.trigger.Tag;

/**
* Query criteria for fetching Alerts.
* TODO: paging, sorting
* @author jay shaughnessy
* @author lucas ponce
*/
Expand All @@ -34,6 +34,8 @@ public class AlertsCriteria {
Collection<String> alertIds = null;
Alert.Status status = null;
Collection<Alert.Status> statusSet = null;
Severity severity = null;
Collection<Severity> severities = null;
String triggerId = null;
Collection<String> triggerIds = null;
Tag tag = null;
Expand Down Expand Up @@ -142,6 +144,22 @@ public void setTags(Collection<Tag> tags) {
this.tags = tags;
}

public Severity getSeverity() {
return severity;
}

public void setSeverity(Severity severity) {
this.severity = severity;
}

public Collection<Severity> getSeverities() {
return severities;
}

public void setSeverities(Collection<Severity> severities) {
this.severities = severities;
}

public boolean isThin() {
return thin;
}
Expand All @@ -151,23 +169,25 @@ public void setThin(boolean thin) {
}

public boolean hasCriteria() {
return null != startTime || //
null != endTime || //
null != triggerId || //
(null != triggerIds && !triggerIds.isEmpty()) || //
null != alertId || //
(null != alertIds && !alertIds.isEmpty()) || //
null != tag || //
(null != tags && !tags.isEmpty()) ||
null != status ||
(null != statusSet && !statusSet.isEmpty());
return null != startTime //
|| null != endTime
|| null != status
|| null != severity
|| null != triggerId
|| null != alertId
|| null != tag
|| (null != statusSet && !statusSet.isEmpty())
|| (null != severities && !severities.isEmpty())
|| (null != triggerIds && !triggerIds.isEmpty())
|| (null != alertIds && !alertIds.isEmpty())
|| (null != tags && !tags.isEmpty());
}

@Override
public String toString() {
return "AlertsCriteria [startTime=" + startTime + ", endTime=" + endTime + ", alertId=" + alertId
+ ", alertIds=" + alertIds + ", status=" + status + ", statusSet=" + statusSet + ", triggerId="
+ triggerId + ", triggerIds=" + triggerIds + ", tag=" + tag + ", tags=" + tags + ", thin=" + thin
+ "]";
+ ", alertIds=" + alertIds + ", status=" + status + ", statusSet=" + statusSet + ", severity="
+ severity + ", severities=" + severities + ", triggerId=" + triggerId + ", triggerIds=" + triggerIds
+ ", tag=" + tag + ", tags=" + tags + ", thin=" + thin + "]";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hawkular.alerts.api.model.Severity;
import org.hawkular.alerts.api.model.action.Action;
import org.hawkular.alerts.api.model.condition.Alert;
import org.hawkular.alerts.api.model.condition.AvailabilityCondition;
Expand All @@ -52,6 +52,7 @@
import org.junit.Test;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;

/**
* Validation of JSON serialization/deserialization
Expand Down Expand Up @@ -93,7 +94,7 @@ public void jsonActionTest() throws Exception {

@Test
public void jsonAlertTest() throws Exception {
Alert alert = new Alert(TEST_TENANT, "trigger-test", null);
Alert alert = new Alert(TEST_TENANT, "trigger-test", Severity.MEDIUM, null);

String output = objectMapper.writeValueAsString(alert);

Expand Down Expand Up @@ -734,7 +735,8 @@ public void jsonTriggerTest() throws Exception {
"\"enabled\":true," +
"\"autoDisable\":true," +
"\"autoResolve\":true," +
"\"autoResolveAlerts\":true}";
"\"autoResolveAlerts\":true," +
"\"severity\":\"HIGH\"}";
Trigger trigger = objectMapper.readValue(str, Trigger.class);

assertTrue(trigger.getName().equals("test-name"));
Expand All @@ -748,6 +750,7 @@ public void jsonTriggerTest() throws Exception {
assertTrue(trigger.isAutoDisable());
assertTrue(trigger.isAutoResolve());
assertTrue(trigger.isAutoResolveAlerts());
assertTrue(trigger.getSeverity() == Severity.HIGH);

String output = objectMapper.writeValueAsString(trigger);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import javax.ejb.EJB;
import javax.ejb.Stateless;

import org.hawkular.alerts.api.model.Severity;
import org.hawkular.alerts.api.model.condition.Alert;
import org.hawkular.alerts.api.model.condition.ConditionEval;
import org.hawkular.alerts.api.model.data.Data;
Expand Down Expand Up @@ -120,6 +121,7 @@ public void addAlerts(Collection<Alert> alerts) throws Exception {
PreparedStatement insertAlertTrigger = CassStatement.get(session, CassStatement.INSERT_ALERT_TRIGGER);
PreparedStatement insertAlertCtime = CassStatement.get(session, CassStatement.INSERT_ALERT_CTIME);
PreparedStatement insertAlertStatus = CassStatement.get(session, CassStatement.INSERT_ALERT_STATUS);
PreparedStatement insertAlertSeverity = CassStatement.get(session, CassStatement.INSERT_ALERT_SEVERITY);
try {
List<ResultSetFuture> futures = new ArrayList<>();
alerts.stream()
Expand All @@ -134,6 +136,9 @@ public void addAlerts(Collection<Alert> alerts) throws Exception {
futures.add(session.executeAsync(insertAlertStatus.bind(a.getTenantId(),
a.getAlertId(),
a.getStatus().name())));
futures.add(session.executeAsync(insertAlertSeverity.bind(a.getTenantId(),
a.getAlertId(),
a.getSeverity().name())));
});
/*
main method is synchronous so we need to wait until futures are completed
Expand All @@ -145,6 +150,16 @@ public void addAlerts(Collection<Alert> alerts) throws Exception {
}
}

// TODO (jshaughn) The DB-Level filtering approach implemented below is a best-practice for dealing
// with Cassandra. It's basically a series of queries, one for each filter, with a progressive
// intersection of the resulting ID set. This will work well in most cases but we may want to consider
// an optimization for dealing with large Alert populations. Certain filters dealing with low-cardinality
// values, like status and severity, could start pulling a large number if alert ids. If we have reduced the
// result set to a small number, via the more narrowing filters, (TBD via perf tests, a threshold that makes
// sense), we may want to pull the resulting alerts and apply the low-cardinality filters here in the code,
// in a post-fetch step. For example, if we have filters "ctime > 123" and "status == Resolved", and the ctime
// filter returns 10 alertIds. We may want to pull the 10 alerts and apply the status filter in the code. For
// large Alert history, the status filter applied to the DB could return a huge set of ids.
@Override
public List<Alert> getAlerts(String tenantId, AlertsCriteria criteria) throws Exception {
if (isEmpty(tenantId)) {
Expand Down Expand Up @@ -206,6 +221,22 @@ public List<Alert> getAlerts(String tenantId, AlertsCriteria criteria) throws Ex
}
}

/*
Get alertsIds filtered by severities clause
*/
Set<String> alertIdsFilteredBySeverity = new HashSet<>();
boolean filterBySeverity = filterBySeverities(tenantId, alertIdsFilteredBySeverity, criteria);
if (filterBySeverity) {
if (alertIds.isEmpty()) {
alertIds.addAll(alertIdsFilteredBySeverity);
} else {
alertIds.retainAll(alertIdsFilteredBySeverity);
}
if (alertIds.isEmpty()) {
return alerts;
}
}

/*
Get alertsIds filtered by statuses clause
*/
Expand All @@ -217,6 +248,7 @@ public List<Alert> getAlerts(String tenantId, AlertsCriteria criteria) throws Ex
} else {
alertIds.retainAll(alertIdsFilteredByStatus);
}

if (alertIds.isEmpty()) {
return alerts;
}
Expand Down Expand Up @@ -417,6 +449,44 @@ private boolean filterByStatuses(String tenantId, Set<String> alertsId, AlertsCr
return filterByStatus;
}

private boolean filterBySeverities(String tenantId, Set<String> alertsId, AlertsCriteria criteria)
throws Exception {
boolean filterBySeverity = false;
Set<Severity> severities = new HashSet<>();
if (isEmpty(criteria.getSeverities())) {
if (criteria.getSeverity() != null) {
severities.add(criteria.getSeverity());
}
} else {
severities.addAll(criteria.getSeverities());
}

if (severities.size() > 0) {
filterBySeverity = true;
PreparedStatement selectAlertSeverityByTenantAndSeverity = CassStatement.get(session,
CassStatement.SELECT_ALERT_SEVERITY_BY_TENANT_AND_SEVERITY);
List<ResultSetFuture> futures = severities.stream().map(severity ->
session.executeAsync(selectAlertSeverityByTenantAndSeverity.bind(tenantId, severity.name())))
.collect(Collectors.toList());

List<ResultSet> rsAlertSeverities = Futures.allAsList(futures).get();
rsAlertSeverities.stream().forEach(r -> {
for (Row row : r) {
String alertId = row.getString("alertId");
alertsId.add(alertId);
}
});
/*
If there is not alertId but we have triggersId means that we have an empty result.
So we need to sure a alertId to mark that we have an empty result for future joins.
*/
if (alertsId.isEmpty()) {
alertsId.add("no-result-fake-alert-id");
}
}
return filterBySeverity;
}

private boolean filterByAlerts(Set<String> alertsId, AlertsCriteria criteria) {
boolean filterByAlerts = false;
if (isEmpty(criteria.getAlertIds())) {
Expand Down Expand Up @@ -607,5 +677,4 @@ private boolean isEmpty(Collection<?> c) {
private boolean isEmpty(String s) {
return null == s || s.trim().isEmpty();
}

}

0 comments on commit 8949597

Please sign in to comment.