/*****************************************************************************
*
* Copyright (C) Zenoss, Inc. 2010, all rights reserved.
*
* This content is made available according to terms specified in
* License.zenoss under the directory where your Zenoss product is installed.
*
****************************************************************************/
package org.zenoss.zep.impl;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.codahale.metrics.annotation.Timed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.zenoss.protobufs.zep.Zep.Event;
import org.zenoss.protobufs.zep.Zep.EventStatus;
import org.zenoss.protobufs.zep.Zep.EventSummary;
import org.zenoss.protobufs.zep.Zep.ZepRawEvent;
import org.zenoss.zep.Counters;
import org.zenoss.zep.EventProcessor;
import org.zenoss.zep.PluginService;
import org.zenoss.zep.ZepException;
import org.zenoss.zep.dao.EventSummaryDao;
import org.zenoss.zep.plugins.EventPostCreateContext;
import org.zenoss.zep.plugins.EventPostCreatePlugin;
import org.zenoss.zep.plugins.EventPreCreateContext;
import org.zenoss.zep.plugins.EventPreCreatePlugin;
import javax.annotation.Resource;
/**
* Default implementation of {@link EventProcessor} which uses
* {@link PluginService} to load the appropriate plug-ins and process events.
*/
public class EventProcessorImpl implements EventProcessor {
private static final Logger logger = LoggerFactory.getLogger(EventProcessorImpl.class);
private static final String EVENT_CLASS_UNKNOWN = "/Unknown";
private PluginService pluginService;
private EventSummaryDao eventSummaryDao;
private Counters counters;
private MetricRegistry metrics = new MetricRegistry();
private Timer preCreatePluginsTimer = metrics.timer("preCreateForUnitTest");
private Timer postCreatePluginsTimer= metrics.timer("postCreateForUnitTest");
public void setEventSummaryDao(EventSummaryDao eventSummaryDao) {
this.eventSummaryDao = eventSummaryDao;
}
/**
* Sets the plug-in service used to look up configured plug-ins.
*
* @param pluginService
* The plug-in service to use to look up configured plug-ins.
*/
public void setPluginService(PluginService pluginService) {
this.pluginService = pluginService;
}
public void setCounters(Counters counters) {
this.counters = counters;
}
private static Event eventFromRawEvent(ZepRawEvent zepRawEvent) {
Event event = zepRawEvent.getEvent();
// Default to event class unknown.
if (event.getEventClass().isEmpty()) {
event = Event.newBuilder(event).setEventClass(EVENT_CLASS_UNKNOWN).build();
}
return event;
}
@Override
@Timed
public void processEvent(ZepRawEvent zepRawEvent) throws ZepException {
logger.debug("processEvent: event={}", zepRawEvent);
counters.addToProcessedEventCount(1);
if (zepRawEvent.getEvent().getStatus() == EventStatus.STATUS_DROPPED) {
logger.debug("Event dropped: {}", zepRawEvent);
counters.addToDroppedEventCount(1);
return;
} else if (zepRawEvent.getEvent().getUuid().isEmpty()) {
logger.error("Could not process event, has no uuid: {}",
zepRawEvent);
counters.addToDroppedEventCount(1);
return;
} else if (!zepRawEvent.getEvent().hasCreatedTime()) {
logger.error("Could not process event, has no created_time: {}",
zepRawEvent);
counters.addToDroppedEventCount(1);
return;
}
EventPreCreateContext ctx = new EventPreCreateContextImpl(zepRawEvent);
Event event = eventFromRawEvent(zepRawEvent);
for (EventPreCreatePlugin plugin : pluginService.getPluginsByType(EventPreCreatePlugin.class)) {
final Timer.Context timerContext = preCreatePluginsTimer.time();
Event modified = plugin.processEvent(event, ctx);
timerContext.stop();
if (modified != null && modified.getStatus() == EventStatus.STATUS_DROPPED) {
logger.debug("Event dropped by {}", plugin.getId());
counters.addToDroppedEventCount(1);
return;
}
if (modified != null && !modified.equals(event)) {
logger.debug("Event modified by {} as {}", plugin.getId(), modified);
event = modified;
}
}
String uuid;
try {
uuid = this.eventSummaryDao.create(event, ctx);
} catch (DuplicateKeyException e) {
// Catch DuplicateKeyException and retry creating the event. Otherwise, the failure
// will propagate to the AMQP consumer, the message will be rejected (and re-queued),
// leading to unnecessary load on the AMQP server re-queueing/re-delivering the event.
if (logger.isDebugEnabled()) {
logger.info("DuplicateKeyException - retrying event: {}", event);
} else {
logger.info("DuplicateKeyException - retrying event: {}", event.getUuid());
}
uuid = this.eventSummaryDao.create(event, ctx);
}
EventSummary summary = null;
EventPostCreateContext context = new EventPostCreateContext() {
};
for (EventPostCreatePlugin plugin : pluginService.getPluginsByType(EventPostCreatePlugin.class)) {
if (summary == null && uuid != null) {
summary = this.eventSummaryDao.findByUuid(uuid);
}
final Timer.Context timerContext = postCreatePluginsTimer.time();
try {
plugin.processEvent(event, summary, context);
} catch (Exception e) {
logger.warn("Failed to run post-create plugin: {} on event: {}, summary: {}",
new Object[] { plugin.getId(), event, summary }, e);
} finally {
timerContext.stop();
}
}
}
@Resource(name="metrics")
public void setBean( MetricRegistry metrics ) {
this.metrics = metrics;
String preCreatePluginsTimerName = MetricRegistry.name(this.getClass().getCanonicalName(), "preCreatePlugins");
String postCreatePluginsTimerName = MetricRegistry.name(this.getClass().getCanonicalName(), "postCreatePlugins");
// Set up timers for plugins
preCreatePluginsTimer = metrics.timer(preCreatePluginsTimerName);
postCreatePluginsTimer = metrics.timer(postCreatePluginsTimerName);
}
}