monasca-thresh/src/main/java/com/hpcloud/mon/infrastructure/thresholding/MetricFilteringBolt.java

117 lines
4.3 KiB
Java

package com.hpcloud.mon.infrastructure.thresholding;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import com.hpcloud.mon.common.event.AlarmCreatedEvent;
import com.hpcloud.mon.common.event.AlarmDeletedEvent;
import com.hpcloud.mon.common.model.metric.MetricDefinition;
import com.hpcloud.mon.domain.service.MetricDefinitionDAO;
import com.hpcloud.mon.domain.service.SubAlarmDAO;
import com.hpcloud.mon.infrastructure.persistence.PersistenceModule;
import com.hpcloud.streaming.storm.Logging;
import com.hpcloud.streaming.storm.Streams;
import com.hpcloud.util.Injector;
/**
* Filters metrics for which there is no associated alarm and forwards metrics for which there is an
* alarm. Receives metric alarm and metric sub-alarm events to update metric definitions.
*
* <ul>
* <li>Input: MetricDefinition metricDefinition, Metric metric
* <li>Input metric-alarm-events: String eventType, MetricDefinition metricDefinition, String
* alarmId
* <li>Input metric-sub-alarm-events: String eventType, MetricDefinition metricDefinition, SubAlarm
* subAlarm
* <li>Output: MetricDefinition metricDefinition, Metric metric
* </ul>
*
* @author Jonathan Halterman
*/
public class MetricFilteringBolt extends BaseRichBolt {
private static final long serialVersionUID = 1096706128973976599L;
private static final Map<MetricDefinition, Object> METRIC_DEFS = new ConcurrentHashMap<MetricDefinition, Object>();
private static final Object SENTINAL = new Object();
private transient Logger LOG;
private final DataSourceFactory dbConfig;
private transient MetricDefinitionDAO metricDefDAO;
private OutputCollector collector;
public MetricFilteringBolt(DataSourceFactory dbConfig) {
this.dbConfig = dbConfig;
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("metricDefinition", "metric"));
}
@Override
public void execute(Tuple tuple) {
LOG.debug("tuple: {}", tuple);
try {
if (Streams.DEFAULT_STREAM_ID.equals(tuple.getSourceStreamId())) {
MetricDefinition metricDef = (MetricDefinition) tuple.getValue(0);
LOG.debug("metric definition: {}", metricDef);
if (METRIC_DEFS.containsKey(metricDef))
collector.emit(tuple, tuple.getValues());
} else {
String eventType = tuple.getString(0);
MetricDefinition metricDefinition = (MetricDefinition) tuple.getValue(1);
LOG.debug("Received {} for {}", eventType, metricDefinition);
if (EventProcessingBolt.METRIC_ALARM_EVENT_STREAM_ID.equals(tuple.getSourceStreamId())) {
if (AlarmDeletedEvent.class.getSimpleName().equals(eventType))
METRIC_DEFS.remove(metricDefinition);
} else if (EventProcessingBolt.METRIC_SUB_ALARM_EVENT_STREAM_ID.equals(tuple.getSourceStreamId())) {
if (AlarmCreatedEvent.class.getSimpleName().equals(eventType))
METRIC_DEFS.put(metricDefinition, SENTINAL);
}
}
} catch (Exception e) {
LOG.error("Error processing tuple {}", tuple, e);
} finally {
collector.ack(tuple);
}
}
@Override
@SuppressWarnings("rawtypes")
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
LOG = LoggerFactory.getLogger(Logging.categoryFor(getClass(), context));
LOG.info("Preparing");
this.collector = collector;
if (metricDefDAO == null) {
Injector.registerIfNotBound(SubAlarmDAO.class, new PersistenceModule(dbConfig));
metricDefDAO = Injector.getInstance(MetricDefinitionDAO.class);
}
// DCL
if (METRIC_DEFS.isEmpty()) {
synchronized (SENTINAL) {
if (METRIC_DEFS.isEmpty()) {
for (MetricDefinition metricDef : metricDefDAO.findForAlarms())
METRIC_DEFS.put(metricDef, SENTINAL);
// Iterate again to ensure we only emit each metricDef once
for (MetricDefinition metricDef : METRIC_DEFS.keySet())
collector.emit(new Values(metricDef, null));
}
}
}
}
}