summaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/metrics
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
committerAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
commit13d05bc8458758ee39cb829098241e89616717ee (patch)
tree22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/apps/metrics
parent6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff)
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/apps/metrics')
-rw-r--r--framework/src/onos/apps/metrics/pom.xml69
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/IntentMetrics.java234
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/IntentMetricsService.java74
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/IntentEventsListCommand.java83
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/IntentEventsMetricsCommand.java152
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/package-info.java20
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/package-info.java20
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/TopologyMetrics.java295
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/TopologyMetricsService.java67
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/TopologyEventsListCommand.java102
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/TopologyEventsMetricsCommand.java144
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/package-info.java20
-rw-r--r--framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/package-info.java20
-rw-r--r--framework/src/onos/apps/metrics/src/main/resources/OSGI-INF/blueprint/shell-config.xml32
14 files changed, 1332 insertions, 0 deletions
diff --git a/framework/src/onos/apps/metrics/pom.xml b/framework/src/onos/apps/metrics/pom.xml
new file mode 100644
index 00000000..89757c9a
--- /dev/null
+++ b/framework/src/onos/apps/metrics/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2014 Open Networking Laboratory
+ ~
+ ~ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-apps</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-app-metrics</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>Performance metrics collection</description>
+
+ <properties>
+ <onos.app.name>org.onosproject.metrics</onos.app.name>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-misc</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-cli</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/IntentMetrics.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/IntentMetrics.java
new file mode 100644
index 00000000..78a540c9
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/IntentMetrics.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+package org.onosproject.metrics.intent;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.metrics.EventMetric;
+import org.onlab.metrics.MetricsService;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentListener;
+import org.onosproject.net.intent.IntentService;
+import org.slf4j.Logger;
+
+/**
+ * ONOS Intent Metrics Application that collects intent-related metrics.
+ */
+@Component(immediate = true)
+@Service
+public class IntentMetrics implements IntentMetricsService,
+ IntentListener {
+ private static final Logger log = getLogger(IntentMetrics.class);
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected IntentService intentService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected MetricsService metricsService;
+
+ private ApplicationId appId;
+
+ private LinkedList<IntentEvent> lastEvents = new LinkedList<>();
+ private static final int LAST_EVENTS_MAX_N = 100;
+
+ //
+ // Metrics
+ //
+ private static final String COMPONENT_NAME = "Intent";
+ private static final String FEATURE_SUBMITTED_NAME = "Submitted";
+ private static final String FEATURE_INSTALLED_NAME = "Installed";
+ private static final String FEATURE_FAILED_NAME = "Failed";
+ private static final String FEATURE_WITHDRAW_REQUESTED_NAME =
+ "WithdrawRequested";
+ private static final String FEATURE_WITHDRAWN_NAME = "Withdrawn";
+ private static final String FEATURE_PURGED_NAME = "Purged";
+ //
+ // Event metrics:
+ // - Intent Submitted API operation
+ // - Intent Installed operation completion
+ // - Intent Failed compilation or installation
+ // - Intent Withdraw Requested API operation
+ // - Intent Withdrawn operation completion
+ // - Intent Purged operation completion
+ //
+ private EventMetric intentSubmittedEventMetric;
+ private EventMetric intentInstalledEventMetric;
+ private EventMetric intentFailedEventMetric;
+ private EventMetric intentWithdrawRequestedEventMetric;
+ private EventMetric intentWithdrawnEventMetric;
+ private EventMetric intentPurgedEventMetric;
+
+ @Activate
+ protected void activate() {
+ appId = coreService.registerApplication("org.onosproject.metrics");
+
+ clear();
+ registerMetrics();
+ intentService.addListener(this);
+ log.info("Started with Application ID {}", appId.id());
+ }
+
+ @Deactivate
+ public void deactivate() {
+ intentService.removeListener(this);
+ removeMetrics();
+ clear();
+ log.info("Stopped");
+ }
+
+ @Override
+ public List<IntentEvent> getEvents() {
+ synchronized (lastEvents) {
+ return ImmutableList.<IntentEvent>copyOf(lastEvents);
+ }
+ }
+
+ @Override
+ public EventMetric intentSubmittedEventMetric() {
+ return intentSubmittedEventMetric;
+ }
+
+ @Override
+ public EventMetric intentInstalledEventMetric() {
+ return intentInstalledEventMetric;
+ }
+
+ @Override
+ public EventMetric intentFailedEventMetric() {
+ return intentFailedEventMetric;
+ }
+
+ @Override
+ public EventMetric intentWithdrawRequestedEventMetric() {
+ return intentWithdrawRequestedEventMetric;
+ }
+
+ @Override
+ public EventMetric intentWithdrawnEventMetric() {
+ return intentWithdrawnEventMetric;
+ }
+
+ @Override
+ public EventMetric intentPurgedEventMetric() {
+ return intentPurgedEventMetric;
+ }
+
+ @Override
+ public void event(IntentEvent event) {
+ synchronized (lastEvents) {
+ switch (event.type()) {
+ case INSTALL_REQ:
+ intentSubmittedEventMetric.eventReceived();
+ break;
+ case INSTALLED:
+ intentInstalledEventMetric.eventReceived();
+ break;
+ case FAILED:
+ intentFailedEventMetric.eventReceived();
+ break;
+ case WITHDRAW_REQ:
+ intentWithdrawRequestedEventMetric.eventReceived();
+ break;
+ case WITHDRAWN:
+ intentWithdrawnEventMetric.eventReceived();
+ break;
+ case PURGED:
+ intentPurgedEventMetric.eventReceived();
+ break;
+ default:
+ break;
+ }
+
+ //
+ // Keep only the last N events, where N = LAST_EVENTS_MAX_N
+ //
+ while (lastEvents.size() >= LAST_EVENTS_MAX_N) {
+ lastEvents.remove();
+ }
+ lastEvents.add(event);
+ }
+
+ log.debug("Intent Event: time = {} type = {} event = {}",
+ event.time(), event.type(), event);
+ }
+
+ /**
+ * Clears the internal state.
+ */
+ private void clear() {
+ synchronized (lastEvents) {
+ lastEvents.clear();
+ }
+ }
+
+ /**
+ * Registers the metrics.
+ */
+ private void registerMetrics() {
+ intentSubmittedEventMetric =
+ new EventMetric(metricsService, COMPONENT_NAME,
+ FEATURE_SUBMITTED_NAME);
+ intentInstalledEventMetric =
+ new EventMetric(metricsService, COMPONENT_NAME,
+ FEATURE_INSTALLED_NAME);
+ intentFailedEventMetric =
+ new EventMetric(metricsService, COMPONENT_NAME,
+ FEATURE_FAILED_NAME);
+ intentWithdrawRequestedEventMetric =
+ new EventMetric(metricsService, COMPONENT_NAME,
+ FEATURE_WITHDRAW_REQUESTED_NAME);
+ intentWithdrawnEventMetric =
+ new EventMetric(metricsService, COMPONENT_NAME,
+ FEATURE_WITHDRAWN_NAME);
+ intentPurgedEventMetric =
+ new EventMetric(metricsService, COMPONENT_NAME,
+ FEATURE_PURGED_NAME);
+
+ intentSubmittedEventMetric.registerMetrics();
+ intentInstalledEventMetric.registerMetrics();
+ intentFailedEventMetric.registerMetrics();
+ intentWithdrawRequestedEventMetric.registerMetrics();
+ intentWithdrawnEventMetric.registerMetrics();
+ intentPurgedEventMetric.registerMetrics();
+ }
+
+ /**
+ * Removes the metrics.
+ */
+ private void removeMetrics() {
+ intentSubmittedEventMetric.removeMetrics();
+ intentInstalledEventMetric.removeMetrics();
+ intentFailedEventMetric.removeMetrics();
+ intentWithdrawRequestedEventMetric.removeMetrics();
+ intentWithdrawnEventMetric.removeMetrics();
+ intentPurgedEventMetric.removeMetrics();
+ }
+}
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/IntentMetricsService.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/IntentMetricsService.java
new file mode 100644
index 00000000..aa03e390
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/IntentMetricsService.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+package org.onosproject.metrics.intent;
+
+import java.util.List;
+import org.onlab.metrics.EventMetric;
+import org.onosproject.net.intent.IntentEvent;
+
+/**
+ * Service interface exported by IntentMetrics.
+ */
+public interface IntentMetricsService {
+ /**
+ * Gets the last saved intent events.
+ *
+ * @return the last saved intent events
+ */
+ List<IntentEvent> getEvents();
+
+ /**
+ * Gets the Event Metric for the intent INSTALL_REQ events.
+ *
+ * @return the Event Metric for the intent INSTALL_REQ events
+ */
+ EventMetric intentSubmittedEventMetric();
+
+ /**
+ * Gets the Event Metric for the intent INSTALLED events.
+ *
+ * @return the Event Metric for the intent INSTALLED events
+ */
+ EventMetric intentInstalledEventMetric();
+
+ /**
+ * Gets the Event Metric for the intent FAILED events.
+ *
+ * @return the Event Metric for the intent FAILED events
+ */
+ EventMetric intentFailedEventMetric();
+
+ /**
+ * Gets the Event Metric for the intent WITHDRAW_REQ events.
+ *
+ * @return the Event Metric for the intent WITHDRAW_REQ events
+ */
+ EventMetric intentWithdrawRequestedEventMetric();
+
+ /**
+ * Gets the Event Metric for the intent WITHDRAWN events.
+ *
+ * @return the Event Metric for the intent WITHDRAWN events
+ */
+ EventMetric intentWithdrawnEventMetric();
+
+ /**
+ * Gets the Event Metric for the intent PURGED events.
+ *
+ * @return the Event Metric for the intent PURGED events
+ */
+ EventMetric intentPurgedEventMetric();
+}
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/IntentEventsListCommand.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/IntentEventsListCommand.java
new file mode 100644
index 00000000..3c8457ad
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/IntentEventsListCommand.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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.
+ */
+package org.onosproject.metrics.intent.cli;
+
+import java.util.List;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.metrics.intent.IntentMetricsService;
+import org.onosproject.net.intent.IntentEvent;
+
+/**
+ * Command to show the list of last intent events.
+ */
+@Command(scope = "onos", name = "intents-events",
+ description = "Lists the last intent events")
+public class IntentEventsListCommand extends AbstractShellCommand {
+
+ private static final String FORMAT_EVENT = "Event=%s";
+
+ @Override
+ protected void execute() {
+ IntentMetricsService service = get(IntentMetricsService.class);
+
+ if (outputJson()) {
+ print("%s", json(service.getEvents()));
+ } else {
+ for (IntentEvent event : service.getEvents()) {
+ print(FORMAT_EVENT, event);
+ print(""); // Extra empty line for clarity
+ }
+ }
+ }
+
+ /**
+ * Produces a JSON array of intent events.
+ *
+ * @param intentEvents the intent events with the data
+ * @return JSON array with the intent events
+ */
+ private JsonNode json(List<IntentEvent> intentEvents) {
+ ObjectMapper mapper = new ObjectMapper();
+ ArrayNode result = mapper.createArrayNode();
+
+ for (IntentEvent event : intentEvents) {
+ result.add(json(mapper, event));
+ }
+ return result;
+ }
+
+ /**
+ * Produces JSON object for a intent event.
+ *
+ * @param mapper the JSON object mapper to use
+ * @param intentEvent the intent event with the data
+ * @return JSON object for the intent event
+ */
+ private ObjectNode json(ObjectMapper mapper, IntentEvent intentEvent) {
+ ObjectNode result = mapper.createObjectNode();
+
+ result.put("time", intentEvent.time())
+ .put("type", intentEvent.type().toString())
+ .put("event", intentEvent.toString());
+ return result;
+ }
+}
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/IntentEventsMetricsCommand.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/IntentEventsMetricsCommand.java
new file mode 100644
index 00000000..356b9ada
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/IntentEventsMetricsCommand.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+package org.onosproject.metrics.intent.cli;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.json.MetricsModule;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.metrics.EventMetric;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.metrics.intent.IntentMetricsService;
+
+/**
+ * Command to show the intent events metrics.
+ */
+@Command(scope = "onos", name = "intents-events-metrics",
+ description = "Lists intent events metrics")
+public class IntentEventsMetricsCommand extends AbstractShellCommand {
+
+ private static final String FORMAT_GAUGE =
+ "Intent %s Event Timestamp (ms from epoch)=%d";
+ private static final String FORMAT_METER =
+ "Intent %s Events count=%d rate(events/sec) mean=%f m1=%f m5=%f m15=%f";
+
+ @Override
+ protected void execute() {
+ IntentMetricsService service = get(IntentMetricsService.class);
+
+ if (outputJson()) {
+ ObjectMapper mapper = new ObjectMapper()
+ .registerModule(new MetricsModule(TimeUnit.SECONDS,
+ TimeUnit.MILLISECONDS,
+ false));
+ ObjectNode result = mapper.createObjectNode();
+ result = json(mapper, result, "intentSubmitted",
+ service.intentSubmittedEventMetric());
+ result = json(mapper, result, "intentInstalled",
+ service.intentInstalledEventMetric());
+ result = json(mapper, result, "intentFailed",
+ service.intentFailedEventMetric());
+ result = json(mapper, result, "intentWithdrawRequested",
+ service.intentWithdrawRequestedEventMetric());
+ result = json(mapper, result, "intentWithdrawn",
+ service.intentWithdrawnEventMetric());
+ result = json(mapper, result, "intentPurged",
+ service.intentPurgedEventMetric());
+ print("%s", result);
+ } else {
+ printEventMetric("Submitted",
+ service.intentSubmittedEventMetric());
+ printEventMetric("Installed",
+ service.intentInstalledEventMetric());
+ printEventMetric("Failed",
+ service.intentFailedEventMetric());
+ printEventMetric("Withdraw Requested",
+ service.intentWithdrawRequestedEventMetric());
+ printEventMetric("Withdrawn",
+ service.intentWithdrawnEventMetric());
+ printEventMetric("Purged",
+ service.intentPurgedEventMetric());
+ }
+ }
+
+ /**
+ * Produces JSON node for an Event Metric.
+ *
+ * @param mapper the JSON object mapper to use
+ * @param objectNode the JSON object node to use
+ * @param propertyPrefix the property prefix to use
+ * @param eventMetric the Event Metric with the data
+ * @return JSON object node for the Event Metric
+ */
+ private ObjectNode json(ObjectMapper mapper, ObjectNode objectNode,
+ String propertyPrefix, EventMetric eventMetric) {
+ String gaugeName = propertyPrefix + "Timestamp";
+ String meterName = propertyPrefix + "Rate";
+ Gauge<Long> gauge = eventMetric.lastEventTimestampGauge();
+ Meter meter = eventMetric.eventRateMeter();
+
+ objectNode.set(gaugeName, json(mapper, gauge));
+ objectNode.set(meterName, json(mapper, meter));
+ return objectNode;
+ }
+
+ /**
+ * Produces JSON node for an Object.
+ *
+ * @param mapper the JSON object mapper to use
+ * @param object the Object with the data
+ * @return JSON node for the Object
+ */
+ private JsonNode json(ObjectMapper mapper, Object object) {
+ //
+ // NOTE: The API for custom serializers is incomplete,
+ // hence we have to parse the JSON string to create JsonNode.
+ //
+ try {
+ final String objectJson = mapper.writeValueAsString(object);
+ JsonNode jsonNode = mapper.readTree(objectJson);
+ return jsonNode;
+ } catch (JsonProcessingException e) {
+ log.error("Error writing value as JSON string", e);
+ } catch (IOException e) {
+ log.error("Error writing value as JSON string", e);
+ }
+ return null;
+ }
+
+ /**
+ * Prints an Event Metric.
+ *
+ * @param operationStr the string with the intent operation to print
+ * @param eventMetric the Event Metric to print
+ */
+ private void printEventMetric(String operationStr,
+ EventMetric eventMetric) {
+ Gauge<Long> gauge = eventMetric.lastEventTimestampGauge();
+ Meter meter = eventMetric.eventRateMeter();
+ TimeUnit rateUnit = TimeUnit.SECONDS;
+ double rateFactor = rateUnit.toSeconds(1);
+
+ // Print the Gauge
+ print(FORMAT_GAUGE, operationStr, gauge.getValue());
+
+ // Print the Meter
+ print(FORMAT_METER, operationStr, meter.getCount(),
+ meter.getMeanRate() * rateFactor,
+ meter.getOneMinuteRate() * rateFactor,
+ meter.getFiveMinuteRate() * rateFactor,
+ meter.getFifteenMinuteRate() * rateFactor);
+ }
+}
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/package-info.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/package-info.java
new file mode 100644
index 00000000..ddc7877c
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/cli/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * Intent metrics command-line handlers.
+ */
+package org.onosproject.metrics.intent.cli;
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/package-info.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/package-info.java
new file mode 100644
index 00000000..9a7ac66c
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/intent/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * ONOS Intent Metrics Application that collects intent-related metrics.
+ */
+package org.onosproject.metrics.intent;
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/TopologyMetrics.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/TopologyMetrics.java
new file mode 100644
index 00000000..5785f5f2
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/TopologyMetrics.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+package org.onosproject.metrics.topology;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.metrics.EventMetric;
+import org.onlab.metrics.MetricsService;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.event.Event;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.link.LinkEvent;
+import org.onosproject.net.link.LinkListener;
+import org.onosproject.net.link.LinkService;
+import org.onosproject.net.topology.TopologyEvent;
+import org.onosproject.net.topology.TopologyListener;
+import org.onosproject.net.topology.TopologyService;
+import org.slf4j.Logger;
+
+/**
+ * ONOS Topology Metrics Application that collects topology-related metrics.
+ */
+@Component(immediate = true)
+@Service
+public class TopologyMetrics implements TopologyMetricsService {
+ private static final Logger log = getLogger(TopologyMetrics.class);
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @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 MetricsService metricsService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected TopologyService topologyService;
+
+ private ApplicationId appId;
+
+ 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
+ //
+ private static final String COMPONENT_NAME = "Topology";
+ private static final String FEATURE_DEVICE_NAME = "DeviceEvent";
+ private static final String FEATURE_HOST_NAME = "HostEvent";
+ private static final String FEATURE_LINK_NAME = "LinkEvent";
+ private static final String FEATURE_GRAPH_NAME = "GraphEvent";
+ private static final String FEATURE_GRAPH_REASONS_NAME = "GraphReasonsEvent";
+ //
+ // Event metrics:
+ // - Device events
+ // - Host events
+ // - Link events
+ // - Topology Graph events
+ // - Topology Graph Reasons events
+ //
+ private EventMetric topologyDeviceEventMetric;
+ private EventMetric topologyHostEventMetric;
+ private EventMetric topologyLinkEventMetric;
+ private EventMetric topologyGraphEventMetric;
+ private EventMetric topologyGraphReasonsEventMetric;
+
+ @Activate
+ protected void activate() {
+ appId = coreService.registerApplication("org.onosproject.metrics");
+
+ clear();
+ registerMetrics();
+
+ // Register for all topology-related events
+ deviceService.addListener(deviceListener);
+ hostService.addListener(hostListener);
+ linkService.addListener(linkListener);
+ topologyService.addListener(topologyListener);
+
+ log.info("Started with Application ID {}", appId.id());
+ }
+
+ @Deactivate
+ public void deactivate() {
+ // De-register from all topology-related events
+ deviceService.removeListener(deviceListener);
+ hostService.removeListener(hostListener);
+ linkService.removeListener(linkListener);
+ topologyService.removeListener(topologyListener);
+
+ removeMetrics();
+ clear();
+ log.info("Stopped");
+ }
+
+ @Override
+ public List<Event> getEvents() {
+ synchronized (lastEvents) {
+ return ImmutableList.<Event>copyOf(lastEvents);
+ }
+ }
+
+ @Override
+ public EventMetric topologyDeviceEventMetric() {
+ return topologyDeviceEventMetric;
+ }
+
+ @Override
+ public EventMetric topologyHostEventMetric() {
+ return topologyHostEventMetric;
+ }
+
+ @Override
+ public EventMetric topologyLinkEventMetric() {
+ return topologyLinkEventMetric;
+ }
+
+ @Override
+ public EventMetric topologyGraphEventMetric() {
+ return topologyGraphEventMetric;
+ }
+
+ @Override
+ public EventMetric topologyGraphReasonsEventMetric() {
+ return topologyGraphReasonsEventMetric;
+ }
+
+ /**
+ * Records an event.
+ *
+ * @param event the event to record
+ * @param eventMetric the Event Metric to use
+ */
+ private void recordEvent(Event event, EventMetric eventMetric) {
+ synchronized (lastEvents) {
+ eventMetric.eventReceived();
+
+ //
+ // Keep only the last N events, where N = LAST_EVENTS_MAX_N
+ //
+ while (lastEvents.size() >= LAST_EVENTS_MAX_N) {
+ lastEvents.remove();
+ }
+ lastEvents.add(event);
+ }
+ }
+
+ /**
+ * Inner Device Event Listener class.
+ */
+ private class InnerDeviceListener implements DeviceListener {
+ @Override
+ public void event(DeviceEvent event) {
+ // Ignore PORT_STATS_UPDATED probe event from interfering with
+ // other device event timestamps
+ if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
+ log.info("PORT_STATS_UPDATED event ignored from metrics");
+ } else {
+ recordEvent(event, topologyDeviceEventMetric);
+ log.info("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, topologyHostEventMetric);
+ 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, topologyLinkEventMetric);
+ 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) {
+ recordEvent(event, topologyGraphEventMetric);
+ log.debug("Topology Event: time = {} type = {} event = {}",
+ event.time(), event.type(), event);
+ for (Event reason : event.reasons()) {
+ recordEvent(event, topologyGraphReasonsEventMetric);
+ log.debug("Topology Event Reason: time = {} type = {} event = {}",
+ reason.time(), reason.type(), reason);
+ }
+ }
+ }
+
+ /**
+ * Clears the internal state.
+ */
+ private void clear() {
+ synchronized (lastEvents) {
+ lastEvents.clear();
+ }
+ }
+
+ /**
+ * Registers the metrics.
+ */
+ private void registerMetrics() {
+ topologyDeviceEventMetric =
+ new EventMetric(metricsService, COMPONENT_NAME,
+ FEATURE_DEVICE_NAME);
+ topologyHostEventMetric =
+ new EventMetric(metricsService, COMPONENT_NAME,
+ FEATURE_HOST_NAME);
+ topologyLinkEventMetric =
+ new EventMetric(metricsService, COMPONENT_NAME,
+ FEATURE_LINK_NAME);
+ topologyGraphEventMetric =
+ new EventMetric(metricsService, COMPONENT_NAME,
+ FEATURE_GRAPH_NAME);
+ topologyGraphReasonsEventMetric =
+ new EventMetric(metricsService, COMPONENT_NAME,
+ FEATURE_GRAPH_REASONS_NAME);
+
+ topologyDeviceEventMetric.registerMetrics();
+ topologyHostEventMetric.registerMetrics();
+ topologyLinkEventMetric.registerMetrics();
+ topologyGraphEventMetric.registerMetrics();
+ topologyGraphReasonsEventMetric.registerMetrics();
+ }
+
+ /**
+ * Removes the metrics.
+ */
+ private void removeMetrics() {
+ topologyDeviceEventMetric.removeMetrics();
+ topologyHostEventMetric.removeMetrics();
+ topologyLinkEventMetric.removeMetrics();
+ topologyGraphEventMetric.removeMetrics();
+ topologyGraphReasonsEventMetric.removeMetrics();
+ }
+}
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/TopologyMetricsService.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/TopologyMetricsService.java
new file mode 100644
index 00000000..47e46b28
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/TopologyMetricsService.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+package org.onosproject.metrics.topology;
+
+import java.util.List;
+import org.onlab.metrics.EventMetric;
+import org.onosproject.event.Event;
+
+/**
+ * Service interface exported by TopologyMetrics.
+ */
+public interface TopologyMetricsService {
+ /**
+ * Gets the last saved topology events.
+ *
+ * @return the last saved topology events
+ */
+ List<Event> getEvents();
+
+ /**
+ * Gets the Event Metric for the Device Events.
+ *
+ * @return the Event Metric for the Device Events
+ */
+ EventMetric topologyDeviceEventMetric();
+
+ /**
+ * Gets the Event Metric for the Host Events.
+ *
+ * @return the Event Metric for the Host Events
+ */
+ EventMetric topologyHostEventMetric();
+
+ /**
+ * Gets the Event Metric for the Link Events.
+ *
+ * @return the Event Metric for the Link Events
+ */
+ EventMetric topologyLinkEventMetric();
+
+ /**
+ * Gets the Event Metric for the Topology Graph Events.
+ *
+ * @return the Event Metric for the Topology Graph Events
+ */
+ EventMetric topologyGraphEventMetric();
+
+ /**
+ * Gets the Event Metric for the Topology Graph Reasons Events.
+ *
+ * @return the Event Metric for the Topology Graph Reasons Events
+ */
+ EventMetric topologyGraphReasonsEventMetric();
+}
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/TopologyEventsListCommand.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/TopologyEventsListCommand.java
new file mode 100644
index 00000000..a070ed8d
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/TopologyEventsListCommand.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+package org.onosproject.metrics.topology.cli;
+
+import java.util.List;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.event.Event;
+import org.onosproject.metrics.topology.TopologyMetricsService;
+import org.onosproject.net.topology.TopologyEvent;
+
+/**
+ * Command to show the list of last topology events.
+ */
+@Command(scope = "onos", name = "topology-events",
+ description = "Lists the last topology events")
+public class TopologyEventsListCommand extends AbstractShellCommand {
+
+ private static final String FORMAT_EVENT = "Event=%s";
+ private static final String FORMAT_REASON = " Reason=%s";
+
+ @Override
+ protected void execute() {
+ TopologyMetricsService service = get(TopologyMetricsService.class);
+
+ if (outputJson()) {
+ print("%s", json(service.getEvents()));
+ } else {
+ 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
+ }
+ }
+ }
+
+ /**
+ * Produces a JSON array of topology events.
+ *
+ * @param events the topology events with the data
+ * @return JSON array with the topology events
+ */
+ private JsonNode json(List<Event> events) {
+ ObjectMapper mapper = new ObjectMapper();
+ ArrayNode result = mapper.createArrayNode();
+
+ for (Event event : events) {
+ result.add(json(mapper, event));
+ }
+ return result;
+ }
+
+ /**
+ * Produces JSON object for a topology event.
+ *
+ * @param mapper the JSON object mapper to use
+ * @param event the topology event with the data
+ * @return JSON object for the topology event
+ */
+ private ObjectNode json(ObjectMapper mapper, Event event) {
+ ObjectNode result = mapper.createObjectNode();
+
+ result.put("time", event.time())
+ .put("type", event.type().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.set("reasons", reasons);
+ }
+
+ return result;
+ }
+}
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/TopologyEventsMetricsCommand.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/TopologyEventsMetricsCommand.java
new file mode 100644
index 00000000..0fbbc053
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/TopologyEventsMetricsCommand.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+package org.onosproject.metrics.topology.cli;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.json.MetricsModule;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.metrics.EventMetric;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.metrics.topology.TopologyMetricsService;
+
+/**
+ * Command to show the topology events metrics.
+ */
+@Command(scope = "onos", name = "topology-events-metrics",
+ description = "Lists topology events metrics")
+public class TopologyEventsMetricsCommand extends AbstractShellCommand {
+
+ private static final String FORMAT_GAUGE =
+ "Topology %s Event Timestamp (ms from epoch)=%d";
+ private static final String FORMAT_METER =
+ "Topology %s Events count=%d rate(events/sec) mean=%f m1=%f m5=%f m15=%f";
+
+ @Override
+ protected void execute() {
+ TopologyMetricsService service = get(TopologyMetricsService.class);
+
+ if (outputJson()) {
+ ObjectMapper mapper = new ObjectMapper()
+ .registerModule(new MetricsModule(TimeUnit.SECONDS,
+ TimeUnit.MILLISECONDS,
+ false));
+ ObjectNode result = mapper.createObjectNode();
+ result = json(mapper, result, "topologyDeviceEvent",
+ service.topologyDeviceEventMetric());
+ result = json(mapper, result, "topologyHostEvent",
+ service.topologyHostEventMetric());
+ result = json(mapper, result, "topologyLinkEvent",
+ service.topologyLinkEventMetric());
+ result = json(mapper, result, "topologyGraphEvent",
+ service.topologyGraphEventMetric());
+ result = json(mapper, result, "topologyGraphReasonsEvent",
+ service.topologyGraphReasonsEventMetric());
+ print("%s", result);
+ } else {
+ printEventMetric("Device", service.topologyDeviceEventMetric());
+ printEventMetric("Host", service.topologyHostEventMetric());
+ printEventMetric("Link", service.topologyLinkEventMetric());
+ printEventMetric("Graph", service.topologyGraphEventMetric());
+ printEventMetric("Graph Reasons",
+ service.topologyGraphReasonsEventMetric());
+ }
+ }
+
+ /**
+ * Produces JSON node for an Event Metric.
+ *
+ * @param mapper the JSON object mapper to use
+ * @param objectNode the JSON object node to use
+ * @param propertyPrefix the property prefix to use
+ * @param eventMetric the Event Metric with the data
+ * @return JSON object node for the Event Metric
+ */
+ private ObjectNode json(ObjectMapper mapper, ObjectNode objectNode,
+ String propertyPrefix, EventMetric eventMetric) {
+ String gaugeName = propertyPrefix + "Timestamp";
+ String meterName = propertyPrefix + "Rate";
+ Gauge<Long> gauge = eventMetric.lastEventTimestampGauge();
+ Meter meter = eventMetric.eventRateMeter();
+
+ objectNode.set(gaugeName, json(mapper, gauge));
+ objectNode.set(meterName, json(mapper, meter));
+ return objectNode;
+ }
+
+ /**
+ * Produces JSON node for an Object.
+ *
+ * @param mapper the JSON object mapper to use
+ * @param object the Object with the data
+ * @return JSON node for the Object
+ */
+ private JsonNode json(ObjectMapper mapper, Object object) {
+ //
+ // NOTE: The API for custom serializers is incomplete,
+ // hence we have to parse the JSON string to create JsonNode.
+ //
+ try {
+ final String objectJson = mapper.writeValueAsString(object);
+ JsonNode jsonNode = mapper.readTree(objectJson);
+ return jsonNode;
+ } catch (JsonProcessingException e) {
+ log.error("Error writing value as JSON string", e);
+ } catch (IOException e) {
+ log.error("Error writing value as JSON string", e);
+ }
+ return null;
+ }
+
+ /**
+ * Prints an Event Metric.
+ *
+ * @param operationStr the string with the intent operation to print
+ * @param eventMetric the Event Metric to print
+ */
+ private void printEventMetric(String operationStr,
+ EventMetric eventMetric) {
+ Gauge<Long> gauge = eventMetric.lastEventTimestampGauge();
+ Meter meter = eventMetric.eventRateMeter();
+ TimeUnit rateUnit = TimeUnit.SECONDS;
+ double rateFactor = rateUnit.toSeconds(1);
+
+ // Print the Gauge
+ print(FORMAT_GAUGE, operationStr, gauge.getValue());
+
+ // Print the Meter
+ print(FORMAT_METER, operationStr, meter.getCount(),
+ meter.getMeanRate() * rateFactor,
+ meter.getOneMinuteRate() * rateFactor,
+ meter.getFiveMinuteRate() * rateFactor,
+ meter.getFifteenMinuteRate() * rateFactor);
+ }
+}
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/package-info.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/package-info.java
new file mode 100644
index 00000000..f8402bea
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/cli/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * Topology metrics command-line handlers.
+ */
+package org.onosproject.metrics.topology.cli;
diff --git a/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/package-info.java b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/package-info.java
new file mode 100644
index 00000000..b35d85ce
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/java/org/onosproject/metrics/topology/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * ONOS Topology Metrics Application that collects topology-related metrics.
+ */
+package org.onosproject.metrics.topology;
diff --git a/framework/src/onos/apps/metrics/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/metrics/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 00000000..c2d82418
--- /dev/null
+++ b/framework/src/onos/apps/metrics/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,32 @@
+<!--
+ ~ Copyright 2014 Open Networking Laboratory
+ ~
+ ~ 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.
+ -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.onosproject.metrics.intent.cli.IntentEventsListCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.metrics.intent.cli.IntentEventsMetricsCommand"/>
+ </command>
+
+ <command>
+ <action class="org.onosproject.metrics.topology.cli.TopologyEventsListCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.metrics.topology.cli.TopologyEventsMetricsCommand"/>
+ </command>
+ </command-bundle>
+</blueprint>