Showing
12 changed files
with
790 additions
and
57 deletions
apps/metrics/intent/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
5 | + <modelVersion>4.0.0</modelVersion> | ||
6 | + | ||
7 | + <parent> | ||
8 | + <groupId>org.onlab.onos</groupId> | ||
9 | + <artifactId>onos-app-metrics</artifactId> | ||
10 | + <version>1.0.0-SNAPSHOT</version> | ||
11 | + <relativePath>../pom.xml</relativePath> | ||
12 | + </parent> | ||
13 | + | ||
14 | + <artifactId>onos-app-metrics-intent</artifactId> | ||
15 | + <packaging>bundle</packaging> | ||
16 | + | ||
17 | + <description>ONOS intent metrics application</description> | ||
18 | + | ||
19 | + <dependencies> | ||
20 | + <dependency> | ||
21 | + <groupId>org.onlab.onos</groupId> | ||
22 | + <artifactId>onos-cli</artifactId> | ||
23 | + <version>${project.version}</version> | ||
24 | + </dependency> | ||
25 | + | ||
26 | + <dependency> | ||
27 | + <groupId>org.apache.karaf.shell</groupId> | ||
28 | + <artifactId>org.apache.karaf.shell.console</artifactId> | ||
29 | + </dependency> | ||
30 | + </dependencies> | ||
31 | + | ||
32 | +</project> |
1 | +package org.onlab.onos.metrics.intent; | ||
2 | + | ||
3 | +import static org.slf4j.LoggerFactory.getLogger; | ||
4 | + | ||
5 | +import java.util.LinkedList; | ||
6 | +import java.util.List; | ||
7 | + | ||
8 | +import com.codahale.metrics.Gauge; | ||
9 | +import com.codahale.metrics.Meter; | ||
10 | +import com.google.common.collect.ImmutableList; | ||
11 | +import org.apache.felix.scr.annotations.Activate; | ||
12 | +import org.apache.felix.scr.annotations.Component; | ||
13 | +import org.apache.felix.scr.annotations.Deactivate; | ||
14 | +import org.apache.felix.scr.annotations.Reference; | ||
15 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
16 | +import org.apache.felix.scr.annotations.Service; | ||
17 | +import org.onlab.metrics.MetricsComponent; | ||
18 | +import org.onlab.metrics.MetricsFeature; | ||
19 | +import org.onlab.metrics.MetricsService; | ||
20 | +import org.onlab.onos.net.intent.IntentEvent; | ||
21 | +import org.onlab.onos.net.intent.IntentListener; | ||
22 | +import org.onlab.onos.net.intent.IntentService; | ||
23 | +import org.slf4j.Logger; | ||
24 | + | ||
25 | +/** | ||
26 | + * ONOS Intent Metrics Application that collects intent-related metrics. | ||
27 | + */ | ||
28 | +@Component(immediate = true) | ||
29 | +@Service | ||
30 | +public class IntentMetrics implements IntentMetricsService, | ||
31 | + IntentListener { | ||
32 | + private static final Logger log = getLogger(IntentMetrics.class); | ||
33 | + | ||
34 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
35 | + protected IntentService intentService; | ||
36 | + private LinkedList<IntentEvent> lastEvents = new LinkedList<>(); | ||
37 | + private static final int LAST_EVENTS_MAX_N = 100; | ||
38 | + | ||
39 | + // | ||
40 | + // Metrics | ||
41 | + // | ||
42 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
43 | + protected MetricsService metricsService; | ||
44 | + // | ||
45 | + private static final String COMPONENT_NAME = "Intent"; | ||
46 | + private static final String FEATURE_SUBMITTED_NAME = "Submitted"; | ||
47 | + private static final String FEATURE_INSTALLED_NAME = "Installed"; | ||
48 | + private static final String FEATURE_WITHDRAW_REQUESTED_NAME = | ||
49 | + "WithdrawRequested"; | ||
50 | + private static final String FEATURE_WITHDRAWN_NAME = "Withdrawn"; | ||
51 | + private static final String GAUGE_TIMESTAMP_NAME = "Timestamp.EpochMs"; | ||
52 | + private static final String METER_RATE_NAME = "Rate"; | ||
53 | + // | ||
54 | + private MetricsComponent metricsComponent; | ||
55 | + private MetricsFeature metricsFeatureSubmitted; | ||
56 | + private MetricsFeature metricsFeatureInstalled; | ||
57 | + private MetricsFeature metricsFeatureWithdrawRequested; | ||
58 | + private MetricsFeature metricsFeatureWithdrawn; | ||
59 | + // | ||
60 | + // Timestamps: | ||
61 | + // - Intent Submitted API operation (ms from the Epoch) | ||
62 | + // - Intent Installed operation completion (ms from the Epoch) | ||
63 | + // - Intent Withdraw Requested API operation (ms from the Epoch) | ||
64 | + // - Intent Withdrawn operation completion (ms from the Epoch) | ||
65 | + // | ||
66 | + private volatile long intentSubmittedTimestampEpochMs = 0; | ||
67 | + private volatile long intentInstalledTimestampEpochMs = 0; | ||
68 | + private volatile long intentWithdrawRequestedTimestampEpochMs = 0; | ||
69 | + private volatile long intentWithdrawnTimestampEpochMs = 0; | ||
70 | + // | ||
71 | + private Gauge<Long> intentSubmittedTimestampEpochMsGauge; | ||
72 | + private Gauge<Long> intentInstalledTimestampEpochMsGauge; | ||
73 | + private Gauge<Long> intentWithdrawRequestedTimestampEpochMsGauge; | ||
74 | + private Gauge<Long> intentWithdrawnTimestampEpochMsGauge; | ||
75 | + // | ||
76 | + // Rate meters: | ||
77 | + // - Rate of the Submitted Intent API operations | ||
78 | + // - Rate of the Installed Intent operations | ||
79 | + // - Rate of the Withdrawn Requested Intent API operations | ||
80 | + // - Rate of the Withdrawn Intent operations | ||
81 | + // | ||
82 | + private Meter intentSubmittedRateMeter; | ||
83 | + private Meter intentInstalledRateMeter; | ||
84 | + private Meter intentWithdrawRequestedRateMeter; | ||
85 | + private Meter intentWithdrawnRateMeter; | ||
86 | + | ||
87 | + @Activate | ||
88 | + protected void activate() { | ||
89 | + clear(); | ||
90 | + registerMetrics(); | ||
91 | + intentService.addListener(this); | ||
92 | + log.info("ONOS Intent Metrics started."); | ||
93 | + } | ||
94 | + | ||
95 | + @Deactivate | ||
96 | + public void deactivate() { | ||
97 | + intentService.removeListener(this); | ||
98 | + removeMetrics(); | ||
99 | + clear(); | ||
100 | + log.info("ONOS Intent Metrics stopped."); | ||
101 | + } | ||
102 | + | ||
103 | + @Override | ||
104 | + public List<IntentEvent> getEvents() { | ||
105 | + synchronized (lastEvents) { | ||
106 | + return ImmutableList.<IntentEvent>copyOf(lastEvents); | ||
107 | + } | ||
108 | + } | ||
109 | + | ||
110 | + @Override | ||
111 | + public Gauge<Long> intentSubmittedTimestampEpochMsGauge() { | ||
112 | + return intentSubmittedTimestampEpochMsGauge; | ||
113 | + } | ||
114 | + | ||
115 | + @Override | ||
116 | + public Gauge<Long> intentInstalledTimestampEpochMsGauge() { | ||
117 | + return intentInstalledTimestampEpochMsGauge; | ||
118 | + } | ||
119 | + | ||
120 | + @Override | ||
121 | + public Gauge<Long> intentWithdrawRequestedTimestampEpochMsGauge() { | ||
122 | + return intentWithdrawRequestedTimestampEpochMsGauge; | ||
123 | + } | ||
124 | + | ||
125 | + @Override | ||
126 | + public Gauge<Long> intentWithdrawnTimestampEpochMsGauge() { | ||
127 | + return intentWithdrawnTimestampEpochMsGauge; | ||
128 | + } | ||
129 | + | ||
130 | + @Override | ||
131 | + public Meter intentSubmittedRateMeter() { | ||
132 | + return intentSubmittedRateMeter; | ||
133 | + } | ||
134 | + | ||
135 | + @Override | ||
136 | + public Meter intentInstalledRateMeter() { | ||
137 | + return intentInstalledRateMeter; | ||
138 | + } | ||
139 | + | ||
140 | + @Override | ||
141 | + public Meter intentWithdrawRequestedRateMeter() { | ||
142 | + return intentWithdrawRequestedRateMeter; | ||
143 | + } | ||
144 | + | ||
145 | + @Override | ||
146 | + public Meter intentWithdrawnRateMeter() { | ||
147 | + return intentWithdrawnRateMeter; | ||
148 | + } | ||
149 | + | ||
150 | + @Override | ||
151 | + public void event(IntentEvent event) { | ||
152 | + synchronized (lastEvents) { | ||
153 | + // | ||
154 | + // TODO: The processing below is incomplete: we don't have | ||
155 | + // an event equivalent of "Withdraw Requested" | ||
156 | + // | ||
157 | + switch (event.type()) { | ||
158 | + case SUBMITTED: | ||
159 | + intentSubmittedTimestampEpochMs = System.currentTimeMillis(); | ||
160 | + intentSubmittedRateMeter.mark(1); | ||
161 | + break; | ||
162 | + case INSTALLED: | ||
163 | + intentInstalledTimestampEpochMs = System.currentTimeMillis(); | ||
164 | + intentInstalledRateMeter.mark(1); | ||
165 | + break; | ||
166 | + case FAILED: | ||
167 | + // TODO: Just ignore? | ||
168 | + break; | ||
169 | + /* | ||
170 | + case WITHDRAW_REQUESTED: | ||
171 | + intentWithdrawRequestedTimestampEpochMs = | ||
172 | + System.currentTimeMillis(); | ||
173 | + intentWithdrawRequestedRateMeter.mark(1); | ||
174 | + break; | ||
175 | + */ | ||
176 | + case WITHDRAWN: | ||
177 | + intentWithdrawnTimestampEpochMs = System.currentTimeMillis(); | ||
178 | + intentWithdrawnRateMeter.mark(1); | ||
179 | + break; | ||
180 | + default: | ||
181 | + break; | ||
182 | + } | ||
183 | + | ||
184 | + // | ||
185 | + // Keep only the last N events, where N = LAST_EVENTS_MAX_N | ||
186 | + // | ||
187 | + while (lastEvents.size() >= LAST_EVENTS_MAX_N) { | ||
188 | + lastEvents.remove(); | ||
189 | + } | ||
190 | + lastEvents.add(event); | ||
191 | + } | ||
192 | + | ||
193 | + log.debug("Intent Event: time = {} type = {} event = {}", | ||
194 | + event.time(), event.type(), event); | ||
195 | + } | ||
196 | + | ||
197 | + /** | ||
198 | + * Clears the internal state. | ||
199 | + */ | ||
200 | + private void clear() { | ||
201 | + synchronized (lastEvents) { | ||
202 | + intentSubmittedTimestampEpochMs = 0; | ||
203 | + intentInstalledTimestampEpochMs = 0; | ||
204 | + intentWithdrawRequestedTimestampEpochMs = 0; | ||
205 | + intentWithdrawnTimestampEpochMs = 0; | ||
206 | + lastEvents.clear(); | ||
207 | + } | ||
208 | + } | ||
209 | + | ||
210 | + /** | ||
211 | + * Registers the metrics. | ||
212 | + */ | ||
213 | + private void registerMetrics() { | ||
214 | + metricsComponent = metricsService.registerComponent(COMPONENT_NAME); | ||
215 | + // | ||
216 | + metricsFeatureSubmitted = | ||
217 | + metricsComponent.registerFeature(FEATURE_SUBMITTED_NAME); | ||
218 | + metricsFeatureInstalled = | ||
219 | + metricsComponent.registerFeature(FEATURE_INSTALLED_NAME); | ||
220 | + metricsFeatureWithdrawRequested = | ||
221 | + metricsComponent.registerFeature(FEATURE_WITHDRAW_REQUESTED_NAME); | ||
222 | + metricsFeatureWithdrawn = | ||
223 | + metricsComponent.registerFeature(FEATURE_WITHDRAWN_NAME); | ||
224 | + // | ||
225 | + intentSubmittedTimestampEpochMsGauge = | ||
226 | + metricsService.registerMetric(metricsComponent, | ||
227 | + metricsFeatureSubmitted, | ||
228 | + GAUGE_TIMESTAMP_NAME, | ||
229 | + new Gauge<Long>() { | ||
230 | + @Override | ||
231 | + public Long getValue() { | ||
232 | + return intentSubmittedTimestampEpochMs; | ||
233 | + } | ||
234 | + }); | ||
235 | + // | ||
236 | + intentInstalledTimestampEpochMsGauge = | ||
237 | + metricsService.registerMetric(metricsComponent, | ||
238 | + metricsFeatureInstalled, | ||
239 | + GAUGE_TIMESTAMP_NAME, | ||
240 | + new Gauge<Long>() { | ||
241 | + @Override | ||
242 | + public Long getValue() { | ||
243 | + return intentInstalledTimestampEpochMs; | ||
244 | + } | ||
245 | + }); | ||
246 | + // | ||
247 | + intentWithdrawRequestedTimestampEpochMsGauge = | ||
248 | + metricsService.registerMetric(metricsComponent, | ||
249 | + metricsFeatureWithdrawRequested, | ||
250 | + GAUGE_TIMESTAMP_NAME, | ||
251 | + new Gauge<Long>() { | ||
252 | + @Override | ||
253 | + public Long getValue() { | ||
254 | + return intentWithdrawRequestedTimestampEpochMs; | ||
255 | + } | ||
256 | + }); | ||
257 | + // | ||
258 | + intentWithdrawnTimestampEpochMsGauge = | ||
259 | + metricsService.registerMetric(metricsComponent, | ||
260 | + metricsFeatureWithdrawn, | ||
261 | + GAUGE_TIMESTAMP_NAME, | ||
262 | + new Gauge<Long>() { | ||
263 | + @Override | ||
264 | + public Long getValue() { | ||
265 | + return intentWithdrawnTimestampEpochMs; | ||
266 | + } | ||
267 | + }); | ||
268 | + // | ||
269 | + intentSubmittedRateMeter = | ||
270 | + metricsService.createMeter(metricsComponent, | ||
271 | + metricsFeatureSubmitted, | ||
272 | + METER_RATE_NAME); | ||
273 | + // | ||
274 | + intentInstalledRateMeter = | ||
275 | + metricsService.createMeter(metricsComponent, | ||
276 | + metricsFeatureInstalled, | ||
277 | + METER_RATE_NAME); | ||
278 | + // | ||
279 | + intentWithdrawRequestedRateMeter = | ||
280 | + metricsService.createMeter(metricsComponent, | ||
281 | + metricsFeatureWithdrawRequested, | ||
282 | + METER_RATE_NAME); | ||
283 | + // | ||
284 | + intentWithdrawnRateMeter = | ||
285 | + metricsService.createMeter(metricsComponent, | ||
286 | + metricsFeatureWithdrawn, | ||
287 | + METER_RATE_NAME); | ||
288 | + } | ||
289 | + | ||
290 | + /** | ||
291 | + * Removes the metrics. | ||
292 | + */ | ||
293 | + private void removeMetrics() { | ||
294 | + metricsService.removeMetric(metricsComponent, | ||
295 | + metricsFeatureSubmitted, | ||
296 | + GAUGE_TIMESTAMP_NAME); | ||
297 | + metricsService.removeMetric(metricsComponent, | ||
298 | + metricsFeatureInstalled, | ||
299 | + GAUGE_TIMESTAMP_NAME); | ||
300 | + metricsService.removeMetric(metricsComponent, | ||
301 | + metricsFeatureWithdrawRequested, | ||
302 | + GAUGE_TIMESTAMP_NAME); | ||
303 | + metricsService.removeMetric(metricsComponent, | ||
304 | + metricsFeatureWithdrawn, | ||
305 | + GAUGE_TIMESTAMP_NAME); | ||
306 | + metricsService.removeMetric(metricsComponent, | ||
307 | + metricsFeatureSubmitted, | ||
308 | + METER_RATE_NAME); | ||
309 | + metricsService.removeMetric(metricsComponent, | ||
310 | + metricsFeatureInstalled, | ||
311 | + METER_RATE_NAME); | ||
312 | + metricsService.removeMetric(metricsComponent, | ||
313 | + metricsFeatureWithdrawRequested, | ||
314 | + METER_RATE_NAME); | ||
315 | + metricsService.removeMetric(metricsComponent, | ||
316 | + metricsFeatureWithdrawn, | ||
317 | + METER_RATE_NAME); | ||
318 | + } | ||
319 | +} |
apps/metrics/intent/src/main/java/org/onlab/onos/metrics/intent/IntentMetricsService.java
0 → 100644
1 | +package org.onlab.onos.metrics.intent; | ||
2 | + | ||
3 | +import java.util.List; | ||
4 | + | ||
5 | +import com.codahale.metrics.Gauge; | ||
6 | +import com.codahale.metrics.Meter; | ||
7 | +import org.onlab.onos.net.intent.IntentEvent; | ||
8 | + | ||
9 | +/** | ||
10 | + * Service interface exported by IntentMetrics. | ||
11 | + */ | ||
12 | +public interface IntentMetricsService { | ||
13 | + /** | ||
14 | + * Gets the last saved intent events. | ||
15 | + * | ||
16 | + * @return the last saved intent events. | ||
17 | + */ | ||
18 | + public List<IntentEvent> getEvents(); | ||
19 | + | ||
20 | + /** | ||
21 | + * Gets the Metrics' Gauge for the intent SUBMITTED event timestamp | ||
22 | + * (ms from the epoch). | ||
23 | + * | ||
24 | + * @return the Metrics' Gauge for the intent SUBMITTED event timestamp | ||
25 | + * (ms from the epoch) | ||
26 | + */ | ||
27 | + public Gauge<Long> intentSubmittedTimestampEpochMsGauge(); | ||
28 | + | ||
29 | + /** | ||
30 | + * Gets the Metrics' Gauge for the intent INSTALLED event timestamp | ||
31 | + * (ms from the epoch). | ||
32 | + * | ||
33 | + * @return the Metrics' Gauge for the intent INSTALLED event timestamp | ||
34 | + * (ms from the epoch) | ||
35 | + */ | ||
36 | + public Gauge<Long> intentInstalledTimestampEpochMsGauge(); | ||
37 | + | ||
38 | + /** | ||
39 | + * Gets the Metrics' Gauge for the intent WITHDRAW_REQUESTED event | ||
40 | + * timestamp (ms from the epoch). | ||
41 | + * | ||
42 | + * TODO: This intent event is not implemented yet. | ||
43 | + * | ||
44 | + * @return the Metrics' Gauge for the intent WITHDRAW_REQUESTED event | ||
45 | + * timestamp (ms from the epoch) | ||
46 | + */ | ||
47 | + public Gauge<Long> intentWithdrawRequestedTimestampEpochMsGauge(); | ||
48 | + | ||
49 | + /** | ||
50 | + * Gets the Metrics' Gauge for the intent WITHDRAWN event timestamp | ||
51 | + * (ms from the epoch). | ||
52 | + * | ||
53 | + * @return the Metrics' Gauge for the intent WITHDRAWN event timestamp | ||
54 | + * (ms from the epoch) | ||
55 | + */ | ||
56 | + public Gauge<Long> intentWithdrawnTimestampEpochMsGauge(); | ||
57 | + | ||
58 | + /** | ||
59 | + * Gets the Metrics' Meter for the submitted intents event rate. | ||
60 | + * | ||
61 | + * @return the Metrics' Meter for the submitted intents event rate | ||
62 | + */ | ||
63 | + public Meter intentSubmittedRateMeter(); | ||
64 | + | ||
65 | + /** | ||
66 | + * Gets the Metrics' Meter for the installed intents event rate. | ||
67 | + * | ||
68 | + * @return the Metrics' Meter for the installed intent event rate | ||
69 | + */ | ||
70 | + public Meter intentInstalledRateMeter(); | ||
71 | + | ||
72 | + /** | ||
73 | + * Gets the Metrics' Meter for the withdraw requested intents event rate. | ||
74 | + * | ||
75 | + * @return the Metrics' Meter for the withdraw requested intents event rate | ||
76 | + */ | ||
77 | + public Meter intentWithdrawRequestedRateMeter(); | ||
78 | + | ||
79 | + /** | ||
80 | + * Gets the Metrics' Meter for the withdraw completed intents event rate. | ||
81 | + * | ||
82 | + * @return the Metrics' Meter for the withdraw completed intents event rate | ||
83 | + */ | ||
84 | + public Meter intentWithdrawnRateMeter(); | ||
85 | +} |
apps/metrics/intent/src/main/java/org/onlab/onos/metrics/intent/cli/IntentEventsListCommand.java
0 → 100644
1 | +package org.onlab.onos.metrics.intent.cli; | ||
2 | + | ||
3 | +import java.util.List; | ||
4 | + | ||
5 | +import com.fasterxml.jackson.databind.JsonNode; | ||
6 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
7 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
8 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
9 | +import org.apache.karaf.shell.commands.Command; | ||
10 | +import org.onlab.onos.cli.AbstractShellCommand; | ||
11 | +import org.onlab.onos.metrics.intent.IntentMetricsService; | ||
12 | +import org.onlab.onos.net.intent.IntentEvent; | ||
13 | + | ||
14 | +/** | ||
15 | + * Command to show the list of last intent events. | ||
16 | + */ | ||
17 | +@Command(scope = "onos", name = "intents-events", | ||
18 | + description = "Lists the last intent events") | ||
19 | +public class IntentEventsListCommand extends AbstractShellCommand { | ||
20 | + | ||
21 | + private static final String FORMAT_EVENT = "Event=%s"; | ||
22 | + | ||
23 | + @Override | ||
24 | + protected void execute() { | ||
25 | + IntentMetricsService service = get(IntentMetricsService.class); | ||
26 | + | ||
27 | + if (outputJson()) { | ||
28 | + print("%s", json(service.getEvents())); | ||
29 | + } else { | ||
30 | + for (IntentEvent event : service.getEvents()) { | ||
31 | + print(FORMAT_EVENT, event); | ||
32 | + print(""); // Extra empty line for clarity | ||
33 | + } | ||
34 | + } | ||
35 | + } | ||
36 | + | ||
37 | + /** | ||
38 | + * Produces a JSON array of intent events. | ||
39 | + * | ||
40 | + * @param intentEvents the intent events with the data | ||
41 | + * @return JSON array with the intent events | ||
42 | + */ | ||
43 | + private JsonNode json(List<IntentEvent> intentEvents) { | ||
44 | + ObjectMapper mapper = new ObjectMapper(); | ||
45 | + ArrayNode result = mapper.createArrayNode(); | ||
46 | + | ||
47 | + for (IntentEvent event : intentEvents) { | ||
48 | + result.add(json(mapper, event)); | ||
49 | + } | ||
50 | + return result; | ||
51 | + } | ||
52 | + | ||
53 | + /** | ||
54 | + * Produces JSON object for a intent event. | ||
55 | + * | ||
56 | + * @param mapper the JSON object mapper to use | ||
57 | + * @param intentEvent the intent event with the data | ||
58 | + * @return JSON object for the intent event | ||
59 | + */ | ||
60 | + private ObjectNode json(ObjectMapper mapper, IntentEvent intentEvent) { | ||
61 | + ObjectNode result = mapper.createObjectNode(); | ||
62 | + | ||
63 | + result.put("time", intentEvent.time()) | ||
64 | + .put("type", intentEvent.type().toString()) | ||
65 | + .put("event", intentEvent.toString()); | ||
66 | + return result; | ||
67 | + } | ||
68 | +} |
apps/metrics/intent/src/main/java/org/onlab/onos/metrics/intent/cli/IntentEventsMetricsCommand.java
0 → 100644
1 | +package org.onlab.onos.metrics.intent.cli; | ||
2 | + | ||
3 | +import java.io.IOException; | ||
4 | +import java.util.concurrent.TimeUnit; | ||
5 | + | ||
6 | +import com.codahale.metrics.Gauge; | ||
7 | +import com.codahale.metrics.Meter; | ||
8 | +import com.codahale.metrics.json.MetricsModule; | ||
9 | +import com.fasterxml.jackson.core.JsonProcessingException; | ||
10 | +import com.fasterxml.jackson.databind.JsonNode; | ||
11 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
12 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
13 | +import org.apache.karaf.shell.commands.Command; | ||
14 | +import org.onlab.onos.cli.AbstractShellCommand; | ||
15 | +import org.onlab.onos.metrics.intent.IntentMetricsService; | ||
16 | + | ||
17 | +/** | ||
18 | + * Command to show the intent events metrics. | ||
19 | + */ | ||
20 | +@Command(scope = "onos", name = "intents-events-metrics", | ||
21 | + description = "Lists intent events metrics") | ||
22 | +public class IntentEventsMetricsCommand extends AbstractShellCommand { | ||
23 | + | ||
24 | + private static final String FORMAT_GAUGE = | ||
25 | + "Intent %s Event Timestamp (ms from epoch)=%d"; | ||
26 | + private static final String FORMAT_METER = | ||
27 | + "Intent %s Events count=%d rate(events/sec) mean=%f m1=%f m5=%f m15=%f"; | ||
28 | + | ||
29 | + @Override | ||
30 | + protected void execute() { | ||
31 | + IntentMetricsService service = get(IntentMetricsService.class); | ||
32 | + Gauge<Long> gauge; | ||
33 | + Meter meter; | ||
34 | + | ||
35 | + if (outputJson()) { | ||
36 | + ObjectMapper mapper = new ObjectMapper() | ||
37 | + .registerModule(new MetricsModule(TimeUnit.SECONDS, | ||
38 | + TimeUnit.MILLISECONDS, | ||
39 | + false)); | ||
40 | + ObjectNode result = mapper.createObjectNode(); | ||
41 | + // | ||
42 | + gauge = service.intentSubmittedTimestampEpochMsGauge(); | ||
43 | + result.put("intentSubmittedTimestamp", json(mapper, gauge)); | ||
44 | + gauge = service.intentInstalledTimestampEpochMsGauge(); | ||
45 | + result.put("intentInstalledTimestamp", json(mapper, gauge)); | ||
46 | + gauge = service.intentWithdrawRequestedTimestampEpochMsGauge(); | ||
47 | + result.put("intentWithdrawRequestedTimestamp", | ||
48 | + json(mapper, gauge)); | ||
49 | + gauge = service.intentWithdrawnTimestampEpochMsGauge(); | ||
50 | + result.put("intentWithdrawnTimestamp", json(mapper, gauge)); | ||
51 | + // | ||
52 | + meter = service.intentSubmittedRateMeter(); | ||
53 | + result.put("intentSubmittedRate", json(mapper, meter)); | ||
54 | + meter = service.intentInstalledRateMeter(); | ||
55 | + result.put("intentInstalledRate", json(mapper, meter)); | ||
56 | + meter = service.intentWithdrawRequestedRateMeter(); | ||
57 | + result.put("intentWithdrawRequestedRate", json(mapper, meter)); | ||
58 | + meter = service.intentWithdrawnRateMeter(); | ||
59 | + result.put("intentWithdrawnRate", json(mapper, meter)); | ||
60 | + // | ||
61 | + print("%s", result); | ||
62 | + } else { | ||
63 | + gauge = service.intentSubmittedTimestampEpochMsGauge(); | ||
64 | + printGauge("Submitted", gauge); | ||
65 | + gauge = service.intentInstalledTimestampEpochMsGauge(); | ||
66 | + printGauge("Installed", gauge); | ||
67 | + gauge = service.intentWithdrawRequestedTimestampEpochMsGauge(); | ||
68 | + printGauge("Withdraw Requested", gauge); | ||
69 | + gauge = service.intentWithdrawnTimestampEpochMsGauge(); | ||
70 | + printGauge("Withdrawn", gauge); | ||
71 | + // | ||
72 | + meter = service.intentSubmittedRateMeter(); | ||
73 | + printMeter("Submitted", meter); | ||
74 | + meter = service.intentInstalledRateMeter(); | ||
75 | + printMeter("Installed", meter); | ||
76 | + meter = service.intentWithdrawRequestedRateMeter(); | ||
77 | + printMeter("Withdraw Requested", meter); | ||
78 | + meter = service.intentWithdrawnRateMeter(); | ||
79 | + printMeter("Withdrawn", meter); | ||
80 | + } | ||
81 | + } | ||
82 | + | ||
83 | + /** | ||
84 | + * Produces JSON node for an Object. | ||
85 | + * | ||
86 | + * @param mapper the JSON object mapper to use | ||
87 | + * @param object the Object with the data | ||
88 | + * @return JSON node for the Object | ||
89 | + */ | ||
90 | + private JsonNode json(ObjectMapper mapper, Object object) { | ||
91 | + // | ||
92 | + // NOTE: The API for custom serializers is incomplete, | ||
93 | + // hence we have to parse the JSON string to create JsonNode. | ||
94 | + // | ||
95 | + try { | ||
96 | + final String objectJson = mapper.writeValueAsString(object); | ||
97 | + JsonNode objectNode = mapper.readTree(objectJson); | ||
98 | + return objectNode; | ||
99 | + } catch (JsonProcessingException e) { | ||
100 | + log.error("Error writing value as JSON string", e); | ||
101 | + } catch (IOException e) { | ||
102 | + log.error("Error writing value as JSON string", e); | ||
103 | + } | ||
104 | + return null; | ||
105 | + } | ||
106 | + | ||
107 | + /** | ||
108 | + * Prints a Gauge. | ||
109 | + * | ||
110 | + * @param operationStr the string with the intent operation to print | ||
111 | + * @param gauge the Gauge to print | ||
112 | + */ | ||
113 | + private void printGauge(String operationStr, Gauge<Long> gauge) { | ||
114 | + print(FORMAT_GAUGE, operationStr, gauge.getValue()); | ||
115 | + } | ||
116 | + | ||
117 | + /** | ||
118 | + * Prints a Meter. | ||
119 | + * | ||
120 | + * @param operationStr the string with the intent operation to print | ||
121 | + * @param meter the Meter to print | ||
122 | + */ | ||
123 | + private void printMeter(String operationStr, Meter meter) { | ||
124 | + TimeUnit rateUnit = TimeUnit.SECONDS; | ||
125 | + double rateFactor = rateUnit.toSeconds(1); | ||
126 | + print(FORMAT_METER, operationStr, meter.getCount(), | ||
127 | + meter.getMeanRate() * rateFactor, | ||
128 | + meter.getOneMinuteRate() * rateFactor, | ||
129 | + meter.getFiveMinuteRate() * rateFactor, | ||
130 | + meter.getFifteenMinuteRate() * rateFactor); | ||
131 | + } | ||
132 | +} |
1 | +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> | ||
2 | + | ||
3 | + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"> | ||
4 | + <command> | ||
5 | + <action class="org.onlab.onos.metrics.intent.cli.IntentEventsListCommand"/> | ||
6 | + </command> | ||
7 | + <command> | ||
8 | + <action class="org.onlab.onos.metrics.intent.cli.IntentEventsMetricsCommand"/> | ||
9 | + </command> | ||
10 | + </command-bundle> | ||
11 | + | ||
12 | +</blueprint> |
... | @@ -17,6 +17,7 @@ | ... | @@ -17,6 +17,7 @@ |
17 | <description>ONOS metrics applications</description> | 17 | <description>ONOS metrics applications</description> |
18 | 18 | ||
19 | <modules> | 19 | <modules> |
20 | + <module>intent</module> | ||
20 | <module>topology</module> | 21 | <module>topology</module> |
21 | </modules> | 22 | </modules> |
22 | 23 | ... | ... |
... | @@ -18,6 +18,15 @@ import org.onlab.metrics.MetricsComponent; | ... | @@ -18,6 +18,15 @@ import org.onlab.metrics.MetricsComponent; |
18 | import org.onlab.metrics.MetricsFeature; | 18 | import org.onlab.metrics.MetricsFeature; |
19 | import org.onlab.metrics.MetricsService; | 19 | import org.onlab.metrics.MetricsService; |
20 | import org.onlab.onos.event.Event; | 20 | import org.onlab.onos.event.Event; |
21 | +import org.onlab.onos.net.device.DeviceEvent; | ||
22 | +import org.onlab.onos.net.device.DeviceListener; | ||
23 | +import org.onlab.onos.net.device.DeviceService; | ||
24 | +import org.onlab.onos.net.host.HostEvent; | ||
25 | +import org.onlab.onos.net.host.HostListener; | ||
26 | +import org.onlab.onos.net.host.HostService; | ||
27 | +import org.onlab.onos.net.link.LinkEvent; | ||
28 | +import org.onlab.onos.net.link.LinkListener; | ||
29 | +import org.onlab.onos.net.link.LinkService; | ||
21 | import org.onlab.onos.net.topology.TopologyEvent; | 30 | import org.onlab.onos.net.topology.TopologyEvent; |
22 | import org.onlab.onos.net.topology.TopologyListener; | 31 | import org.onlab.onos.net.topology.TopologyListener; |
23 | import org.onlab.onos.net.topology.TopologyService; | 32 | import org.onlab.onos.net.topology.TopologyService; |
... | @@ -28,14 +37,26 @@ import org.slf4j.Logger; | ... | @@ -28,14 +37,26 @@ import org.slf4j.Logger; |
28 | */ | 37 | */ |
29 | @Component(immediate = true) | 38 | @Component(immediate = true) |
30 | @Service | 39 | @Service |
31 | -public class TopologyMetrics implements TopologyMetricsService, | 40 | +public class TopologyMetrics implements TopologyMetricsService { |
32 | - TopologyListener { | ||
33 | private static final Logger log = getLogger(TopologyMetrics.class); | 41 | private static final Logger log = getLogger(TopologyMetrics.class); |
34 | 42 | ||
35 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 43 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
44 | + protected DeviceService deviceService; | ||
45 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
46 | + protected HostService hostService; | ||
47 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
48 | + protected LinkService linkService; | ||
49 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
36 | protected TopologyService topologyService; | 50 | protected TopologyService topologyService; |
37 | - private LinkedList<TopologyEvent> lastEvents = new LinkedList<>(); | 51 | + |
38 | - private static final int LAST_EVENTS_MAX_N = 10; | 52 | + private LinkedList<Event> lastEvents = new LinkedList<>(); |
53 | + private static final int LAST_EVENTS_MAX_N = 100; | ||
54 | + | ||
55 | + private final DeviceListener deviceListener = new InnerDeviceListener(); | ||
56 | + private final HostListener hostListener = new InnerHostListener(); | ||
57 | + private final LinkListener linkListener = new InnerLinkListener(); | ||
58 | + private final TopologyListener topologyListener = | ||
59 | + new InnerTopologyListener(); | ||
39 | 60 | ||
40 | // | 61 | // |
41 | // Metrics | 62 | // Metrics |
... | @@ -61,22 +82,33 @@ public class TopologyMetrics implements TopologyMetricsService, | ... | @@ -61,22 +82,33 @@ public class TopologyMetrics implements TopologyMetricsService, |
61 | protected void activate() { | 82 | protected void activate() { |
62 | clear(); | 83 | clear(); |
63 | registerMetrics(); | 84 | registerMetrics(); |
64 | - topologyService.addListener(this); | 85 | + |
86 | + // Register for all topology-related events | ||
87 | + deviceService.addListener(deviceListener); | ||
88 | + hostService.addListener(hostListener); | ||
89 | + linkService.addListener(linkListener); | ||
90 | + topologyService.addListener(topologyListener); | ||
91 | + | ||
65 | log.info("ONOS Topology Metrics started."); | 92 | log.info("ONOS Topology Metrics started."); |
66 | } | 93 | } |
67 | 94 | ||
68 | @Deactivate | 95 | @Deactivate |
69 | public void deactivate() { | 96 | public void deactivate() { |
70 | - topologyService.removeListener(this); | 97 | + // De-register from all topology-related events |
98 | + deviceService.removeListener(deviceListener); | ||
99 | + hostService.removeListener(hostListener); | ||
100 | + linkService.removeListener(linkListener); | ||
101 | + topologyService.removeListener(topologyListener); | ||
102 | + | ||
71 | removeMetrics(); | 103 | removeMetrics(); |
72 | clear(); | 104 | clear(); |
73 | log.info("ONOS Topology Metrics stopped."); | 105 | log.info("ONOS Topology Metrics stopped."); |
74 | } | 106 | } |
75 | 107 | ||
76 | @Override | 108 | @Override |
77 | - public List<TopologyEvent> getEvents() { | 109 | + public List<Event> getEvents() { |
78 | synchronized (lastEvents) { | 110 | synchronized (lastEvents) { |
79 | - return ImmutableList.<TopologyEvent>copyOf(lastEvents); | 111 | + return ImmutableList.<Event>copyOf(lastEvents); |
80 | } | 112 | } |
81 | } | 113 | } |
82 | 114 | ||
... | @@ -90,27 +122,22 @@ public class TopologyMetrics implements TopologyMetricsService, | ... | @@ -90,27 +122,22 @@ public class TopologyMetrics implements TopologyMetricsService, |
90 | return eventRateMeter; | 122 | return eventRateMeter; |
91 | } | 123 | } |
92 | 124 | ||
93 | - @Override | 125 | + /** |
94 | - public void event(TopologyEvent event) { | 126 | + * Records an event. |
127 | + * | ||
128 | + * @param event the event to record | ||
129 | + * @param updateEventRateMeter if true, update the Event Rate Meter | ||
130 | + */ | ||
131 | + private void recordEvent(Event event, boolean updateEventRateMeter) { | ||
132 | + synchronized (lastEvents) { | ||
95 | lastEventTimestampEpochMs = System.currentTimeMillis(); | 133 | lastEventTimestampEpochMs = System.currentTimeMillis(); |
96 | - // | 134 | + if (updateEventRateMeter) { |
97 | - // NOTE: If we want to count each "reason" as a separate event, | ||
98 | - // then we should use 'event.reason().size()' instead of '1' to | ||
99 | - // mark the meter below. | ||
100 | - // | ||
101 | eventRateMeter.mark(1); | 135 | eventRateMeter.mark(1); |
102 | - | ||
103 | - log.debug("Topology Event: time = {} type = {} subject = {}", | ||
104 | - event.time(), event.type(), event.subject()); | ||
105 | - for (Event reason : event.reasons()) { | ||
106 | - log.debug("Topology Event Reason: time = {} type = {} subject = {}", | ||
107 | - reason.time(), reason.type(), reason.subject()); | ||
108 | } | 136 | } |
109 | 137 | ||
110 | // | 138 | // |
111 | // Keep only the last N events, where N = LAST_EVENTS_MAX_N | 139 | // Keep only the last N events, where N = LAST_EVENTS_MAX_N |
112 | // | 140 | // |
113 | - synchronized (lastEvents) { | ||
114 | while (lastEvents.size() >= LAST_EVENTS_MAX_N) { | 141 | while (lastEvents.size() >= LAST_EVENTS_MAX_N) { |
115 | lastEvents.remove(); | 142 | lastEvents.remove(); |
116 | } | 143 | } |
... | @@ -119,11 +146,67 @@ public class TopologyMetrics implements TopologyMetricsService, | ... | @@ -119,11 +146,67 @@ public class TopologyMetrics implements TopologyMetricsService, |
119 | } | 146 | } |
120 | 147 | ||
121 | /** | 148 | /** |
149 | + * Inner Device Event Listener class. | ||
150 | + */ | ||
151 | + private class InnerDeviceListener implements DeviceListener { | ||
152 | + @Override | ||
153 | + public void event(DeviceEvent event) { | ||
154 | + recordEvent(event, true); | ||
155 | + log.debug("Device Event: time = {} type = {} event = {}", | ||
156 | + event.time(), event.type(), event); | ||
157 | + } | ||
158 | + } | ||
159 | + | ||
160 | + /** | ||
161 | + * Inner Host Event Listener class. | ||
162 | + */ | ||
163 | + private class InnerHostListener implements HostListener { | ||
164 | + @Override | ||
165 | + public void event(HostEvent event) { | ||
166 | + recordEvent(event, true); | ||
167 | + log.debug("Host Event: time = {} type = {} event = {}", | ||
168 | + event.time(), event.type(), event); | ||
169 | + } | ||
170 | + } | ||
171 | + | ||
172 | + /** | ||
173 | + * Inner Link Event Listener class. | ||
174 | + */ | ||
175 | + private class InnerLinkListener implements LinkListener { | ||
176 | + @Override | ||
177 | + public void event(LinkEvent event) { | ||
178 | + recordEvent(event, true); | ||
179 | + log.debug("Link Event: time = {} type = {} event = {}", | ||
180 | + event.time(), event.type(), event); | ||
181 | + } | ||
182 | + } | ||
183 | + | ||
184 | + /** | ||
185 | + * Inner Topology Event Listener class. | ||
186 | + */ | ||
187 | + private class InnerTopologyListener implements TopologyListener { | ||
188 | + @Override | ||
189 | + public void event(TopologyEvent event) { | ||
190 | + // | ||
191 | + // NOTE: Don't update the eventRateMeter, because the real | ||
192 | + // events are already captured/counted. | ||
193 | + // | ||
194 | + recordEvent(event, false); | ||
195 | + log.debug("Topology Event: time = {} type = {} event = {}", | ||
196 | + event.time(), event.type(), event); | ||
197 | + for (Event reason : event.reasons()) { | ||
198 | + log.debug("Topology Event Reason: time = {} type = {} event = {}", | ||
199 | + reason.time(), reason.type(), reason); | ||
200 | + } | ||
201 | + } | ||
202 | + } | ||
203 | + | ||
204 | + /** | ||
122 | * Clears the internal state. | 205 | * Clears the internal state. |
123 | */ | 206 | */ |
124 | private void clear() { | 207 | private void clear() { |
125 | - lastEventTimestampEpochMs = 0; | ||
126 | synchronized (lastEvents) { | 208 | synchronized (lastEvents) { |
209 | + lastEventTimestampEpochMs = 0; | ||
127 | lastEvents.clear(); | 210 | lastEvents.clear(); |
128 | } | 211 | } |
129 | } | 212 | } | ... | ... |
... | @@ -4,7 +4,7 @@ import java.util.List; | ... | @@ -4,7 +4,7 @@ import java.util.List; |
4 | 4 | ||
5 | import com.codahale.metrics.Gauge; | 5 | import com.codahale.metrics.Gauge; |
6 | import com.codahale.metrics.Meter; | 6 | import com.codahale.metrics.Meter; |
7 | -import org.onlab.onos.net.topology.TopologyEvent; | 7 | +import org.onlab.onos.event.Event; |
8 | 8 | ||
9 | /** | 9 | /** |
10 | * Service interface exported by TopologyMetrics. | 10 | * Service interface exported by TopologyMetrics. |
... | @@ -15,7 +15,7 @@ public interface TopologyMetricsService { | ... | @@ -15,7 +15,7 @@ public interface TopologyMetricsService { |
15 | * | 15 | * |
16 | * @return the last saved topology events. | 16 | * @return the last saved topology events. |
17 | */ | 17 | */ |
18 | - public List<TopologyEvent> getEvents(); | 18 | + public List<Event> getEvents(); |
19 | 19 | ||
20 | /** | 20 | /** |
21 | * Gets the Metrics' Gauge for the last topology event timestamp | 21 | * Gets the Metrics' Gauge for the last topology event timestamp | ... | ... |
... | @@ -19,10 +19,8 @@ import org.onlab.onos.net.topology.TopologyEvent; | ... | @@ -19,10 +19,8 @@ import org.onlab.onos.net.topology.TopologyEvent; |
19 | description = "Lists the last topology events") | 19 | description = "Lists the last topology events") |
20 | public class TopologyEventsListCommand extends AbstractShellCommand { | 20 | public class TopologyEventsListCommand extends AbstractShellCommand { |
21 | 21 | ||
22 | - private static final String FORMAT_EVENT = | 22 | + private static final String FORMAT_EVENT = "Event=%s"; |
23 | - "Topology Event time=%d type=%s subject=%s"; | 23 | + private static final String FORMAT_REASON = " Reason=%s"; |
24 | - private static final String FORMAT_REASON = | ||
25 | - " Reason time=%d type=%s subject=%s"; | ||
26 | 24 | ||
27 | @Override | 25 | @Override |
28 | protected void execute() { | 26 | protected void execute() { |
... | @@ -31,12 +29,13 @@ public class TopologyEventsListCommand extends AbstractShellCommand { | ... | @@ -31,12 +29,13 @@ public class TopologyEventsListCommand extends AbstractShellCommand { |
31 | if (outputJson()) { | 29 | if (outputJson()) { |
32 | print("%s", json(service.getEvents())); | 30 | print("%s", json(service.getEvents())); |
33 | } else { | 31 | } else { |
34 | - for (TopologyEvent event : service.getEvents()) { | 32 | + for (Event event : service.getEvents()) { |
35 | - print(FORMAT_EVENT, event.time(), event.type(), | 33 | + print(FORMAT_EVENT, event); |
36 | - event.subject()); | 34 | + if (event instanceof TopologyEvent) { |
37 | - for (Event reason : event.reasons()) { | 35 | + TopologyEvent topologyEvent = (TopologyEvent) event; |
38 | - print(FORMAT_REASON, reason.time(), reason.type(), | 36 | + for (Event reason : topologyEvent.reasons()) { |
39 | - reason.subject()); | 37 | + print(FORMAT_REASON, reason); |
38 | + } | ||
40 | } | 39 | } |
41 | print(""); // Extra empty line for clarity | 40 | print(""); // Extra empty line for clarity |
42 | } | 41 | } |
... | @@ -46,14 +45,14 @@ public class TopologyEventsListCommand extends AbstractShellCommand { | ... | @@ -46,14 +45,14 @@ public class TopologyEventsListCommand extends AbstractShellCommand { |
46 | /** | 45 | /** |
47 | * Produces a JSON array of topology events. | 46 | * Produces a JSON array of topology events. |
48 | * | 47 | * |
49 | - * @param topologyEvents the topology events with the data | 48 | + * @param events the topology events with the data |
50 | * @return JSON array with the topology events | 49 | * @return JSON array with the topology events |
51 | */ | 50 | */ |
52 | - private JsonNode json(List<TopologyEvent> topologyEvents) { | 51 | + private JsonNode json(List<Event> events) { |
53 | ObjectMapper mapper = new ObjectMapper(); | 52 | ObjectMapper mapper = new ObjectMapper(); |
54 | ArrayNode result = mapper.createArrayNode(); | 53 | ArrayNode result = mapper.createArrayNode(); |
55 | 54 | ||
56 | - for (TopologyEvent event : topologyEvents) { | 55 | + for (Event event : events) { |
57 | result.add(json(mapper, event)); | 56 | result.add(json(mapper, event)); |
58 | } | 57 | } |
59 | return result; | 58 | return result; |
... | @@ -66,32 +65,23 @@ public class TopologyEventsListCommand extends AbstractShellCommand { | ... | @@ -66,32 +65,23 @@ public class TopologyEventsListCommand extends AbstractShellCommand { |
66 | * @param topologyEvent the topology event with the data | 65 | * @param topologyEvent the topology event with the data |
67 | * @return JSON object for the topology event | 66 | * @return JSON object for the topology event |
68 | */ | 67 | */ |
69 | - private ObjectNode json(ObjectMapper mapper, TopologyEvent topologyEvent) { | 68 | + private ObjectNode json(ObjectMapper mapper, Event event) { |
70 | ObjectNode result = mapper.createObjectNode(); | 69 | ObjectNode result = mapper.createObjectNode(); |
71 | - ArrayNode reasons = mapper.createArrayNode(); | ||
72 | 70 | ||
71 | + result.put("time", event.time()) | ||
72 | + .put("type", event.type().toString()) | ||
73 | + .put("event", event.toString()); | ||
74 | + | ||
75 | + // Add the reasons if a TopologyEvent | ||
76 | + if (event instanceof TopologyEvent) { | ||
77 | + TopologyEvent topologyEvent = (TopologyEvent) event; | ||
78 | + ArrayNode reasons = mapper.createArrayNode(); | ||
73 | for (Event reason : topologyEvent.reasons()) { | 79 | for (Event reason : topologyEvent.reasons()) { |
74 | reasons.add(json(mapper, reason)); | 80 | reasons.add(json(mapper, reason)); |
75 | } | 81 | } |
76 | - result.put("time", topologyEvent.time()) | 82 | + result.put("reasons", reasons); |
77 | - .put("type", topologyEvent.type().toString()) | ||
78 | - .put("subject", topologyEvent.subject().toString()) | ||
79 | - .put("reasons", reasons); | ||
80 | - return result; | ||
81 | } | 83 | } |
82 | 84 | ||
83 | - /** | ||
84 | - * Produces JSON object for a generic event. | ||
85 | - * | ||
86 | - * @param event the generic event with the data | ||
87 | - * @return JSON object for the generic event | ||
88 | - */ | ||
89 | - private ObjectNode json(ObjectMapper mapper, Event event) { | ||
90 | - ObjectNode result = mapper.createObjectNode(); | ||
91 | - | ||
92 | - result.put("time", event.time()) | ||
93 | - .put("type", event.type().toString()) | ||
94 | - .put("subject", event.subject().toString()); | ||
95 | return result; | 85 | return result; |
96 | } | 86 | } |
97 | } | 87 | } | ... | ... |
... | @@ -199,9 +199,16 @@ | ... | @@ -199,9 +199,16 @@ |
199 | 199 | ||
200 | <feature name="onos-app-metrics" version="1.0.0" | 200 | <feature name="onos-app-metrics" version="1.0.0" |
201 | description="ONOS metrics applications"> | 201 | description="ONOS metrics applications"> |
202 | + <feature>onos-app-metrics-intent</feature> | ||
202 | <feature>onos-app-metrics-topology</feature> | 203 | <feature>onos-app-metrics-topology</feature> |
203 | </feature> | 204 | </feature> |
204 | 205 | ||
206 | + <feature name="onos-app-metrics-intent" version="1.0.0" | ||
207 | + description="ONOS intent metrics application"> | ||
208 | + <feature>onos-api</feature> | ||
209 | + <bundle>mvn:org.onlab.onos/onos-app-metrics-intent/1.0.0-SNAPSHOT</bundle> | ||
210 | + </feature> | ||
211 | + | ||
205 | <feature name="onos-app-metrics-topology" version="1.0.0" | 212 | <feature name="onos-app-metrics-topology" version="1.0.0" |
206 | description="ONOS topology metrics application"> | 213 | description="ONOS topology metrics application"> |
207 | <feature>onos-api</feature> | 214 | <feature>onos-api</feature> | ... | ... |
-
Please register or login to post a comment