/*
* RHQ Management Platform
* Copyright (C) 2005-2008 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.enterprise.server.alert.engine.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.rhq.core.domain.alert.AlertCondition;
import org.rhq.core.domain.alert.AlertConditionCategory;
import org.rhq.core.domain.alert.AlertConditionOperator;
import org.rhq.core.domain.alert.composite.AbstractAlertConditionCategoryComposite;
import org.rhq.core.domain.alert.composite.AlertConditionBaselineCategoryComposite;
import org.rhq.core.domain.alert.composite.AlertConditionChangesCategoryComposite;
import org.rhq.core.domain.alert.composite.AlertConditionDriftCategoryComposite;
import org.rhq.core.domain.alert.composite.AlertConditionEventCategoryComposite;
import org.rhq.core.domain.alert.composite.AlertConditionRangeCategoryComposite;
import org.rhq.core.domain.alert.composite.AlertConditionScheduleCategoryComposite;
import org.rhq.core.domain.alert.composite.AlertConditionTraitCategoryComposite;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.event.Event;
import org.rhq.core.domain.event.EventSeverity;
import org.rhq.core.domain.event.EventSource;
import org.rhq.core.domain.measurement.DataType;
import org.rhq.core.domain.measurement.MeasurementData;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementDataTrait;
import org.rhq.core.domain.measurement.calltime.CallTimeData;
import org.rhq.core.domain.measurement.calltime.CallTimeDataValue;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.server.alert.AlertConditionManagerLocal;
import org.rhq.enterprise.server.alert.engine.AlertConditionCacheStats;
import org.rhq.enterprise.server.alert.engine.internal.AlertConditionCacheCoordinator.Cache;
import org.rhq.enterprise.server.alert.engine.mbean.AlertConditionCacheMonitor;
import org.rhq.enterprise.server.alert.engine.model.CallTimeDataCacheElement;
import org.rhq.enterprise.server.alert.engine.model.CallTimeDataCacheElement.CallTimeElementValue;
import org.rhq.enterprise.server.alert.engine.model.DriftCacheElement;
import org.rhq.enterprise.server.alert.engine.model.EventCacheElement;
import org.rhq.enterprise.server.alert.engine.model.InvalidCacheElementException;
import org.rhq.enterprise.server.alert.engine.model.MeasurementBaselineCacheElement;
import org.rhq.enterprise.server.alert.engine.model.MeasurementNumericCacheElement;
import org.rhq.enterprise.server.alert.engine.model.MeasurementRangeNumericCacheElement;
import org.rhq.enterprise.server.alert.engine.model.MeasurementTraitCacheElement;
import org.rhq.enterprise.server.alert.engine.model.NumericDoubleCacheElement;
import org.rhq.enterprise.server.auth.SubjectManagerLocal;
import org.rhq.enterprise.server.measurement.MeasurementDataManagerLocal;
import org.rhq.enterprise.server.plugin.pc.drift.DriftChangeSetSummary;
import org.rhq.enterprise.server.util.LookupUtil;
/**
* @author Joseph Marques
*/
class AgentConditionCache extends AbstractConditionCache {
private Map<Integer, List<NumericDoubleCacheElement>> measurementDataCache; // key: schedule ID
private Map<Integer, List<MeasurementTraitCacheElement>> measurementTraitCache; // key: schedule ID
private Map<Integer, List<CallTimeDataCacheElement>> callTimeCache; // key: schedule ID
private Map<Integer, List<EventCacheElement>> eventsCache; // key: resource ID
private Map<Integer, List<DriftCacheElement>> driftCache; // key: resource ID
private AlertConditionManagerLocal alertConditionManager;
private MeasurementDataManagerLocal measurementDataManager;
private SubjectManagerLocal subjectManager;
private int agentId;
public AgentConditionCache(int agentId) {
super();
this.agentId = agentId;
measurementDataCache = new HashMap<Integer, List<NumericDoubleCacheElement>>();
measurementTraitCache = new HashMap<Integer, List<MeasurementTraitCacheElement>>();
callTimeCache = new HashMap<Integer, List<CallTimeDataCacheElement>>();
eventsCache = new HashMap<Integer, List<EventCacheElement>>();
driftCache = new HashMap<Integer, List<DriftCacheElement>>();
alertConditionManager = LookupUtil.getAlertConditionManager();
measurementDataManager = LookupUtil.getMeasurementDataManager();
subjectManager = LookupUtil.getSubjectManager();
loadCachesForAgent(agentId);
}
/**
* This method is used to do the initial loading from the database for a particular agent. In the high availability
* infrastructure each server instance in the cloud will only be responsible for monitoring a select number of
* agents at any given point in time. When an agent makes a connection to this server instance, the caches for that
* agent will be loaded at that time.
*
* @return the number of conditions that re/loaded
*/
private AlertConditionCacheStats loadCachesForAgent(int agentId) {
AlertConditionCacheStats stats = new AlertConditionCacheStats();
try {
if (log.isDebugEnabled()) {
log.debug("Loading Alert Condition Caches for agent[id=" + agentId + "]...");
}
Subject overlord = subjectManager.getOverlord();
EnumSet<AlertConditionCategory> supportedCategories = EnumSet.of(AlertConditionCategory.BASELINE,
AlertConditionCategory.CHANGE, AlertConditionCategory.TRAIT, AlertConditionCategory.THRESHOLD,
AlertConditionCategory.EVENT, AlertConditionCategory.DRIFT, AlertConditionCategory.RANGE);
for (AlertConditionCategory nextCategory : supportedCategories) {
// page thru all alert definitions
int rowsProcessed = 0;
PageControl pc = new PageControl();
pc.setPageNumber(0);
pc.setPageSize(PAGE_SIZE); // condition composites are small so we can grab alot; use the setter, constructor limits this to 100
while (true) {
PageList<? extends AbstractAlertConditionCategoryComposite> alertConditions = null;
alertConditions = alertConditionManager.getAlertConditionComposites(overlord, agentId,
nextCategory, pc);
if (alertConditions.isEmpty()) {
break; // didn't get any rows back, must not have any data or no more rows left to process
}
for (AbstractAlertConditionCategoryComposite nextComposite : alertConditions) {
insertAlertConditionComposite(agentId, nextComposite, stats);
}
rowsProcessed += alertConditions.size();
if (rowsProcessed >= alertConditions.getTotalSize()) {
break; // we've processed all data, we can stop now
}
pc.setPageNumber(pc.getPageNumber() + 1);
}
if (log.isDebugEnabled()) {
log.debug("Loaded " + rowsProcessed + " Alert Condition Composites of type '" + nextCategory + "'");
}
}
if (log.isDebugEnabled()) {
log.debug("Loaded Alert Condition Caches for agent[id=" + agentId + "]");
}
} catch (Throwable t) {
// don't let any exceptions bubble up to the calling SLSB layer
log.error("Error loading cache for agent[id=" + agentId + "]", t);
}
return stats;
}
private void insertAlertConditionComposite(int agentId, AbstractAlertConditionCategoryComposite composite,
AlertConditionCacheStats stats) {
AlertCondition alertCondition = composite.getCondition();
int alertConditionId = alertCondition.getId(); // auto-unboxing is safe here because as the PK it's guaranteed to be non-null
AlertConditionCategory alertConditionCategory = alertCondition.getCategory();
AlertConditionOperator alertConditionOperator = AlertConditionCacheUtils
.getAlertConditionOperator(alertCondition);
if (DataType.CALLTIME == composite.getDataType()) { // call-time cases start here
if (alertConditionCategory == AlertConditionCategory.CHANGE) {
AlertConditionChangesCategoryComposite changesComposite = (AlertConditionChangesCategoryComposite) composite;
int scheduleId = changesComposite.getScheduleId();
try {
CallTimeDataCacheElement cacheElement = new CallTimeDataCacheElement(alertConditionOperator,
CallTimeElementValue.valueOf(alertCondition.getOption()), alertCondition.getComparator(),
alertCondition.getThreshold(), alertConditionId, alertCondition.getName());
addTo("callTimeDataCache", callTimeCache, scheduleId, cacheElement, alertConditionId, stats);
} catch (InvalidCacheElementException icee) {
log.info("Failed to create CallTimeDataCacheElement with parameters: "
+ AlertConditionCacheUtils.getCacheElementErrorString(alertConditionId, alertConditionOperator,
null, alertCondition.getThreshold(), icee));
}
} else if (alertConditionCategory == AlertConditionCategory.THRESHOLD) {
AlertConditionScheduleCategoryComposite thresholdComposite = (AlertConditionScheduleCategoryComposite) composite;
try {
CallTimeDataCacheElement cacheElement = new CallTimeDataCacheElement(alertConditionOperator,
CallTimeElementValue.valueOf(alertCondition.getOption()), null, alertCondition.getThreshold(),
alertConditionId, alertCondition.getName());
addTo("measurementDataCache", callTimeCache, thresholdComposite.getScheduleId(), cacheElement,
alertConditionId, stats);
} catch (InvalidCacheElementException icee) {
log.info("Failed to create CallTimeDataCacheElement with parameters: "
+ AlertConditionCacheUtils.getCacheElementErrorString(alertConditionId, alertConditionOperator,
null, alertCondition.getThreshold(), icee));
}
}// last call-time case
} else if (alertConditionCategory == AlertConditionCategory.BASELINE) { // normal cases start here
AlertConditionBaselineCategoryComposite baselineComposite = (AlertConditionBaselineCategoryComposite) composite;
// option status for baseline gets set to "mean", but it's rather useless since the UI
// current doesn't allow alerting off of other baseline properties such as "min" and "max"
Double threshold = alertCondition.getThreshold();
String optionStatus = alertCondition.getOption();
/*
* yes, calculatedValue may be null, but that's OK because the match
* method for MeasurementBaselineCacheElement handles nulls just fine
*/
Double calculatedValue = getCalculatedBaselineValue(alertConditionId, baselineComposite, optionStatus,
threshold);
try {
MeasurementBaselineCacheElement cacheElement = new MeasurementBaselineCacheElement(
alertConditionOperator, calculatedValue, alertConditionId, optionStatus);
// auto-boxing (of alertConditionId) is always safe
addTo("measurementDataCache", measurementDataCache, baselineComposite.getScheduleId(), cacheElement,
alertConditionId, stats);
} catch (InvalidCacheElementException icee) {
log.info("Failed to create MeasurementBaselineCacheElement with parameters: "
+ AlertConditionCacheUtils.getCacheElementErrorString(alertConditionId, alertConditionOperator,
null, calculatedValue, icee));
}
} else if (alertConditionCategory == AlertConditionCategory.CHANGE) {
AlertConditionChangesCategoryComposite changesComposite = (AlertConditionChangesCategoryComposite) composite;
int scheduleId = changesComposite.getScheduleId();
MeasurementDataNumeric numeric = measurementDataManager.getCurrentNumericForSchedule(scheduleId);
try {
MeasurementNumericCacheElement cacheElement = new MeasurementNumericCacheElement(
alertConditionOperator, (numeric == null) ? null : numeric.getValue(), alertConditionId);
addTo("measurementDataCache", measurementDataCache, scheduleId, cacheElement, alertConditionId, stats);
} catch (InvalidCacheElementException icee) {
log.info("Failed to create MeasurementNumericCacheElement with parameters: "
+ AlertConditionCacheUtils.getCacheElementErrorString(alertConditionId, alertConditionOperator,
null, numeric, icee));
}
} else if (alertConditionCategory == AlertConditionCategory.TRAIT) {
AlertConditionTraitCategoryComposite traitsComposite = (AlertConditionTraitCategoryComposite) composite;
String value = null;
switch (alertConditionOperator) {
case CHANGES:
value = traitsComposite.getValue();
break;
case REGEX:
value = traitsComposite.getCondition().getOption();
break;
default:
log.error("Invalid operator for Trait condition: " + alertConditionOperator);
}
try {
/*
* don't forget special defensive handling to allow for null trait calculation;
* this might happen if a newly committed resource has some alert template applied to
* it for some trait that it has not yet gotten from the agent
*/
MeasurementTraitCacheElement cacheElement = new MeasurementTraitCacheElement(alertConditionOperator,
value, alertConditionId);
addTo("measurementTraitCache", measurementTraitCache, traitsComposite.getScheduleId(), cacheElement,
alertConditionId, stats);
} catch (InvalidCacheElementException icee) {
log.info("Failed to create MeasurementTraitCacheElement with parameters: "
+ AlertConditionCacheUtils.getCacheElementErrorString(alertConditionId, alertConditionOperator,
null, value, icee));
}
} else if (alertConditionCategory == AlertConditionCategory.THRESHOLD) {
AlertConditionScheduleCategoryComposite thresholdComposite = (AlertConditionScheduleCategoryComposite) composite;
Double thresholdValue = alertCondition.getThreshold();
MeasurementNumericCacheElement cacheElement = null;
try {
cacheElement = new MeasurementNumericCacheElement(alertConditionOperator, thresholdValue,
alertConditionId);
} catch (InvalidCacheElementException icee) {
log.info("Failed to create MeasurementNumericCacheElement with parameters: "
+ AlertConditionCacheUtils.getCacheElementErrorString(alertConditionId, alertConditionOperator,
null, thresholdValue, icee));
}
if (cacheElement != null) {
addTo("measurementDataCache", measurementDataCache, thresholdComposite.getScheduleId(), cacheElement,
alertConditionId, stats);
}
} else if (alertConditionCategory == AlertConditionCategory.EVENT) {
AlertConditionEventCategoryComposite eventComposite = (AlertConditionEventCategoryComposite) composite;
EventSeverity eventSeverity = EventSeverity.valueOf(alertCondition.getName());
String eventDetails = alertCondition.getOption();
EventCacheElement cacheElement = null;
try {
if (eventDetails == null) {
cacheElement = new EventCacheElement(alertConditionOperator, eventSeverity, alertConditionId);
} else {
String regexEventDetails = "", regexSourceLocation = "";
if (eventDetails.contains(AlertCondition.ADHOC_SEPARATOR)) {
String[] regexes = eventDetails.split(AlertCondition.ADHOC_SEPARATOR);
if (regexes.length > 0) {
regexEventDetails = regexes[0];
if (regexes.length > 1) {
regexSourceLocation = regexes[1];
}
}
} else {
regexEventDetails = eventDetails; // let's keep backward compatibility here, because there may be REST
// clients using the old approach
}
cacheElement = new EventCacheElement(alertConditionOperator, eventDetails, regexEventDetails,
regexSourceLocation, eventSeverity, alertConditionId);
}
} catch (InvalidCacheElementException icee) {
log.info("Failed to create EventCacheElement with parameters: "
+ AlertConditionCacheUtils.getCacheElementErrorString(alertConditionId, alertConditionOperator,
eventDetails, eventSeverity, icee));
}
addTo("eventsCache", eventsCache, eventComposite.getResourceId(), cacheElement, alertConditionId, stats);
} else if (alertConditionCategory == AlertConditionCategory.DRIFT) {
AlertConditionDriftCategoryComposite driftComposite = (AlertConditionDriftCategoryComposite) composite;
String driftDefNameRegexStr = driftComposite.getCondition().getName();
String driftPathNameRegexStr = driftComposite.getCondition().getOption();
DriftCacheElement cacheElement = null;
try {
cacheElement = new DriftCacheElement(alertConditionOperator, driftDefNameRegexStr,
driftPathNameRegexStr, alertConditionId);
} catch (InvalidCacheElementException icee) {
log.info("Failed to create DriftCacheElement: id=" + alertConditionId + ", operator="
+ alertConditionOperator + ", driftDefNameRegex=" + driftDefNameRegexStr + ", driftPathNameRegex="
+ driftPathNameRegexStr);
}
addTo("driftCache", driftCache, driftComposite.getResourceId(), cacheElement, alertConditionId, stats);
} else if (alertConditionCategory == AlertConditionCategory.RANGE) {
AlertConditionRangeCategoryComposite rangeComposite = (AlertConditionRangeCategoryComposite) composite;
Double loValue = alertCondition.getThreshold();
String hiValueStr = alertCondition.getOption();
MeasurementNumericCacheElement cacheElement = null;
try {
if (hiValueStr == null) {
throw new NumberFormatException("The range alert condition is missing the high value");
}
Double hiValue = Double.valueOf(hiValueStr);
cacheElement = new MeasurementRangeNumericCacheElement(alertConditionOperator, loValue, hiValue,
alertConditionId);
} catch (InvalidCacheElementException icee) {
log.info("Failed to create MeasurementRangeNumericCacheElement with parameters: "
+ AlertConditionCacheUtils.getCacheElementErrorString(alertConditionId, alertConditionOperator,
hiValueStr, loValue, icee));
} catch (NumberFormatException nfe) {
log.info("Failed to create MeasurementRangeNumericCacheElement with parameters: "
+ AlertConditionCacheUtils.getCacheElementErrorString(alertConditionId, alertConditionOperator,
hiValueStr, loValue, nfe));
}
if (cacheElement != null) {
addTo("measurementDataCache", measurementDataCache, rangeComposite.getScheduleId(), cacheElement,
alertConditionId, stats);
}
}
}
public AlertConditionCacheStats checkConditions(MeasurementData... measurementData) {
if ((measurementData == null) || (measurementData.length == 0)) {
return new AlertConditionCacheStats();
}
AlertConditionCacheStats stats = new AlertConditionCacheStats();
try {
for (MeasurementData datum : measurementData) {
int scheduleId = datum.getScheduleId();
if (datum instanceof MeasurementDataNumeric) {
List<? extends NumericDoubleCacheElement> conditionCacheElements = lookupMeasurementDataCacheElements(scheduleId);
Double providedValue = ((MeasurementDataNumeric) datum).getValue();
processCacheElements(conditionCacheElements, providedValue, datum.getTimestamp(), stats);
} else if (datum instanceof MeasurementDataTrait) {
List<MeasurementTraitCacheElement> cacheElements = lookupMeasurementTraitCacheElements(scheduleId);
processCacheElements(cacheElements, ((MeasurementDataTrait) datum).getValue(),
datum.getTimestamp(), stats);
} else {
log.error(getClass().getSimpleName() + " does not support " + "checking conditions against "
+ datum.getClass().getSimpleName() + " types");
}
}
AlertConditionCacheMonitor.getMBean().incrementMeasurementCacheElementMatches(stats.matched);
AlertConditionCacheMonitor.getMBean().incrementMeasurementProcessingTime(stats.getAge());
if (log.isDebugEnabled())
log.debug("Check Measurements[size=" + measurementData.length + "] - " + stats);
} catch (Throwable t) {
// don't let any exceptions bubble up to the calling SLSB layer
log.error("Error during measurement data cache processing for agent[id=" + agentId + "]", t);
}
return stats;
}
public AlertConditionCacheStats checkConditions(CallTimeData... callTime) {
if ((callTime == null) || (callTime.length == 0)) {
return new AlertConditionCacheStats();
}
AlertConditionCacheStats stats = new AlertConditionCacheStats();
try {
HashMap<Integer, HashMap<String, ArrayList<CallTimeDataValue>>> order = produceOrderedCallTimeDataStructure(callTime);
for (Integer scheduleId : order.keySet()) {
List<? extends CallTimeDataCacheElement> conditionCacheElements = lookupCallTimeDataCacheElements(scheduleId);
for (String callDest : order.get(scheduleId).keySet()) {
for (CallTimeDataValue provided : order.get(scheduleId).get(callDest)) {
processCacheElements(conditionCacheElements, provided, provided.getBeginTime(), stats, callDest);
}
}
}
AlertConditionCacheMonitor.getMBean().incrementCallTimeCacheElementMatches(stats.matched);
AlertConditionCacheMonitor.getMBean().incrementCallTimeProcessingTime(stats.getAge());
} catch (Throwable t) {
// don't let any exceptions bubble up to the calling SLSB layer
log.error("Error during calltime cache processing for agent[id=" + agentId + "]", t);
}
return stats;
}
private HashMap<Integer, HashMap<String, ArrayList<CallTimeDataValue>>> produceOrderedCallTimeDataStructure(
CallTimeData... callTime) {
long beginTime = 0;
if (log.isDebugEnabled()) {
beginTime = System.nanoTime();
}
//Insert all CallTimeDataValue in data structure
HashMap<Integer, HashMap<String, ArrayList<CallTimeDataValue>>> order = new HashMap<Integer, HashMap<String, ArrayList<CallTimeDataValue>>>();
for (CallTimeData ctd : callTime) {
if (!order.containsKey(ctd.getScheduleId()))
order.put(ctd.getScheduleId(), new HashMap<String, ArrayList<CallTimeDataValue>>());
HashMap<String, ArrayList<CallTimeDataValue>> partialOrder = order.get(ctd.getScheduleId());
for (String callDestination : ctd.getValues().keySet()) {
if (!partialOrder.containsKey(callDestination))
partialOrder.put(callDestination, new ArrayList<CallTimeDataValue>());
ArrayList<CallTimeDataValue> list = partialOrder.get(callDestination);
list.add(ctd.getValues().get(callDestination));
}
}
//sort all lists in the data structure
for (HashMap<String, ArrayList<CallTimeDataValue>> topList : order.values())
for (ArrayList<CallTimeDataValue> bottomList : topList.values())
Collections.sort(bottomList, getCallTimeComparator());
if (log.isDebugEnabled()) {
log.debug("sorting call-time data during alerting took: "
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - beginTime) + "ms");
}
return order;
}
private Comparator<CallTimeDataValue> getCallTimeComparator() {
return new Comparator<CallTimeDataValue>() {
public int compare(CallTimeDataValue arg0, CallTimeDataValue arg1) {
if (arg0 == null || arg1 == null)
throw new IllegalArgumentException("Call-time data value entries must not be null!");
if (arg0 == arg1)
return 0;
//differing begin times:
if (arg0.getBeginTime() < arg1.getBeginTime())
return -1;
if (arg0.getBeginTime() > arg1.getBeginTime())
return 1;
// begin time equality:
if (arg0.getBeginTime() == arg1.getBeginTime()) {
if (arg0.getEndTime() == arg1.getEndTime())
return 0;
if (arg0.getEndTime() < arg1.getEndTime())
return -1;
if (arg0.getEndTime() > arg1.getEndTime())
return 1;
}
return Integer.MIN_VALUE;
}
};
}
/**
* This operates differently from the other {{checkConditions()}} methods. Because it's possible that one
* batch of events may contain both an event triggering a problem event and also an event triggering its
* recovery alert, we return after a matched condition to allow for the caller to check remaining
* events only after a cache refresh has been performed.
*
* @param stats not null. the stats object to update
* @param source
* @param events
* @return the number of eventsProcessed until a match was found or all events were processed.
*/
public AlertConditionCacheStats checkConditions(EventSource source, List<Event> events) {
AlertConditionCacheStats stats = new AlertConditionCacheStats();
if ((events == null) || events.isEmpty()) {
return stats;
}
int initialSize = events.size();
try {
Resource resource = source.getResource();
List<EventCacheElement> cacheElements = lookupEventCacheElements(resource.getId());
for (Iterator<Event> i = events.iterator(); i.hasNext();) {
Event event = i.next();
i.remove();
int matched = stats.matched;
processCacheElements(cacheElements, event.getSeverity(), event.getTimestamp(), stats,
"sourceLocation=" + source.getLocation(), event.getDetail());
if (matched < stats.matched) {
break;
}
}
AlertConditionCacheMonitor.getMBean().incrementEventCacheElementMatches(stats.matched);
AlertConditionCacheMonitor.getMBean().incrementEventProcessingTime(stats.getAge());
if (log.isDebugEnabled()) {
log.debug("Check Events[size=" + (initialSize - events.size()) + "] - " + stats);
}
} catch (Throwable t) {
// don't let any exceptions bubble up to the calling SLSB layer
log.error("Error during event cache processing for agent[id=" + agentId + "]", t);
}
return stats;
}
public AlertConditionCacheStats checkConditions(DriftChangeSetSummary driftChangeSetSummary) {
AlertConditionCacheStats stats = new AlertConditionCacheStats();
try {
int resourceId = driftChangeSetSummary.getResourceId();
List<DriftCacheElement> cacheElements = lookupDriftCacheElements(resourceId);
processCacheElements(cacheElements, DriftCacheElement.UNUSED_CONDITION_VALUE,
driftChangeSetSummary.getCreatedTime(), stats, driftChangeSetSummary);
AlertConditionCacheMonitor.getMBean().incrementDriftCacheElementMatches(stats.matched);
AlertConditionCacheMonitor.getMBean().incrementDriftProcessingTime(stats.getAge());
if (log.isDebugEnabled()) {
log.debug("Check Drift[resourceId=" + resourceId + "] - " + stats);
}
} catch (Throwable t) {
// don't let any exceptions bubble up to the calling SLSB layer
log.error("Error during drift cache processing for agent[id=" + agentId + "]", t);
}
return stats;
}
private List<? extends NumericDoubleCacheElement> lookupMeasurementDataCacheElements(int scheduleId) {
return measurementDataCache.get(scheduleId); // yup, might be null
}
private List<? extends CallTimeDataCacheElement> lookupCallTimeDataCacheElements(int scheduleId) {
return callTimeCache.get(scheduleId); // yup, might be null
}
private List<MeasurementTraitCacheElement> lookupMeasurementTraitCacheElements(int scheduleId) {
return measurementTraitCache.get(scheduleId); // yup, might be null
}
private List<EventCacheElement> lookupEventCacheElements(int resourceId) {
return eventsCache.get(resourceId); // yup, might be null
}
private List<DriftCacheElement> lookupDriftCacheElements(int resourceId) {
return driftCache.get(resourceId); // yup, might be null
}
private Double getCalculatedBaselineValue(int conditionId, AlertConditionBaselineCategoryComposite composite,
String optionStatus, Double threshold) {
int baselineId = composite.getBaselineId();
if (AlertConditionCacheUtils.isInvalidDouble(threshold)) {
log.error("Failed to calculate baseline for [conditionId=" + conditionId + ", baselineId=" + baselineId
+ "]: threshold was null");
}
// auto-unboxing of threshold is safe here
Double baselineValue = 0.0;
if (optionStatus == null) {
log.error("Failed to calculate baseline for [conditionId=" + conditionId + ", baselineId=" + baselineId
+ "]: optionStatus string was null");
} else if (optionStatus.equals("min")) {
baselineValue = composite.getMinValue();
} else if (optionStatus.equals("mean")) {
baselineValue = composite.getMeanValue();
} else if (optionStatus.equals("max")) {
baselineValue = composite.getMaxValue();
} else {
log.error("Failed to calculate baseline for [conditionId=" + conditionId + ", baselineId=" + baselineId
+ "]: unrecognized optionStatus string of '" + optionStatus + "'");
return null;
}
if (AlertConditionCacheUtils.isInvalidDouble(baselineValue)) {
log.error("Failed to calculate baseline for [conditionId=" + conditionId + ", baselineId=" + baselineId
+ "]: optionStatus string was '" + optionStatus + "', but the corresponding baseline value was null");
}
return threshold * baselineValue;
}
@Override
public int getCacheSize(Cache cache) {
if (cache == AlertConditionCacheCoordinator.Cache.MeasurementDataCache) {
return AlertConditionCacheUtils.getMapListCount(measurementDataCache);
} else if (cache == AlertConditionCacheCoordinator.Cache.MeasurementTraitCache) {
return AlertConditionCacheUtils.getMapListCount(measurementTraitCache);
} else if (cache == AlertConditionCacheCoordinator.Cache.CallTimeDataCache) {
return AlertConditionCacheUtils.getMapListCount(callTimeCache);
} else if (cache == AlertConditionCacheCoordinator.Cache.EventsCache) {
return AlertConditionCacheUtils.getMapListCount(eventsCache);
} else if (cache == AlertConditionCacheCoordinator.Cache.DriftCache) {
return AlertConditionCacheUtils.getMapListCount(driftCache);
} else {
throw new IllegalArgumentException("The " + AgentConditionCache.class.getSimpleName()
+ " either does not manage caches of type " + cache.type + ", or does not support obtaining their size");
}
}
}