Committed by
Gerrit Code Review
Event history service and CLI
- Tool created while debugging ONOS-3509 Usage Example: (See recent Mastership and Device events) onos> events -m -d Change-Id: I87aceaf8fe61732a61c2d1e39399d0f10a729b54
Showing
9 changed files
with
1071 additions
and
0 deletions
apps/events/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<!-- | ||
3 | + ~ Copyright 2016 Open Networking Laboratory | ||
4 | + ~ | ||
5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + ~ you may not use this file except in compliance with the License. | ||
7 | + ~ You may obtain a copy of the License at | ||
8 | + ~ | ||
9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + ~ | ||
11 | + ~ Unless required by applicable law or agreed to in writing, software | ||
12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + ~ See the License for the specific language governing permissions and | ||
15 | + ~ limitations under the License. | ||
16 | + --> | ||
17 | +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
18 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
19 | + <modelVersion>4.0.0</modelVersion> | ||
20 | + <parent> | ||
21 | + <artifactId>onos-apps</artifactId> | ||
22 | + <groupId>org.onosproject</groupId> | ||
23 | + <version>1.5.0-SNAPSHOT</version> | ||
24 | + <relativePath>../pom.xml</relativePath> | ||
25 | + </parent> | ||
26 | + | ||
27 | + <groupId>org.onosproject</groupId> | ||
28 | + <artifactId>onos-events</artifactId> | ||
29 | + <packaging>bundle</packaging> | ||
30 | + | ||
31 | + <description>App to display ONOS event history</description> | ||
32 | + <url>http://onosproject.org</url> | ||
33 | + | ||
34 | + <properties> | ||
35 | + <onos.version>1.5.0-SNAPSHOT</onos.version> | ||
36 | + <onos.app.name>org.onosproject.events</onos.app.name> | ||
37 | + </properties> | ||
38 | + | ||
39 | + <dependencies> | ||
40 | + <dependency> | ||
41 | + <groupId>org.onosproject</groupId> | ||
42 | + <artifactId>onos-api</artifactId> | ||
43 | + </dependency> | ||
44 | + | ||
45 | + <dependency> | ||
46 | + <groupId>org.onosproject</groupId> | ||
47 | + <artifactId>onlab-osgi</artifactId> | ||
48 | + </dependency> | ||
49 | + | ||
50 | + <dependency> | ||
51 | + <groupId>junit</groupId> | ||
52 | + <artifactId>junit</artifactId> | ||
53 | + <scope>test</scope> | ||
54 | + </dependency> | ||
55 | + | ||
56 | + <dependency> | ||
57 | + <groupId>org.onosproject</groupId> | ||
58 | + <artifactId>onos-api</artifactId> | ||
59 | + <scope>test</scope> | ||
60 | + <classifier>tests</classifier> | ||
61 | + </dependency> | ||
62 | + | ||
63 | + <dependency> | ||
64 | + <groupId>org.apache.felix</groupId> | ||
65 | + <artifactId>org.apache.felix.scr.annotations</artifactId> | ||
66 | + <scope>provided</scope> | ||
67 | + </dependency> | ||
68 | + | ||
69 | + <dependency> | ||
70 | + <groupId>org.onosproject</groupId> | ||
71 | + <artifactId>onos-cli</artifactId> | ||
72 | + <version>${project.version}</version> | ||
73 | + </dependency> | ||
74 | + | ||
75 | + <dependency> | ||
76 | + <groupId>org.osgi</groupId> | ||
77 | + <artifactId>org.osgi.core</artifactId> | ||
78 | + <scope>provided</scope> | ||
79 | + </dependency> | ||
80 | + | ||
81 | + <dependency> | ||
82 | + <groupId>org.apache.karaf.shell</groupId> | ||
83 | + <artifactId>org.apache.karaf.shell.console</artifactId> | ||
84 | + <scope>provided</scope> | ||
85 | + </dependency> | ||
86 | + <dependency> | ||
87 | + <groupId>org.onosproject</groupId> | ||
88 | + <artifactId>onlab-junit</artifactId> | ||
89 | + <scope>test</scope> | ||
90 | + </dependency> | ||
91 | + <dependency> | ||
92 | + <groupId>org.onosproject</groupId> | ||
93 | + <artifactId>onlab-misc</artifactId> | ||
94 | + </dependency> | ||
95 | + </dependencies> | ||
96 | + | ||
97 | + <build> | ||
98 | + <plugins> | ||
99 | + <plugin> | ||
100 | + <groupId>org.apache.felix</groupId> | ||
101 | + <artifactId>maven-bundle-plugin</artifactId> | ||
102 | + <extensions>true</extensions> | ||
103 | + </plugin> | ||
104 | + <plugin> | ||
105 | + <groupId>org.apache.maven.plugins</groupId> | ||
106 | + <artifactId>maven-compiler-plugin</artifactId> | ||
107 | + </plugin> | ||
108 | + <plugin> | ||
109 | + <groupId>org.apache.felix</groupId> | ||
110 | + <artifactId>maven-scr-plugin</artifactId> | ||
111 | + <executions> | ||
112 | + <execution> | ||
113 | + <id>generate-scr-srcdescriptor</id> | ||
114 | + <goals> | ||
115 | + <goal>scr</goal> | ||
116 | + </goals> | ||
117 | + </execution> | ||
118 | + </executions> | ||
119 | + <configuration> | ||
120 | + <supportedProjectTypes> | ||
121 | + <supportedProjectType>bundle</supportedProjectType> | ||
122 | + <supportedProjectType>war</supportedProjectType> | ||
123 | + </supportedProjectTypes> | ||
124 | + </configuration> | ||
125 | + </plugin> | ||
126 | + <plugin> | ||
127 | + <groupId>org.onosproject</groupId> | ||
128 | + <artifactId>onos-maven-plugin</artifactId> | ||
129 | + <executions> | ||
130 | + <execution> | ||
131 | + <id>cfg</id> | ||
132 | + <phase>generate-resources</phase> | ||
133 | + <goals> | ||
134 | + <goal>cfg</goal> | ||
135 | + </goals> | ||
136 | + </execution> | ||
137 | + <execution> | ||
138 | + <id>swagger</id> | ||
139 | + <phase>generate-sources</phase> | ||
140 | + <goals> | ||
141 | + <goal>swagger</goal> | ||
142 | + </goals> | ||
143 | + </execution> | ||
144 | + <execution> | ||
145 | + <id>app</id> | ||
146 | + <phase>package</phase> | ||
147 | + <goals> | ||
148 | + <goal>app</goal> | ||
149 | + </goals> | ||
150 | + </execution> | ||
151 | + </executions> | ||
152 | + </plugin> | ||
153 | + </plugins> | ||
154 | + </build> | ||
155 | + | ||
156 | +</project> |
1 | +/* | ||
2 | + * Copyright 2016 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.events; | ||
17 | + | ||
18 | +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; | ||
19 | +import static org.onlab.util.Tools.groupedThreads; | ||
20 | +import static org.onlab.util.Tools.minPriority; | ||
21 | + | ||
22 | +import java.util.Deque; | ||
23 | +import java.util.concurrent.ConcurrentLinkedDeque; | ||
24 | +import java.util.concurrent.ScheduledExecutorService; | ||
25 | +import java.util.concurrent.TimeUnit; | ||
26 | + | ||
27 | +import org.apache.felix.scr.annotations.Activate; | ||
28 | +import org.apache.felix.scr.annotations.Component; | ||
29 | +import org.apache.felix.scr.annotations.Deactivate; | ||
30 | +import org.apache.felix.scr.annotations.Property; | ||
31 | +import org.apache.felix.scr.annotations.Reference; | ||
32 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
33 | +import org.apache.felix.scr.annotations.Service; | ||
34 | +import org.onlab.util.UnmodifiableDeque; | ||
35 | +import org.onosproject.cluster.ClusterEvent; | ||
36 | +import org.onosproject.cluster.ClusterEventListener; | ||
37 | +import org.onosproject.cluster.ClusterService; | ||
38 | +import org.onosproject.core.ApplicationId; | ||
39 | +import org.onosproject.core.CoreService; | ||
40 | +import org.onosproject.event.Event; | ||
41 | +import org.onosproject.event.ListenerTracker; | ||
42 | +import org.onosproject.mastership.MastershipEvent; | ||
43 | +import org.onosproject.mastership.MastershipListener; | ||
44 | +import org.onosproject.mastership.MastershipService; | ||
45 | +import org.onosproject.net.device.DeviceEvent; | ||
46 | +import org.onosproject.net.device.DeviceListener; | ||
47 | +import org.onosproject.net.device.DeviceService; | ||
48 | +import org.onosproject.net.host.HostEvent; | ||
49 | +import org.onosproject.net.host.HostListener; | ||
50 | +import org.onosproject.net.host.HostService; | ||
51 | +import org.onosproject.net.link.LinkEvent; | ||
52 | +import org.onosproject.net.link.LinkListener; | ||
53 | +import org.onosproject.net.link.LinkService; | ||
54 | +import org.onosproject.net.topology.TopologyEvent; | ||
55 | +import org.onosproject.net.topology.TopologyListener; | ||
56 | +import org.onosproject.net.topology.TopologyService; | ||
57 | +import org.slf4j.Logger; | ||
58 | +import org.slf4j.LoggerFactory; | ||
59 | + | ||
60 | +/** | ||
61 | + * Application to store history of instance local ONOS Events. | ||
62 | + */ | ||
63 | +@Component(immediate = true) | ||
64 | +@Service | ||
65 | +public class EventHistoryManager | ||
66 | + implements EventHistoryService { | ||
67 | + | ||
68 | + private final Logger log = LoggerFactory.getLogger(getClass()); | ||
69 | + | ||
70 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
71 | + protected CoreService coreService; | ||
72 | + | ||
73 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
74 | + protected MastershipService mastershipService; | ||
75 | + | ||
76 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
77 | + protected DeviceService deviceService; | ||
78 | + | ||
79 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
80 | + protected LinkService linkService; | ||
81 | + | ||
82 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
83 | + protected TopologyService topologyService; | ||
84 | + | ||
85 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
86 | + protected HostService hostService; | ||
87 | + | ||
88 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
89 | + protected ClusterService clusterService; | ||
90 | + | ||
91 | + @Property(name = "excludeStatsEvent", boolValue = true, | ||
92 | + label = "Exclude stats related events") | ||
93 | + private boolean excludeStatsEvent = true; | ||
94 | + | ||
95 | + @Property(name = "sizeLimit", intValue = 10_000, | ||
96 | + label = "Number of event history to store") | ||
97 | + private int sizeLimit = 10_000; | ||
98 | + | ||
99 | + private ApplicationId appId; | ||
100 | + | ||
101 | + private ListenerTracker listeners; | ||
102 | + | ||
103 | + // Using Deque so that it'll be possible to iterate from both ends | ||
104 | + // (Tail-end is the most recent event) | ||
105 | + private final Deque<Event<?, ?>> history = new ConcurrentLinkedDeque<>(); | ||
106 | + | ||
107 | + private ScheduledExecutorService pruner; | ||
108 | + | ||
109 | + // pruneEventHistoryTask() execution interval in seconds | ||
110 | + private long pruneInterval = 5; | ||
111 | + | ||
112 | + | ||
113 | + @Activate | ||
114 | + protected void activate() { | ||
115 | + appId = coreService.registerApplication("org.onosproject.events"); | ||
116 | + log.debug("Registered as {}", appId); | ||
117 | + | ||
118 | + pruner = newSingleThreadScheduledExecutor(minPriority(groupedThreads("onos/events", "history-pruner"))); | ||
119 | + | ||
120 | + pruner.scheduleWithFixedDelay(this::pruneEventHistoryTask, | ||
121 | + pruneInterval , pruneInterval, TimeUnit.SECONDS); | ||
122 | + | ||
123 | + listeners = new ListenerTracker(); | ||
124 | + listeners.addListener(mastershipService, new InternalMastershipListener()) | ||
125 | + .addListener(deviceService, new InternalDeviceListener()) | ||
126 | + .addListener(linkService, new InternalLinkListener()) | ||
127 | + .addListener(topologyService, new InternalTopologyListener()) | ||
128 | + .addListener(hostService, new InternalHostListener()) | ||
129 | + .addListener(clusterService, new InternalClusterListener()); | ||
130 | + | ||
131 | + log.info("Started"); | ||
132 | + } | ||
133 | + | ||
134 | + @Deactivate | ||
135 | + protected void deactivate() { | ||
136 | + listeners.removeListeners(); | ||
137 | + | ||
138 | + pruner.shutdownNow(); | ||
139 | + history.clear(); | ||
140 | + | ||
141 | + log.info("Stopped"); | ||
142 | + } | ||
143 | + | ||
144 | + @Override | ||
145 | + public Deque<Event<?, ?>> history() { | ||
146 | + return UnmodifiableDeque.unmodifiableDeque(history); | ||
147 | + } | ||
148 | + | ||
149 | + @Override | ||
150 | + public void clear() { | ||
151 | + history.clear(); | ||
152 | + } | ||
153 | + | ||
154 | + // This method assumes only 1 call is in flight at the same time. | ||
155 | + private void pruneEventHistoryTask() { | ||
156 | + int size = history.size(); | ||
157 | + int overflows = size - sizeLimit; | ||
158 | + if (overflows > 0) { | ||
159 | + for (int i = 0; i < overflows; ++i) { | ||
160 | + history.poll(); | ||
161 | + } | ||
162 | + } | ||
163 | + } | ||
164 | + | ||
165 | + private void addEvent(Event<?, ?> event) { | ||
166 | + history.offer(event); | ||
167 | + } | ||
168 | + | ||
169 | + class InternalMastershipListener | ||
170 | + implements MastershipListener { | ||
171 | + | ||
172 | + @Override | ||
173 | + public void event(MastershipEvent event) { | ||
174 | + addEvent(event); | ||
175 | + } | ||
176 | + } | ||
177 | + | ||
178 | + class InternalDeviceListener | ||
179 | + implements DeviceListener { | ||
180 | + | ||
181 | + @Override | ||
182 | + public boolean isRelevant(DeviceEvent event) { | ||
183 | + if (excludeStatsEvent) { | ||
184 | + return event.type() != DeviceEvent.Type.PORT_STATS_UPDATED; | ||
185 | + } else { | ||
186 | + return true; | ||
187 | + } | ||
188 | + } | ||
189 | + | ||
190 | + @Override | ||
191 | + public void event(DeviceEvent event) { | ||
192 | + addEvent(event); | ||
193 | + } | ||
194 | + } | ||
195 | + | ||
196 | + class InternalLinkListener | ||
197 | + implements LinkListener { | ||
198 | + | ||
199 | + @Override | ||
200 | + public void event(LinkEvent event) { | ||
201 | + addEvent(event); | ||
202 | + } | ||
203 | + } | ||
204 | + | ||
205 | + class InternalTopologyListener | ||
206 | + implements TopologyListener { | ||
207 | + | ||
208 | + @Override | ||
209 | + public void event(TopologyEvent event) { | ||
210 | + addEvent(event); | ||
211 | + } | ||
212 | + } | ||
213 | + | ||
214 | + class InternalHostListener | ||
215 | + implements HostListener { | ||
216 | + | ||
217 | + @Override | ||
218 | + public void event(HostEvent event) { | ||
219 | + addEvent(event); | ||
220 | + } | ||
221 | + } | ||
222 | + | ||
223 | + class InternalClusterListener | ||
224 | + implements ClusterEventListener { | ||
225 | + | ||
226 | + @Override | ||
227 | + public void event(ClusterEvent event) { | ||
228 | + addEvent(event); | ||
229 | + } | ||
230 | + } | ||
231 | + | ||
232 | +} |
1 | +/* | ||
2 | + * Copyright 2016 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.events; | ||
17 | + | ||
18 | +import java.util.Deque; | ||
19 | + | ||
20 | +import org.onosproject.event.Event; | ||
21 | + | ||
22 | +import com.google.common.annotations.Beta; | ||
23 | + | ||
24 | +/** | ||
25 | + * Provides history of instance local ONOS Events. | ||
26 | + */ | ||
27 | +@Beta | ||
28 | +public interface EventHistoryService { | ||
29 | + | ||
30 | + /** | ||
31 | + * Returns unmodifiable view of ONOS events history. | ||
32 | + * | ||
33 | + * @return ONOS events (First element is the oldest event stored) | ||
34 | + */ | ||
35 | + Deque<Event<?, ?>> history(); | ||
36 | + | ||
37 | + /** | ||
38 | + * Clears all stored history. | ||
39 | + */ | ||
40 | + void clear(); | ||
41 | +} |
1 | +/* | ||
2 | + * Copyright 2016 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.events; | ||
17 | + | ||
18 | +import static java.util.stream.Collectors.toList; | ||
19 | + | ||
20 | +import java.io.PrintWriter; | ||
21 | +import java.io.StringWriter; | ||
22 | +import java.util.List; | ||
23 | +import java.util.function.Predicate; | ||
24 | +import java.util.stream.Collector; | ||
25 | +import java.util.stream.Stream; | ||
26 | + | ||
27 | +import org.apache.karaf.shell.commands.Command; | ||
28 | +import org.apache.karaf.shell.commands.Option; | ||
29 | +import org.joda.time.LocalDateTime; | ||
30 | +import org.onosproject.cli.AbstractShellCommand; | ||
31 | +import org.onosproject.cluster.ClusterEvent; | ||
32 | +import org.onosproject.event.Event; | ||
33 | +import org.onosproject.mastership.MastershipEvent; | ||
34 | +import org.onosproject.net.Link; | ||
35 | +import org.onosproject.net.device.DeviceEvent; | ||
36 | +import org.onosproject.net.host.HostEvent; | ||
37 | +import org.onosproject.net.link.LinkEvent; | ||
38 | +import org.onosproject.net.topology.Topology; | ||
39 | +import org.onosproject.net.topology.TopologyEvent; | ||
40 | + | ||
41 | +import com.fasterxml.jackson.core.JsonProcessingException; | ||
42 | +import com.fasterxml.jackson.databind.JsonNode; | ||
43 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
44 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
45 | +import com.google.common.base.MoreObjects; | ||
46 | +import com.google.common.collect.ImmutableList; | ||
47 | + | ||
48 | +/** | ||
49 | + * Command to print history of instance local ONOS Events. | ||
50 | + */ | ||
51 | +@Command(scope = "onos", name = "events", | ||
52 | + description = "Command to print history of instance local ONOS Events") | ||
53 | +public class EventsCommand | ||
54 | + extends AbstractShellCommand { | ||
55 | + | ||
56 | + @Option(name = "--all", aliases = "-a", | ||
57 | + description = "Include all Events (default behavior)", | ||
58 | + required = false) | ||
59 | + private boolean all = false; | ||
60 | + | ||
61 | + @Option(name = "--mastership", aliases = "-m", | ||
62 | + description = "Include MastershipEvent", | ||
63 | + required = false) | ||
64 | + private boolean mastership = false; | ||
65 | + | ||
66 | + @Option(name = "--device", aliases = "-d", | ||
67 | + description = "Include DeviceEvent", | ||
68 | + required = false) | ||
69 | + private boolean device = false; | ||
70 | + | ||
71 | + @Option(name = "--link", aliases = "-l", | ||
72 | + description = "Include LinkEvent", | ||
73 | + required = false) | ||
74 | + private boolean link = false; | ||
75 | + | ||
76 | + @Option(name = "--topology", aliases = "-t", | ||
77 | + description = "Include TopologyEvent", | ||
78 | + required = false) | ||
79 | + private boolean topology = false; | ||
80 | + | ||
81 | + @Option(name = "--host", aliases = "-t", | ||
82 | + description = "Include HostEvent", | ||
83 | + required = false) | ||
84 | + private boolean host = false; | ||
85 | + | ||
86 | + @Option(name = "--cluster", aliases = "-c", | ||
87 | + description = "Include ClusterEvent", | ||
88 | + required = false) | ||
89 | + private boolean cluster = false; | ||
90 | + | ||
91 | + @Option(name = "--max-events", aliases = "-n", | ||
92 | + description = "Maximum number of events to print", | ||
93 | + required = false, | ||
94 | + valueToShowInHelp = "-1 [no limit]") | ||
95 | + private long maxSize = -1; | ||
96 | + | ||
97 | + @Override | ||
98 | + protected void execute() { | ||
99 | + EventHistoryService eventHistoryService = get(EventHistoryService.class); | ||
100 | + | ||
101 | + Stream<Event<?, ?>> events = eventHistoryService.history().stream(); | ||
102 | + | ||
103 | + boolean dumpAll = all || !(mastership || device || link || topology || host); | ||
104 | + | ||
105 | + if (!dumpAll) { | ||
106 | + Predicate<Event<?, ?>> filter = (defaultIs) -> false; | ||
107 | + | ||
108 | + if (mastership) { | ||
109 | + filter = filter.or(evt -> evt instanceof MastershipEvent); | ||
110 | + } | ||
111 | + if (device) { | ||
112 | + filter = filter.or(evt -> evt instanceof DeviceEvent); | ||
113 | + } | ||
114 | + if (link) { | ||
115 | + filter = filter.or(evt -> evt instanceof LinkEvent); | ||
116 | + } | ||
117 | + if (topology) { | ||
118 | + filter = filter.or(evt -> evt instanceof TopologyEvent); | ||
119 | + } | ||
120 | + if (host) { | ||
121 | + filter = filter.or(evt -> evt instanceof HostEvent); | ||
122 | + } | ||
123 | + if (cluster) { | ||
124 | + filter = filter.or(evt -> evt instanceof ClusterEvent); | ||
125 | + } | ||
126 | + | ||
127 | + events = events.filter(filter); | ||
128 | + } | ||
129 | + | ||
130 | + if (maxSize > 0) { | ||
131 | + events = events.limit(maxSize); | ||
132 | + } | ||
133 | + | ||
134 | + if (outputJson()) { | ||
135 | + ArrayNode jsonEvents = events.map(this::json).collect(toArrayNode()); | ||
136 | + printJson(jsonEvents); | ||
137 | + } else { | ||
138 | + events.forEach(this::printEvent); | ||
139 | + } | ||
140 | + | ||
141 | + } | ||
142 | + | ||
143 | + private Collector<JsonNode, ArrayNode, ArrayNode> toArrayNode() { | ||
144 | + return Collector.of(() -> mapper().createArrayNode(), | ||
145 | + ArrayNode::add, | ||
146 | + ArrayNode::addAll); | ||
147 | + } | ||
148 | + | ||
149 | + private ObjectNode json(Event<?, ?> event) { | ||
150 | + ObjectNode result = mapper().createObjectNode(); | ||
151 | + | ||
152 | + result.put("time", event.time()) | ||
153 | + .put("type", event.type().toString()) | ||
154 | + .put("event", event.toString()); | ||
155 | + | ||
156 | + return result; | ||
157 | + } | ||
158 | + | ||
159 | + /** | ||
160 | + * Print JsonNode using default pretty printer. | ||
161 | + * | ||
162 | + * @param json JSON node to print | ||
163 | + */ | ||
164 | + private void printJson(JsonNode json) { | ||
165 | + try { | ||
166 | + print("%s", mapper().writerWithDefaultPrettyPrinter().writeValueAsString(json)); | ||
167 | + } catch (JsonProcessingException e) { | ||
168 | + StringWriter sw = new StringWriter(); | ||
169 | + e.printStackTrace(new PrintWriter(sw)); | ||
170 | + print("[ERROR] %s\n%s", e.getMessage(), sw.toString()); | ||
171 | + } | ||
172 | + } | ||
173 | + | ||
174 | + private void printEvent(Event<?, ?> event) { | ||
175 | + if (event instanceof DeviceEvent) { | ||
176 | + DeviceEvent deviceEvent = (DeviceEvent) event; | ||
177 | + if (event.type().toString().startsWith("PORT")) { | ||
178 | + // Port event | ||
179 | + print("%s %s\t%s/%s [%s]", | ||
180 | + new LocalDateTime(event.time()), | ||
181 | + event.type(), | ||
182 | + deviceEvent.subject().id(), deviceEvent.port().number(), | ||
183 | + deviceEvent.port() | ||
184 | + ); | ||
185 | + } else { | ||
186 | + // Device event | ||
187 | + print("%s %s\t%s [%s]", | ||
188 | + new LocalDateTime(event.time()), | ||
189 | + event.type(), | ||
190 | + deviceEvent.subject().id(), | ||
191 | + deviceEvent.subject() | ||
192 | + ); | ||
193 | + } | ||
194 | + | ||
195 | + } else if (event instanceof MastershipEvent) { | ||
196 | + print("%s %s\t%s [%s]", | ||
197 | + new LocalDateTime(event.time()), | ||
198 | + event.type(), | ||
199 | + event.subject(), | ||
200 | + ((MastershipEvent) event).roleInfo()); | ||
201 | + | ||
202 | + } else if (event instanceof LinkEvent) { | ||
203 | + LinkEvent linkEvent = (LinkEvent) event; | ||
204 | + Link link = linkEvent.subject(); | ||
205 | + print("%s %s\t%s/%s-%s/%s [%s]", | ||
206 | + new LocalDateTime(event.time()), | ||
207 | + event.type(), | ||
208 | + link.src().deviceId(), link.src().port(), link.dst().deviceId(), link.dst().port(), | ||
209 | + link); | ||
210 | + | ||
211 | + } else if (event instanceof HostEvent) { | ||
212 | + HostEvent hostEvent = (HostEvent) event; | ||
213 | + print("%s %s\t%s [%s->%s]", | ||
214 | + new LocalDateTime(event.time()), | ||
215 | + event.type(), | ||
216 | + hostEvent.subject().id(), | ||
217 | + hostEvent.prevSubject(), hostEvent.subject()); | ||
218 | + | ||
219 | + } else if (event instanceof TopologyEvent) { | ||
220 | + TopologyEvent topoEvent = (TopologyEvent) event; | ||
221 | + List<Event> reasons = MoreObjects.firstNonNull(topoEvent.reasons(), ImmutableList.of()); | ||
222 | + Topology topo = topoEvent.subject(); | ||
223 | + String summary = String.format("(d=%d,l=%d,c=%d)", | ||
224 | + topo.deviceCount(), | ||
225 | + topo.linkCount(), | ||
226 | + topo.clusterCount()); | ||
227 | + print("%s %s%s [%s]", | ||
228 | + new LocalDateTime(event.time()), | ||
229 | + event.type(), | ||
230 | + summary, | ||
231 | + reasons.stream().map(e -> e.type()).collect(toList())); | ||
232 | + | ||
233 | + } else if (event instanceof ClusterEvent) { | ||
234 | + print("%s %s\t%s [%s]", | ||
235 | + new LocalDateTime(event.time()), | ||
236 | + event.type(), | ||
237 | + ((ClusterEvent) event).subject().id(), | ||
238 | + event.subject()); | ||
239 | + | ||
240 | + } else { | ||
241 | + // Unknown Event? | ||
242 | + print("%s %s\t%s [%s]", | ||
243 | + new LocalDateTime(event.time()), | ||
244 | + event.type(), | ||
245 | + event.subject(), | ||
246 | + event); | ||
247 | + } | ||
248 | + } | ||
249 | + | ||
250 | +} |
1 | +/* | ||
2 | + * Copyright 2016 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +/** | ||
18 | + * Application to store history of instance local ONOS Events. | ||
19 | + */ | ||
20 | +package org.onosproject.events; |
1 | +<!-- | ||
2 | + ~ Copyright 2016 Open Networking Laboratory | ||
3 | + ~ | ||
4 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + ~ you may not use this file except in compliance with the License. | ||
6 | + ~ You may obtain a copy of the License at | ||
7 | + ~ | ||
8 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + ~ | ||
10 | + ~ Unless required by applicable law or agreed to in writing, software | ||
11 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + ~ See the License for the specific language governing permissions and | ||
14 | + ~ limitations under the License. | ||
15 | + --> | ||
16 | +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> | ||
17 | + | ||
18 | + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"> | ||
19 | + <command> | ||
20 | + <action class="org.onosproject.events.EventsCommand"/> | ||
21 | + </command> | ||
22 | + </command-bundle> | ||
23 | + | ||
24 | +</blueprint> |
... | @@ -63,6 +63,7 @@ | ... | @@ -63,6 +63,7 @@ |
63 | <module>pathpainter</module> | 63 | <module>pathpainter</module> |
64 | <module>drivermatrix</module> | 64 | <module>drivermatrix</module> |
65 | <module>cpman</module> | 65 | <module>cpman</module> |
66 | + <module>events</module> | ||
66 | </modules> | 67 | </modules> |
67 | 68 | ||
68 | <properties> | 69 | <properties> |
... | @@ -107,3 +108,4 @@ | ... | @@ -107,3 +108,4 @@ |
107 | </build> | 108 | </build> |
108 | 109 | ||
109 | </project> | 110 | </project> |
111 | + | ... | ... |
1 | +/* | ||
2 | + * Copyright 2016 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.event; | ||
17 | + | ||
18 | +import java.util.ArrayList; | ||
19 | +import java.util.List; | ||
20 | + | ||
21 | +import javax.annotation.concurrent.NotThreadSafe; | ||
22 | + | ||
23 | +import org.apache.commons.lang3.tuple.Pair; | ||
24 | + | ||
25 | +import com.google.common.annotations.Beta; | ||
26 | +import com.google.common.collect.Lists; | ||
27 | + | ||
28 | +/** | ||
29 | + * Utility to keeps track of registered Listeners. | ||
30 | + * <p> | ||
31 | + * Usage Example: | ||
32 | + * <pre> | ||
33 | + * <code> | ||
34 | + private ListenerTracker listeners; | ||
35 | + | ||
36 | + {@code @Activate} | ||
37 | + protected void activate() { | ||
38 | + listeners = new ListenerTracker(); | ||
39 | + listeners.addListener(mastershipService, new InternalMastershipListener()) | ||
40 | + .addListener(deviceService, new InternalDeviceListener()) | ||
41 | + .addListener(linkService, new InternalLinkListener()) | ||
42 | + .addListener(topologyService, new InternalTopologyListener()) | ||
43 | + .addListener(hostService, new InternalHostListener()); | ||
44 | + } | ||
45 | + | ||
46 | + {@code @Deactivate} | ||
47 | + protected void deactivate() { | ||
48 | + listeners.removeListeners(); | ||
49 | + } | ||
50 | + * </code> | ||
51 | + * </pre> | ||
52 | + */ | ||
53 | +@Beta | ||
54 | +@NotThreadSafe | ||
55 | +public class ListenerTracker { | ||
56 | + | ||
57 | + @SuppressWarnings("rawtypes") | ||
58 | + private List<Pair<ListenerService, EventListener>> listeners = new ArrayList<>(); | ||
59 | + | ||
60 | + /** | ||
61 | + * Adds {@link EventListener} to specified {@link ListenerService}. | ||
62 | + * | ||
63 | + * @param service {@link ListenerService} | ||
64 | + * @param listener {@link EventListener} | ||
65 | + * @return self | ||
66 | + */ | ||
67 | + public <E extends Event<?, ?>, L extends EventListener<E>> | ||
68 | + ListenerTracker addListener(ListenerService<E, L> service, L listener) { | ||
69 | + service.addListener(listener); | ||
70 | + listeners.add(Pair.of(service, listener)); | ||
71 | + return this; | ||
72 | + } | ||
73 | + | ||
74 | + /** | ||
75 | + * Removes all listeners in reverse order they have been registered. | ||
76 | + */ | ||
77 | + public void removeListeners() { | ||
78 | + Lists.reverse(listeners) | ||
79 | + .forEach(r -> r.getLeft().removeListener(r.getRight())); | ||
80 | + listeners.clear(); | ||
81 | + } | ||
82 | +} |
1 | +/* | ||
2 | + * Copyright 2016 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onlab.util; | ||
17 | + | ||
18 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
19 | + | ||
20 | +import java.util.Collection; | ||
21 | +import java.util.Deque; | ||
22 | +import java.util.Iterator; | ||
23 | +import java.util.Spliterator; | ||
24 | +import java.util.function.Consumer; | ||
25 | +import java.util.function.Predicate; | ||
26 | +import java.util.stream.Stream; | ||
27 | +import com.google.common.collect.Iterators; | ||
28 | + | ||
29 | +/** | ||
30 | + * Unmodifiable view of the specified Deque. | ||
31 | + */ | ||
32 | +public class UnmodifiableDeque<E> implements Deque<E> { | ||
33 | + | ||
34 | + private final Deque<E> deque; | ||
35 | + | ||
36 | + UnmodifiableDeque(Deque<E> deque) { | ||
37 | + this.deque = checkNotNull(deque); | ||
38 | + } | ||
39 | + | ||
40 | + /** | ||
41 | + * Returns an unmodifiable view of the specified Deque. | ||
42 | + * | ||
43 | + * @param deque underlying {@link Deque} to use. | ||
44 | + * @return unmodifiable view of {@code deque} | ||
45 | + */ | ||
46 | + public static <T> Deque<T> unmodifiableDeque(Deque<T> deque) { | ||
47 | + return new UnmodifiableDeque<T>(deque); | ||
48 | + } | ||
49 | + | ||
50 | + @Override | ||
51 | + public void forEach(Consumer<? super E> action) { | ||
52 | + deque.forEach(action); | ||
53 | + } | ||
54 | + | ||
55 | + @Override | ||
56 | + public void addFirst(E e) { | ||
57 | + throw new UnsupportedOperationException(); | ||
58 | + } | ||
59 | + | ||
60 | + @Override | ||
61 | + public boolean isEmpty() { | ||
62 | + return deque.isEmpty(); | ||
63 | + } | ||
64 | + | ||
65 | + @Override | ||
66 | + public void addLast(E e) { | ||
67 | + throw new UnsupportedOperationException(); | ||
68 | + } | ||
69 | + | ||
70 | + @Override | ||
71 | + public Object[] toArray() { | ||
72 | + return deque.toArray(); | ||
73 | + } | ||
74 | + | ||
75 | + @Override | ||
76 | + public boolean offerFirst(E e) { | ||
77 | + throw new UnsupportedOperationException(); | ||
78 | + } | ||
79 | + | ||
80 | + @Override | ||
81 | + public <T> T[] toArray(T[] a) { | ||
82 | + return deque.toArray(a); | ||
83 | + } | ||
84 | + | ||
85 | + @Override | ||
86 | + public boolean offerLast(E e) { | ||
87 | + throw new UnsupportedOperationException(); | ||
88 | + } | ||
89 | + | ||
90 | + @Override | ||
91 | + public E removeFirst() { | ||
92 | + throw new UnsupportedOperationException(); | ||
93 | + } | ||
94 | + | ||
95 | + @Override | ||
96 | + public E removeLast() { | ||
97 | + throw new UnsupportedOperationException(); | ||
98 | + } | ||
99 | + | ||
100 | + @Override | ||
101 | + public E pollFirst() { | ||
102 | + throw new UnsupportedOperationException(); | ||
103 | + } | ||
104 | + | ||
105 | + @Override | ||
106 | + public E pollLast() { | ||
107 | + throw new UnsupportedOperationException(); | ||
108 | + } | ||
109 | + | ||
110 | + @Override | ||
111 | + public E getFirst() { | ||
112 | + return deque.getFirst(); | ||
113 | + } | ||
114 | + | ||
115 | + @Override | ||
116 | + public E getLast() { | ||
117 | + return deque.getLast(); | ||
118 | + } | ||
119 | + | ||
120 | + @Override | ||
121 | + public E peekFirst() { | ||
122 | + return deque.peekFirst(); | ||
123 | + } | ||
124 | + | ||
125 | + @Override | ||
126 | + public E peekLast() { | ||
127 | + return deque.peekLast(); | ||
128 | + } | ||
129 | + | ||
130 | + @Override | ||
131 | + public boolean removeFirstOccurrence(Object o) { | ||
132 | + throw new UnsupportedOperationException(); | ||
133 | + } | ||
134 | + | ||
135 | + @Override | ||
136 | + public boolean removeLastOccurrence(Object o) { | ||
137 | + throw new UnsupportedOperationException(); | ||
138 | + } | ||
139 | + | ||
140 | + @Override | ||
141 | + public boolean containsAll(Collection<?> c) { | ||
142 | + return deque.containsAll(c); | ||
143 | + } | ||
144 | + | ||
145 | + @Override | ||
146 | + public boolean add(E e) { | ||
147 | + throw new UnsupportedOperationException(); | ||
148 | + } | ||
149 | + | ||
150 | + @Override | ||
151 | + public boolean addAll(Collection<? extends E> c) { | ||
152 | + throw new UnsupportedOperationException(); | ||
153 | + } | ||
154 | + | ||
155 | + @Override | ||
156 | + public boolean offer(E e) { | ||
157 | + throw new UnsupportedOperationException(); | ||
158 | + } | ||
159 | + | ||
160 | + @Override | ||
161 | + public boolean removeAll(Collection<?> c) { | ||
162 | + throw new UnsupportedOperationException(); | ||
163 | + } | ||
164 | + | ||
165 | + @Override | ||
166 | + public E remove() { | ||
167 | + throw new UnsupportedOperationException(); | ||
168 | + } | ||
169 | + | ||
170 | + @Override | ||
171 | + public E poll() { | ||
172 | + throw new UnsupportedOperationException(); | ||
173 | + } | ||
174 | + | ||
175 | + @Override | ||
176 | + public E element() { | ||
177 | + return deque.element(); | ||
178 | + } | ||
179 | + | ||
180 | + @Override | ||
181 | + public boolean removeIf(Predicate<? super E> filter) { | ||
182 | + throw new UnsupportedOperationException(); | ||
183 | + } | ||
184 | + | ||
185 | + @Override | ||
186 | + public E peek() { | ||
187 | + return deque.peek(); | ||
188 | + } | ||
189 | + | ||
190 | + @Override | ||
191 | + public void push(E e) { | ||
192 | + throw new UnsupportedOperationException(); | ||
193 | + } | ||
194 | + | ||
195 | + @Override | ||
196 | + public boolean retainAll(Collection<?> c) { | ||
197 | + throw new UnsupportedOperationException(); | ||
198 | + } | ||
199 | + | ||
200 | + @Override | ||
201 | + public E pop() { | ||
202 | + throw new UnsupportedOperationException(); | ||
203 | + } | ||
204 | + | ||
205 | + @Override | ||
206 | + public boolean remove(Object o) { | ||
207 | + throw new UnsupportedOperationException(); | ||
208 | + } | ||
209 | + | ||
210 | + @Override | ||
211 | + public void clear() { | ||
212 | + throw new UnsupportedOperationException(); | ||
213 | + } | ||
214 | + | ||
215 | + @Override | ||
216 | + public boolean equals(Object o) { | ||
217 | + return deque.equals(o); | ||
218 | + } | ||
219 | + | ||
220 | + @Override | ||
221 | + public boolean contains(Object o) { | ||
222 | + return deque.contains(o); | ||
223 | + } | ||
224 | + | ||
225 | + @Override | ||
226 | + public int size() { | ||
227 | + return deque.size(); | ||
228 | + } | ||
229 | + | ||
230 | + @Override | ||
231 | + public Iterator<E> iterator() { | ||
232 | + return Iterators.unmodifiableIterator(deque.iterator()); | ||
233 | + } | ||
234 | + | ||
235 | + @Override | ||
236 | + public Iterator<E> descendingIterator() { | ||
237 | + return Iterators.unmodifiableIterator(deque.descendingIterator()); | ||
238 | + } | ||
239 | + | ||
240 | + @Override | ||
241 | + public int hashCode() { | ||
242 | + return deque.hashCode(); | ||
243 | + } | ||
244 | + | ||
245 | + @Override | ||
246 | + public Spliterator<E> spliterator() { | ||
247 | + return deque.spliterator(); | ||
248 | + } | ||
249 | + | ||
250 | + @Override | ||
251 | + public Stream<E> stream() { | ||
252 | + return deque.stream(); | ||
253 | + } | ||
254 | + | ||
255 | + @Override | ||
256 | + public Stream<E> parallelStream() { | ||
257 | + return deque.parallelStream(); | ||
258 | + } | ||
259 | + | ||
260 | + @Override | ||
261 | + public String toString() { | ||
262 | + return deque.toString(); | ||
263 | + } | ||
264 | +} |
-
Please register or login to post a comment