package com.thinkbiganalytics.servicemonitor.model; /*- * #%L * thinkbig-service-monitor-core * %% * Copyright (C) 2017 ThinkBig Analytics * %% * 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. * #L% */ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; /** * The Default ServiceComponent and Builder for Service health notifications. * * This is used by the Kylo UI to display health about components in within a service */ @JsonIgnoreProperties(ignoreUnknown = true) public class DefaultServiceComponent implements ServiceComponent { private String clusterName; private String serviceName; private String name; private boolean healthy; private String message; private Date checkDate; private List<ServiceAlert> alerts; private List<ServiceAlert> errorAlerts; private boolean containsErrorAlerts; private Map<String, Object> properties; private STATE state; private ServiceAlert.STATE maxAlertState; public DefaultServiceComponent(Builder builder) { this.clusterName = builder.clusterName; this.serviceName = builder.serviceName; this.name = builder.name; this.healthy = builder.healthy; this.message = builder.message; this.checkDate = new Date(); this.properties = builder.properties; this.alerts = builder.alerts; this.state = builder.state; this.errorAlerts = this.getErrorAlerts(); this.containsErrorAlerts = (errorAlerts != null && !errorAlerts.isEmpty()); this.maxAlertState = getHighestAlertState(); } public DefaultServiceAlert.STATE getHighestAlertState() { DefaultServiceAlert.STATE maxState = null; if (this.alerts != null) { for (ServiceAlert alert : alerts) { if (alert.getState().isError()) { if (maxState == null) { maxState = alert.getState(); } else { if (alert.getState().getSeverity() > maxState.getSeverity()) { maxState = alert.getState(); } } } } } return maxState; } public Map<String, Object> getProperties() { return properties; } public String getServiceName() { return serviceName; } public void setServiceName(String serviceName) { this.serviceName = serviceName; } public String getName() { return name; } public boolean isHealthy() { return healthy; } public Date getCheckDate() { return checkDate; } public String getMessage() { return message; } public STATE getState() { return state; } public List<ServiceAlert> getAlerts() { return alerts; } public boolean isContainsErrorAlerts() { return containsErrorAlerts; } public String getClusterName() { return clusterName; } public List<ServiceAlert> getErrorAlerts() { boolean hasErrors = false; if (alerts != null && !alerts.isEmpty()) { Predicate<ServiceAlert> predicate = new Predicate<ServiceAlert>() { @Override public boolean apply(ServiceAlert alert) { return alert.getState().isError(); } }; Collection<ServiceAlert> matchingAlerts = Collections2.filter(alerts, predicate); if (matchingAlerts != null && !matchingAlerts.isEmpty()) { return new ArrayList<ServiceAlert>(matchingAlerts); } } return null; } private Date getEarliestOrLatestAlertTimestamp(TIMESTAMP_TYPE timestampType, boolean onlyErrors) { ServiceAlert latestAlert = null; Date latestTime = null; List<ServiceAlert> alerts = getAlerts(); if (alerts != null) { for (ServiceAlert alert : alerts) { Date time = alert.getLatestTimestamp(); if (time != null && ((onlyErrors && alert.getState().isError()) || !onlyErrors) && (latestTime == null || ( timestampType.equals(TIMESTAMP_TYPE.LATEST) && latestTime != null && time.after(latestTime)) || (timestampType .equals(TIMESTAMP_TYPE.EARLIEST) && latestTime != null && time .before(latestTime)))) { latestAlert = alert; latestTime = time; } } } return latestTime; } public Date getLatestAlertTimestamp() { Date date = null; if (this.containsErrorAlerts) { date = getEarliestOrLatestAlertTimestamp(TIMESTAMP_TYPE.LATEST, true); } else { date = getEarliestOrLatestAlertTimestamp(TIMESTAMP_TYPE.LATEST, false); } return date; } public Date getEarliestAlertTimestamp() { Date date = null; if (this.containsErrorAlerts) { date = getEarliestOrLatestAlertTimestamp(TIMESTAMP_TYPE.EARLIEST, true); } else { date = getEarliestOrLatestAlertTimestamp(TIMESTAMP_TYPE.EARLIEST, false); } return date; } public DefaultServiceAlert.STATE getMaxAlertState() { return maxAlertState; } /** * The builder to help create {@link ServiceComponent} objects */ public static class Builder { private String clusterName = ServiceComponent.DEFAULT_CLUSTER; private String serviceName; private String name; private boolean healthy = true; private String message; private List<ServiceAlert> alerts; private Map<String, Object> properties; private STATE state; public Builder(String clusterName, String serviceName, String componentName, STATE state) { this.clusterName = clusterName; this.serviceName = serviceName; this.name = componentName; this.state = state; } public Builder(String componentName, STATE state) { this.name = componentName; this.state = state; } public Builder serviceName(String serviceName) { this.serviceName = serviceName; return this; } public Builder clusterName(String clusterName) { this.clusterName = clusterName; return this; } public Builder message(String message) { this.message = message; return this; } public Builder properties(Map<String, Object> properties) { if (this.properties == null) { this.properties = new HashMap<>(); } this.properties.putAll(properties); return this; } public Builder alerts(List<ServiceAlert> alerts) { this.alerts = alerts; if (this.alerts != null) { for (ServiceAlert alert : alerts) { if (alert.getState().isError()) { this.healthy = false; } } } return this; } private DefaultServiceAlert generateAlert(String label, String message, Date time) { DefaultServiceAlert alert = new DefaultServiceAlert(); alert.setComponentName(this.name); alert.setServiceName(this.serviceName); alert.setLatestTimestamp(time); alert.setLabel(label); alert.setMessage(message); return alert; } /** * Add a warning alert */ public Builder addWarningAlert(String label, String message, Date time) { DefaultServiceAlert alert = generateAlert(label, message, time); alert.setState(ServiceAlert.STATE.WARNING); return addAlert(alert); } /** * add a message alert */ public Builder addMessageAlert(String label, String message, Date time) { DefaultServiceAlert alert = generateAlert(label, message, time); alert.setState(ServiceAlert.STATE.OK); return addAlert(alert); } /** * add a critical alert */ public Builder addErrorAlert(String label, String message, Date time) { DefaultServiceAlert alert = generateAlert(label, message, time); alert.setState(ServiceAlert.STATE.CRITICAL); return addAlert(alert); } public Builder addAlert(ServiceAlert alert) { if(alert != null) { if (this.alerts == null) { this.alerts = new ArrayList<>(); } this.alerts.add(alert); } return this; } public Builder property(String key, Object value) { if (this.properties == null) { this.properties = new HashMap<>(); } this.properties.put(key, value); return this; } public Builder exception(Throwable e) { this.message = e.getMessage(); this.healthy = false; return this; } public ServiceComponent build() { if (this.healthy) { this.healthy = state.isHealthy(); } ServiceComponent health = new DefaultServiceComponent(this); return health; } } }