Update the TopologyMetrics module to listen for all topology-related events:
Devices, Hosts, Links, TopologyEvent
Now the semantics for updating the metrics are:
* Any topology-related event (DeviceEvent, HostEvent, LinkEvent,
TopologyEvent) will update the Lost Topology Event Timestamp
* Only the DeviceEvent, HostEvent and LinkEvent will be counted in
measuring the event rate; TopologyEvent is excluded, because it
is generated as a result of some of those events
Also, increased the number of saved events from 10 to 100.
Change-Id: Ie759ee69869cddc617d7ad5b8b75a622e2571620
diff --git a/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/TopologyMetrics.java b/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/TopologyMetrics.java
index e2a4532..32cf0cf 100644
--- a/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/TopologyMetrics.java
+++ b/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/TopologyMetrics.java
@@ -18,6 +18,15 @@
import org.onlab.metrics.MetricsFeature;
import org.onlab.metrics.MetricsService;
import org.onlab.onos.event.Event;
+import org.onlab.onos.net.device.DeviceEvent;
+import org.onlab.onos.net.device.DeviceListener;
+import org.onlab.onos.net.device.DeviceService;
+import org.onlab.onos.net.host.HostEvent;
+import org.onlab.onos.net.host.HostListener;
+import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.link.LinkEvent;
+import org.onlab.onos.net.link.LinkListener;
+import org.onlab.onos.net.link.LinkService;
import org.onlab.onos.net.topology.TopologyEvent;
import org.onlab.onos.net.topology.TopologyListener;
import org.onlab.onos.net.topology.TopologyService;
@@ -28,14 +37,26 @@
*/
@Component(immediate = true)
@Service
-public class TopologyMetrics implements TopologyMetricsService,
- TopologyListener {
+public class TopologyMetrics implements TopologyMetricsService {
private static final Logger log = getLogger(TopologyMetrics.class);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected LinkService linkService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
- private LinkedList<TopologyEvent> lastEvents = new LinkedList<>();
- private static final int LAST_EVENTS_MAX_N = 10;
+
+ private LinkedList<Event> lastEvents = new LinkedList<>();
+ private static final int LAST_EVENTS_MAX_N = 100;
+
+ private final DeviceListener deviceListener = new InnerDeviceListener();
+ private final HostListener hostListener = new InnerHostListener();
+ private final LinkListener linkListener = new InnerLinkListener();
+ private final TopologyListener topologyListener =
+ new InnerTopologyListener();
//
// Metrics
@@ -61,22 +82,33 @@
protected void activate() {
clear();
registerMetrics();
- topologyService.addListener(this);
+
+ // Register for all topology-related events
+ deviceService.addListener(deviceListener);
+ hostService.addListener(hostListener);
+ linkService.addListener(linkListener);
+ topologyService.addListener(topologyListener);
+
log.info("ONOS Topology Metrics started.");
}
@Deactivate
public void deactivate() {
- topologyService.removeListener(this);
+ // De-register from all topology-related events
+ deviceService.removeListener(deviceListener);
+ hostService.removeListener(hostListener);
+ linkService.removeListener(linkListener);
+ topologyService.removeListener(topologyListener);
+
removeMetrics();
clear();
log.info("ONOS Topology Metrics stopped.");
}
@Override
- public List<TopologyEvent> getEvents() {
+ public List<Event> getEvents() {
synchronized (lastEvents) {
- return ImmutableList.<TopologyEvent>copyOf(lastEvents);
+ return ImmutableList.<Event>copyOf(lastEvents);
}
}
@@ -90,27 +122,22 @@
return eventRateMeter;
}
- @Override
- public void event(TopologyEvent event) {
- lastEventTimestampEpochMs = System.currentTimeMillis();
- //
- // NOTE: If we want to count each "reason" as a separate event,
- // then we should use 'event.reason().size()' instead of '1' to
- // mark the meter below.
- //
- eventRateMeter.mark(1);
-
- log.debug("Topology Event: time = {} type = {} subject = {}",
- event.time(), event.type(), event.subject());
- for (Event reason : event.reasons()) {
- log.debug("Topology Event Reason: time = {} type = {} subject = {}",
- reason.time(), reason.type(), reason.subject());
- }
-
- //
- // Keep only the last N events, where N = LAST_EVENTS_MAX_N
- //
+ /**
+ * Records an event.
+ *
+ * @param event the event to record
+ * @param updateEventRateMeter if true, update the Event Rate Meter
+ */
+ private void recordEvent(Event event, boolean updateEventRateMeter) {
synchronized (lastEvents) {
+ lastEventTimestampEpochMs = System.currentTimeMillis();
+ if (updateEventRateMeter) {
+ eventRateMeter.mark(1);
+ }
+
+ //
+ // Keep only the last N events, where N = LAST_EVENTS_MAX_N
+ //
while (lastEvents.size() >= LAST_EVENTS_MAX_N) {
lastEvents.remove();
}
@@ -119,11 +146,67 @@
}
/**
+ * Inner Device Event Listener class.
+ */
+ private class InnerDeviceListener implements DeviceListener {
+ @Override
+ public void event(DeviceEvent event) {
+ recordEvent(event, true);
+ log.debug("Device Event: time = {} type = {} event = {}",
+ event.time(), event.type(), event);
+ }
+ }
+
+ /**
+ * Inner Host Event Listener class.
+ */
+ private class InnerHostListener implements HostListener {
+ @Override
+ public void event(HostEvent event) {
+ recordEvent(event, true);
+ log.debug("Host Event: time = {} type = {} event = {}",
+ event.time(), event.type(), event);
+ }
+ }
+
+ /**
+ * Inner Link Event Listener class.
+ */
+ private class InnerLinkListener implements LinkListener {
+ @Override
+ public void event(LinkEvent event) {
+ recordEvent(event, true);
+ log.debug("Link Event: time = {} type = {} event = {}",
+ event.time(), event.type(), event);
+ }
+ }
+
+ /**
+ * Inner Topology Event Listener class.
+ */
+ private class InnerTopologyListener implements TopologyListener {
+ @Override
+ public void event(TopologyEvent event) {
+ //
+ // NOTE: Don't update the eventRateMeter, because the real
+ // events are already captured/counted.
+ //
+ recordEvent(event, false);
+ log.debug("Topology Event: time = {} type = {} event = {}",
+ event.time(), event.type(), event);
+ for (Event reason : event.reasons()) {
+ log.debug("Topology Event Reason: time = {} type = {} event = {}",
+ reason.time(), reason.type(), reason);
+ }
+ }
+ }
+
+ /**
* Clears the internal state.
*/
private void clear() {
- lastEventTimestampEpochMs = 0;
synchronized (lastEvents) {
+ lastEventTimestampEpochMs = 0;
lastEvents.clear();
}
}
diff --git a/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/TopologyMetricsService.java b/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/TopologyMetricsService.java
index cc370fa..aeb2e32 100644
--- a/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/TopologyMetricsService.java
+++ b/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/TopologyMetricsService.java
@@ -4,7 +4,7 @@
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Meter;
-import org.onlab.onos.net.topology.TopologyEvent;
+import org.onlab.onos.event.Event;
/**
* Service interface exported by TopologyMetrics.
@@ -15,7 +15,7 @@
*
* @return the last saved topology events.
*/
- public List<TopologyEvent> getEvents();
+ public List<Event> getEvents();
/**
* Gets the Metrics' Gauge for the last topology event timestamp
diff --git a/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/cli/TopologyEventsListCommand.java b/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/cli/TopologyEventsListCommand.java
index 8bab4d0..f8d0c1a 100644
--- a/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/cli/TopologyEventsListCommand.java
+++ b/apps/metrics/topology/src/main/java/org/onlab/onos/metrics/topology/cli/TopologyEventsListCommand.java
@@ -19,10 +19,8 @@
description = "Lists the last topology events")
public class TopologyEventsListCommand extends AbstractShellCommand {
- private static final String FORMAT_EVENT =
- "Topology Event time=%d type=%s subject=%s";
- private static final String FORMAT_REASON =
- " Reason time=%d type=%s subject=%s";
+ private static final String FORMAT_EVENT = "Event=%s";
+ private static final String FORMAT_REASON = " Reason=%s";
@Override
protected void execute() {
@@ -31,12 +29,13 @@
if (outputJson()) {
print("%s", json(service.getEvents()));
} else {
- for (TopologyEvent event : service.getEvents()) {
- print(FORMAT_EVENT, event.time(), event.type(),
- event.subject());
- for (Event reason : event.reasons()) {
- print(FORMAT_REASON, reason.time(), reason.type(),
- reason.subject());
+ for (Event event : service.getEvents()) {
+ print(FORMAT_EVENT, event);
+ if (event instanceof TopologyEvent) {
+ TopologyEvent topologyEvent = (TopologyEvent) event;
+ for (Event reason : topologyEvent.reasons()) {
+ print(FORMAT_REASON, reason);
+ }
}
print(""); // Extra empty line for clarity
}
@@ -46,14 +45,14 @@
/**
* Produces a JSON array of topology events.
*
- * @param topologyEvents the topology events with the data
+ * @param events the topology events with the data
* @return JSON array with the topology events
*/
- private JsonNode json(List<TopologyEvent> topologyEvents) {
+ private JsonNode json(List<Event> events) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
- for (TopologyEvent event : topologyEvents) {
+ for (Event event : events) {
result.add(json(mapper, event));
}
return result;
@@ -66,32 +65,23 @@
* @param topologyEvent the topology event with the data
* @return JSON object for the topology event
*/
- private ObjectNode json(ObjectMapper mapper, TopologyEvent topologyEvent) {
- ObjectNode result = mapper.createObjectNode();
- ArrayNode reasons = mapper.createArrayNode();
-
- for (Event reason : topologyEvent.reasons()) {
- reasons.add(json(mapper, reason));
- }
- result.put("time", topologyEvent.time())
- .put("type", topologyEvent.type().toString())
- .put("subject", topologyEvent.subject().toString())
- .put("reasons", reasons);
- return result;
- }
-
- /**
- * Produces JSON object for a generic event.
- *
- * @param event the generic event with the data
- * @return JSON object for the generic event
- */
private ObjectNode json(ObjectMapper mapper, Event event) {
ObjectNode result = mapper.createObjectNode();
result.put("time", event.time())
.put("type", event.type().toString())
- .put("subject", event.subject().toString());
+ .put("event", event.toString());
+
+ // Add the reasons if a TopologyEvent
+ if (event instanceof TopologyEvent) {
+ TopologyEvent topologyEvent = (TopologyEvent) event;
+ ArrayNode reasons = mapper.createArrayNode();
+ for (Event reason : topologyEvent.reasons()) {
+ reasons.add(json(mapper, reason));
+ }
+ result.put("reasons", reasons);
+ }
+
return result;
}
}