0b1c77fe7c7a93bd6323c74aaec910c7eb934801
[deliverable/tracecompass.git] / org.eclipse.tracecompass.lttng2.control.ui / src / org / eclipse / tracecompass / internal / lttng2 / control / ui / views / service / LTTngControlServiceMI.java
1 /**********************************************************************
2 * Copyright (c) 2014, 2015 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Jonathan Rajotte - Initial support for machine interface lttng 2.6
11 * Bernd Hufmann - Fix check for live session
12 **********************************************************************/
13
14 package org.eclipse.tracecompass.internal.lttng2.control.ui.views.service;
15
16 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
17
18 import java.io.IOException;
19 import java.io.StringReader;
20 import java.math.BigInteger;
21 import java.net.URL;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.regex.Matcher;
25
26 import javax.xml.XMLConstants;
27 import javax.xml.parsers.DocumentBuilder;
28 import javax.xml.parsers.DocumentBuilderFactory;
29 import javax.xml.parsers.ParserConfigurationException;
30 import javax.xml.validation.SchemaFactory;
31
32 import org.eclipse.core.commands.ExecutionException;
33 import org.eclipse.core.runtime.IProgressMonitor;
34 import org.eclipse.jdt.annotation.NonNull;
35 import org.eclipse.jdt.annotation.Nullable;
36 import org.eclipse.osgi.util.NLS;
37 import org.eclipse.tracecompass.common.core.NonNullUtils;
38 import org.eclipse.tracecompass.internal.lttng2.control.core.model.IBaseEventInfo;
39 import org.eclipse.tracecompass.internal.lttng2.control.core.model.IChannelInfo;
40 import org.eclipse.tracecompass.internal.lttng2.control.core.model.IDomainInfo;
41 import org.eclipse.tracecompass.internal.lttng2.control.core.model.IEventInfo;
42 import org.eclipse.tracecompass.internal.lttng2.control.core.model.IFieldInfo;
43 import org.eclipse.tracecompass.internal.lttng2.control.core.model.IProbeEventInfo;
44 import org.eclipse.tracecompass.internal.lttng2.control.core.model.ISessionInfo;
45 import org.eclipse.tracecompass.internal.lttng2.control.core.model.ISnapshotInfo;
46 import org.eclipse.tracecompass.internal.lttng2.control.core.model.IUstProviderInfo;
47 import org.eclipse.tracecompass.internal.lttng2.control.core.model.LogLevelType;
48 import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceDomainType;
49 import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceEnablement;
50 import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceEventType;
51 import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceLogLevel;
52 import org.eclipse.tracecompass.internal.lttng2.control.core.model.impl.BaseEventInfo;
53 import org.eclipse.tracecompass.internal.lttng2.control.core.model.impl.BufferType;
54 import org.eclipse.tracecompass.internal.lttng2.control.core.model.impl.ChannelInfo;
55 import org.eclipse.tracecompass.internal.lttng2.control.core.model.impl.DomainInfo;
56 import org.eclipse.tracecompass.internal.lttng2.control.core.model.impl.EventInfo;
57 import org.eclipse.tracecompass.internal.lttng2.control.core.model.impl.FieldInfo;
58 import org.eclipse.tracecompass.internal.lttng2.control.core.model.impl.ProbeEventInfo;
59 import org.eclipse.tracecompass.internal.lttng2.control.core.model.impl.SessionInfo;
60 import org.eclipse.tracecompass.internal.lttng2.control.core.model.impl.SnapshotInfo;
61 import org.eclipse.tracecompass.internal.lttng2.control.core.model.impl.UstProviderInfo;
62 import org.eclipse.tracecompass.internal.lttng2.control.ui.views.handlers.XmlMiValidationErrorHandler;
63 import org.eclipse.tracecompass.internal.lttng2.control.ui.views.messages.Messages;
64 import org.eclipse.tracecompass.tmf.remote.core.shell.ICommandInput;
65 import org.eclipse.tracecompass.tmf.remote.core.shell.ICommandResult;
66 import org.eclipse.tracecompass.tmf.remote.core.shell.ICommandShell;
67 import org.w3c.dom.Document;
68 import org.w3c.dom.Node;
69 import org.w3c.dom.NodeList;
70 import org.xml.sax.InputSource;
71 import org.xml.sax.SAXException;
72
73 /**
74 * Service for sending LTTng trace control commands to remote host via machine
75 * interface mode.
76 *
77 * @author Jonathan Rajotte
78 */
79 public class LTTngControlServiceMI extends LTTngControlService {
80
81 // ------------------------------------------------------------------------
82 // Attributes
83 // ------------------------------------------------------------------------
84
85 private final DocumentBuilder fDocumentBuilder;
86
87 // ------------------------------------------------------------------------
88 // Constructors
89 // ------------------------------------------------------------------------
90
91 /**
92 * Constructor
93 *
94 * @param shell
95 * the command shell implementation to use
96 * @param xsdUrl
97 * the xsd schema file for validation
98 * @throws ExecutionException
99 * if the creation of the Schema and DocumentBuilder objects
100 * fails
101 */
102 public LTTngControlServiceMI(@NonNull ICommandShell shell, @Nullable URL xsdUrl) throws ExecutionException {
103 super(shell);
104
105 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
106 docBuilderFactory.setValidating(false);
107
108 // Validate XSD schema
109 if (xsdUrl != null) {
110 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
111 try {
112 docBuilderFactory.setSchema(schemaFactory.newSchema(xsdUrl));
113 } catch (SAXException e) {
114 throw new ExecutionException(Messages.TraceControl_InvalidSchemaError, e);
115 }
116 }
117
118 try {
119 fDocumentBuilder = docBuilderFactory.newDocumentBuilder();
120 } catch (ParserConfigurationException e) {
121 throw new ExecutionException(Messages.TraceControl_XmlDocumentBuilderError, e);
122 }
123
124 fDocumentBuilder.setErrorHandler(new XmlMiValidationErrorHandler());
125
126 }
127
128 /**
129 * Generate a Document object from an list of Strings.
130 *
131 * @param xmlStrings
132 * list of strings representing an xml input
133 * @return Document generated from strings input
134 * @throws ExecutionException
135 * when parsing has failed
136 */
137 private Document getDocumentFromStrings(List<String> xmlStrings) throws ExecutionException {
138 StringBuilder concatenedString = new StringBuilder();
139 for (String string : xmlStrings) {
140 concatenedString.append(string);
141 }
142 InputSource stream = new InputSource(new StringReader(concatenedString.toString()));
143
144 Document document;
145 try {
146 document = fDocumentBuilder.parse(stream);
147 } catch (SAXException | IOException e) {
148 throw new ExecutionException(Messages.TraceControl_XmlParsingError + ':' + e.toString(), e);
149 }
150 return document;
151
152 }
153
154 /**
155 * Parse, populate and set the internal LTTngVersion variable
156 *
157 * @param xmlOutput
158 * the mi xml output of lttng version
159 * @throws ExecutionException
160 * when xml extraction fail
161 */
162 public void setVersion(List<String> xmlOutput) throws ExecutionException {
163 Document doc = getDocumentFromStrings(xmlOutput);
164 NodeList element = doc.getElementsByTagName(MIStrings.VERSION);
165 int major = 0;
166 int minor = 0;
167 int patchLevel = 0;
168 String license = ""; //$NON-NLS-1$
169 String commit = ""; //$NON-NLS-1$
170 String name = ""; //$NON-NLS-1$
171 String description = ""; //$NON-NLS-1$
172 String url = ""; //$NON-NLS-1$
173 String fullVersion = ""; //$NON-NLS-1$
174 if (element.getLength() == 1) {
175 NodeList child = element.item(0).getChildNodes();
176 // Get basic information
177 for (int i = 0; i < child.getLength(); i++) {
178 Node node = child.item(i);
179 switch (node.getNodeName()) {
180 case MIStrings.VERSION_MAJOR:
181 major = Integer.parseInt(node.getTextContent());
182 break;
183 case MIStrings.VERSION_MINOR:
184 minor = Integer.parseInt(node.getTextContent());
185 break;
186 case MIStrings.VERSION_PATCH_LEVEL:
187 patchLevel = Integer.parseInt(node.getTextContent());
188 break;
189 case MIStrings.VERSION_COMMIT:
190 commit = node.getTextContent();
191 break;
192 case MIStrings.VERSION_DESCRIPTION:
193 description = node.getTextContent();
194 break;
195 case MIStrings.VERSION_LICENSE:
196 license = node.getTextContent();
197 break;
198 case MIStrings.VERSION_NAME:
199 name = node.getTextContent();
200 break;
201 case MIStrings.VERSION_STR:
202 fullVersion = node.getTextContent();
203 break;
204 case MIStrings.VERSION_WEB:
205 url = node.getTextContent();
206 break;
207 default:
208 break;
209 }
210 }
211 setVersion(new LttngVersion(major, minor, patchLevel, license, commit, name, description, url, fullVersion));
212 } else {
213 throw new ExecutionException(Messages.TraceControl_UnsupportedVersionError);
214 }
215 }
216
217 @Override
218 public List<String> getSessionNames(IProgressMonitor monitor) throws ExecutionException {
219 ICommandInput command = createCommand(LTTngControlServiceConstants.COMMAND_LIST);
220 ICommandResult result = executeCommand(command, monitor);
221
222 Document doc = getDocumentFromStrings(result.getOutput());
223
224 NodeList elements = doc.getElementsByTagName(MIStrings.NAME);
225
226 ArrayList<String> retArray = new ArrayList<>();
227 for (int i = 0; i < elements.getLength(); i++) {
228 Node node = elements.item(i);
229 if (node.getParentNode().getNodeName().equalsIgnoreCase(MIStrings.SESSION)) {
230 retArray.add(node.getTextContent());
231 }
232 }
233 return retArray;
234 }
235
236 @Override
237 public ISessionInfo getSession(String sessionName, IProgressMonitor monitor) throws ExecutionException {
238 ICommandInput command = createCommand(LTTngControlServiceConstants.COMMAND_LIST, sessionName);
239 ICommandResult result = executeCommand(command, monitor);
240
241 ISessionInfo sessionInfo = new SessionInfo(sessionName);
242 Document document = getDocumentFromStrings(result.getOutput());
243
244 NodeList sessionsNode = document.getElementsByTagName(MIStrings.SESSION);
245 // There should be only one session
246 if (sessionsNode.getLength() != 1) {
247 throw new ExecutionException(NLS.bind(Messages.TraceControl_MiInvalidNumberOfElementError, MIStrings.SESSION));
248 }
249
250 // Populate session information
251 Node rawSession = sessionsNode.item(0);
252 parseSession(sessionInfo, rawSession);
253
254 // Fetch the snapshot info
255 if (sessionInfo.isSnapshotSession()) {
256 ISnapshotInfo snapshot = getSnapshotInfo(sessionName, monitor);
257 sessionInfo.setSnapshotInfo(snapshot);
258 }
259
260 return sessionInfo;
261 }
262
263 /**
264 * @param sessionInfo
265 * @param rawSession
266 * @throws ExecutionException
267 */
268 private void parseSession(ISessionInfo sessionInfo, Node rawSession) throws ExecutionException {
269 if (!rawSession.getNodeName().equalsIgnoreCase(MIStrings.SESSION)) {
270 throw new ExecutionException(Messages.TraceControl_MiInvalidElementError);
271 }
272 NodeList rawSessionInfos = rawSession.getChildNodes();
273 for (int i = 0; i < rawSessionInfos.getLength(); i++) {
274 Node rawInfo = rawSessionInfos.item(i);
275 switch (rawInfo.getNodeName()) {
276 case MIStrings.NAME:
277 sessionInfo.setName(rawInfo.getTextContent());
278 break;
279 case MIStrings.PATH:
280 sessionInfo.setSessionPath(rawInfo.getTextContent());
281 break;
282 case MIStrings.ENABLED:
283 sessionInfo.setSessionState(rawInfo.getTextContent());
284 break;
285 case MIStrings.SNAPSHOT_MODE:
286 if (rawInfo.getTextContent().equals(LTTngControlServiceConstants.TRUE_NUMERICAL)) {
287 // real name will be set later
288 ISnapshotInfo snapshotInfo = new SnapshotInfo(""); //$NON-NLS-1$
289 sessionInfo.setSnapshotInfo(snapshotInfo);
290 }
291 break;
292 case MIStrings.LIVE_TIMER_INTERVAL:
293 long liveDelay = Long.parseLong(rawInfo.getTextContent());
294 if ((liveDelay > 0 && (liveDelay <= LTTngControlServiceConstants.MAX_LIVE_TIMER_INTERVAL))) {
295 sessionInfo.setLive(true);
296 sessionInfo.setLiveUrl(SessionInfo.DEFAULT_LIVE_NETWORK_URL);
297 sessionInfo.setLivePort(SessionInfo.DEFAULT_LIVE_PORT);
298 sessionInfo.setLiveDelay(liveDelay);
299 }
300 break;
301 case MIStrings.DOMAINS:
302 // Extract the domains node
303 NodeList rawDomains = rawInfo.getChildNodes();
304 IDomainInfo domain = null;
305 for (int j = 0; j < rawDomains.getLength(); j++) {
306 if (rawDomains.item(j).getNodeName().equalsIgnoreCase(MIStrings.DOMAIN)) {
307 domain = parseDomain(rawDomains.item(j));
308 sessionInfo.addDomain(domain);
309 }
310 }
311 break;
312 default:
313 break;
314 }
315 }
316
317 if (!sessionInfo.isSnapshotSession()) {
318 Matcher matcher = LTTngControlServiceConstants.TRACE_NETWORK_PATTERN.matcher(sessionInfo.getSessionPath());
319 if (matcher.matches()) {
320 sessionInfo.setStreamedTrace(true);
321 }
322 }
323 }
324
325 /**
326 * Parse a raw domain XML node to a IDomainInfo object
327 *
328 * @param rawDomain
329 * a domain xml node
330 * @return a populated {@link DomainInfo} object
331 * @throws ExecutionException
332 * when missing required xml element (type)
333 */
334 protected IDomainInfo parseDomain(Node rawDomain) throws ExecutionException {
335 IDomainInfo domain = null;
336 // Get the type
337 Node rawType = getFirstOf(rawDomain.getChildNodes(), MIStrings.TYPE);
338 if (rawType == null) {
339 throw new ExecutionException(Messages.TraceControl_MiMissingRequiredError);
340 }
341 String rawTypeString = rawType.getTextContent().toLowerCase();
342 TraceDomainType domainType = TraceDomainType.valueOfString(rawTypeString);
343 switch (domainType) {
344 case KERNEL:
345 domain = new DomainInfo(Messages.TraceControl_KernelProviderDisplayName);
346 domain.setIsKernel(true);
347 break;
348 case UST:
349 domain = new DomainInfo(Messages.TraceControl_UstGlobalDomainDisplayName);
350 domain.setIsKernel(false);
351 break;
352 case JUL:
353 /**
354 * TODO: Support for JUL JUL substructure and semantic is not the
355 * same as a regular UST or Kernel Domain There is no channel under
356 * JUL domain only events. The channel is activated in UST Channel
357 */
358 domain = new DomainInfo(Messages.TraceControl_JULDomainDisplayName);
359 domain.setIsKernel(false);
360 break;
361 case UNKNOWN:
362 domain = new DomainInfo(Messages.TraceControl_UnknownDomainDisplayName);
363 domain.setIsKernel(false);
364 break;
365 default:
366 throw new ExecutionException(Messages.TraceControl_MiInvalidElementError);
367 }
368
369 NodeList rawInfos = rawDomain.getChildNodes();
370 for (int i = 0; i < rawInfos.getLength(); i++) {
371 Node rawInfo = rawInfos.item(i);
372 switch (rawInfo.getNodeName()) {
373 case MIStrings.BUFFER_TYPE:
374 BufferType bufferType = BufferType.valueOfString(rawInfo.getTextContent());
375 domain.setBufferType(bufferType);
376 break;
377 case MIStrings.CHANNELS:
378 ArrayList<IChannelInfo> channels = new ArrayList<>();
379 parseChannels(rawInfo.getChildNodes(), channels);
380 if (channels.size() > 0) {
381 domain.setChannels(channels);
382 }
383 break;
384 default:
385 break;
386 }
387 }
388
389 return domain;
390 }
391
392 /**
393 * Parse a list of raw channel XML node into an ArrayList of IChannelInfo
394 *
395 * @param rawChannes
396 * List of raw channel XML node
397 * @param channels
398 * the parsed channels list
399 * @throws ExecutionException
400 * when missing required xml element (type)
401 */
402 private static void parseChannels(NodeList rawChannels, ArrayList<IChannelInfo> channels) throws ExecutionException {
403 IChannelInfo channel = null;
404 for (int i = 0; i < rawChannels.getLength(); i++) {
405 Node rawChannel = rawChannels.item(i);
406 if (rawChannel.getNodeName().equalsIgnoreCase(MIStrings.CHANNEL)) {
407 channel = new ChannelInfo(""); //$NON-NLS-1$
408
409 // Populate the channel
410 NodeList rawInfos = rawChannel.getChildNodes();
411 Node rawInfo = null;
412 for (int j = 0; j < rawInfos.getLength(); j++) {
413 rawInfo = rawInfos.item(j);
414 switch (rawInfo.getNodeName()) {
415 case MIStrings.NAME:
416 channel.setName(rawInfo.getTextContent());
417 break;
418 case MIStrings.ENABLED:
419 channel.setState(TraceEnablement.valueOfString(rawInfo.getTextContent()));
420 break;
421 case MIStrings.EVENTS:
422 List<IEventInfo> events = new ArrayList<>();
423 getEventInfo(rawInfo.getChildNodes(), events);
424 channel.setEvents(events);
425 break;
426 case MIStrings.ATTRIBUTES:
427 NodeList rawAttributes = rawInfo.getChildNodes();
428 for (int k = 0; k < rawAttributes.getLength(); k++) {
429 Node attribute = rawAttributes.item(k);
430 switch (attribute.getNodeName()) {
431 case MIStrings.OVERWRITE_MODE:
432 channel.setOverwriteMode(!LTTngControlServiceConstants.OVERWRITE_MODE_ATTRIBUTE_FALSE_MI.equalsIgnoreCase(attribute.getTextContent()));
433 break;
434 case MIStrings.SUBBUF_SIZE:
435 channel.setSubBufferSize(Long.valueOf(attribute.getTextContent()));
436 break;
437 case MIStrings.NUM_SUBBUF:
438 channel.setNumberOfSubBuffers(Integer.valueOf(attribute.getTextContent()));
439 break;
440 case MIStrings.SWITCH_TIMER_INTERVAL:
441 channel.setSwitchTimer(Long.valueOf(attribute.getTextContent()));
442 break;
443 case MIStrings.READ_TIMER_INTERVAL:
444 channel.setReadTimer(Long.valueOf(attribute.getTextContent()));
445 break;
446 case MIStrings.OUTPUT_TYPE:
447 channel.setOutputType(attribute.getTextContent());
448 break;
449 case MIStrings.TRACEFILE_SIZE:
450 channel.setMaxSizeTraceFiles(Long.parseLong(attribute.getTextContent()));
451 break;
452 case MIStrings.TRACEFILE_COUNT:
453 channel.setMaxNumberTraceFiles(Integer.parseInt(attribute.getTextContent()));
454 break;
455 case MIStrings.LIVE_TIMER_INTERVAL:
456 // TODO: currently not supported by tmf
457 break;
458 default:
459 break;
460 }
461 }
462 break;
463 default:
464 break;
465 }
466 }
467 channels.add(channel);
468 }
469 }
470
471 }
472
473 @Override
474 public ISnapshotInfo getSnapshotInfo(String sessionName, IProgressMonitor monitor) throws ExecutionException {
475 // TODO A session can have multiple snapshot output. This need to be
476 // supported in the future.
477 // Currently the SessionInfo object does not support multiple snashot
478 // output.
479 // For now only keep the last one.
480 ICommandInput command = createCommand(LTTngControlServiceConstants.COMMAND_SNAPSHOT, LTTngControlServiceConstants.COMMAND_LIST_SNAPSHOT_OUTPUT, LTTngControlServiceConstants.OPTION_SESSION, sessionName);
481 ICommandResult result = executeCommand(command, monitor);
482 Document doc = getDocumentFromStrings(result.getOutput());
483 NodeList rawSnapshotsOutputs = doc.getElementsByTagName(MIStrings.SNAPSHOT_OUTPUTS);
484
485 ISnapshotInfo snapshotInfo = new SnapshotInfo(""); //$NON-NLS-1$
486
487 // TODO: tmf does not have a notion of a ctrl url.
488 for (int i = 0; i < rawSnapshotsOutputs.getLength(); i++) {
489 NodeList rawSnapshotOutput = rawSnapshotsOutputs.item(i).getChildNodes();
490 for (int j = 0; j < rawSnapshotOutput.getLength(); j++) {
491 Node rawInfo = rawSnapshotOutput.item(j);
492 switch (rawInfo.getNodeName()) {
493 case MIStrings.ID:
494 snapshotInfo.setId(Integer.parseInt(rawInfo.getTextContent()));
495 break;
496 case MIStrings.NAME:
497 snapshotInfo.setName(rawInfo.getTextContent());
498 break;
499 case MIStrings.SNAPSHOT_CTRL_URL:
500 // The use of the ctrl_url for the snapshot path is to assure
501 // basic support. Refactoring is necessary in lttng and
502 // tmf side.
503 // See http://bugs.lttng.org/issues/828 (+comment)
504 snapshotInfo.setSnapshotPath(rawInfo.getTextContent());
505 break;
506 default:
507 break;
508 }
509 }
510 }
511
512 // Check if the snapshot output is Streamed
513 Matcher matcher2 = LTTngControlServiceConstants.TRACE_NETWORK_PATTERN.matcher(snapshotInfo.getSnapshotPath());
514 if (matcher2.matches()) {
515 snapshotInfo.setStreamedSnapshot(true);
516 }
517
518 return snapshotInfo;
519 }
520
521 @Override
522 public List<IBaseEventInfo> getKernelProvider(IProgressMonitor monitor) throws ExecutionException {
523 ICommandInput command = createCommand(LTTngControlServiceConstants.COMMAND_LIST, LTTngControlServiceConstants.OPTION_KERNEL);
524 ICommandResult result = executeCommand(command, monitor, false);
525 List<IBaseEventInfo> events = new ArrayList<>();
526
527 if (isError(result)) {
528 // Ignore the following 2 cases:
529 // Spawning a session daemon
530 // Error: Unable to list kernel events
531 // or:
532 // Error: Unable to list kernel events
533 if (ignoredPattern(result.getErrorOutput(), LTTngControlServiceConstants.LIST_KERNEL_NO_KERNEL_PROVIDER_PATTERN)) {
534 return events;
535 }
536 throw new ExecutionException(Messages.TraceControl_CommandError + command.toString());
537 }
538
539 Document document = getDocumentFromStrings(result.getOutput());
540 NodeList rawEvents = document.getElementsByTagName(MIStrings.EVENT);
541 getBaseEventInfo(rawEvents, events);
542 return events;
543 }
544
545 @Override
546 public List<IUstProviderInfo> getUstProvider(IProgressMonitor monitor) throws ExecutionException {
547 ICommandInput command = createCommand(LTTngControlServiceConstants.COMMAND_LIST, LTTngControlServiceConstants.OPTION_UST);
548 // Get the field to
549 command.add(LTTngControlServiceConstants.OPTION_FIELDS);
550
551 // Execute
552 ICommandResult result = executeCommand(command, monitor, false);
553 List<IUstProviderInfo> allProviders = new ArrayList<>();
554
555 if (isError(result)) {
556 // Ignore the following 2 cases:
557 // Spawning a session daemon
558 // Error: Unable to list UST events: Listing UST events failed
559 // or:
560 // Error: Unable to list UST events: Listing UST events failed
561 if (ignoredPattern(result.getErrorOutput(), LTTngControlServiceConstants.LIST_UST_NO_UST_PROVIDER_PATTERN)) {
562 return allProviders;
563 }
564 throw new ExecutionException(Messages.TraceControl_CommandError + command.toString());
565 }
566
567 Document document = getDocumentFromStrings(result.getOutput());
568 NodeList rawProviders = document.getElementsByTagName(MIStrings.PID);
569
570 IUstProviderInfo providerInfo = null;
571
572 for (int i = 0; i < rawProviders.getLength(); i++) {
573 Node provider = rawProviders.item(i);
574 Node name = getFirstOf(provider.getChildNodes(), MIStrings.NAME);
575 if (name == null) {
576 throw new ExecutionException(Messages.TraceControl_MiInvalidProviderError);
577 }
578 providerInfo = new UstProviderInfo(name.getTextContent());
579
580 // Populate provider
581 NodeList infos = provider.getChildNodes();
582 for (int j = 0; j < infos.getLength(); j++) {
583 Node info = infos.item(j);
584 switch (info.getNodeName()) {
585 case MIStrings.PID_ID:
586 providerInfo.setPid(Integer.parseInt(info.getTextContent()));
587 break;
588 case MIStrings.EVENTS:
589 List<IBaseEventInfo> events = new ArrayList<>();
590 NodeList rawEvents = info.getChildNodes();
591 getBaseEventInfo(rawEvents, events);
592 providerInfo.setEvents(events);
593 break;
594 default:
595 break;
596 }
597 }
598 allProviders.add(providerInfo);
599 }
600
601 return allProviders;
602 }
603
604 @Override
605 public ISessionInfo createSession(ISessionInfo sessionInfo, IProgressMonitor monitor) throws ExecutionException {
606 if (sessionInfo.isStreamedTrace()) {
607 return createStreamedSession(sessionInfo, monitor);
608 }
609
610 ICommandInput command = prepareSessionCreationCommand(sessionInfo);
611 ICommandResult result = executeCommand(command, monitor);
612
613 Document document = getDocumentFromStrings(result.getOutput());
614 NodeList sessions = document.getElementsByTagName(MIStrings.SESSION);
615
616 // Number of session should be equal to 1
617 if (sessions.getLength() != 1) {
618 throw new ExecutionException(Messages.TraceControl_CommandError + " " + command + "\n" //$NON-NLS-1$//$NON-NLS-2$
619 + NLS.bind(Messages.TraceControl_UnexpectedNumberOfElementError, MIStrings.SESSION) + " " + sessions.getLength()); //$NON-NLS-1$
620 }
621
622 // Fetch a session from output
623 ISessionInfo outputSession = new SessionInfo(""); //$NON-NLS-1$
624 parseSession(outputSession, sessions.item(0));
625
626 // Verify session name
627 if ((outputSession.getName().equals("")) || (!"".equals(sessionInfo.getName()) && !outputSession.getName().equals(sessionInfo.getName()))) { //$NON-NLS-1$ //$NON-NLS-2$
628 // Unexpected name returned
629 throw new ExecutionException(Messages.TraceControl_CommandError + " " + command + "\n" + //$NON-NLS-1$ //$NON-NLS-2$
630 Messages.TraceControl_UnexpectedNameError + ": " + outputSession.getName()); //$NON-NLS-1$
631 }
632
633 // Verify session path
634 if (!sessionInfo.isSnapshotSession() &&
635 ((outputSession.getSessionPath() == null) || ((sessionInfo.getSessionPath() != null) && (!outputSession.getSessionPath().contains(sessionInfo.getSessionPath()))))) {
636 // Unexpected path
637 throw new ExecutionException(Messages.TraceControl_CommandError + " " + command + "\n" + //$NON-NLS-1$ //$NON-NLS-2$
638 Messages.TraceControl_UnexpectedPathError + ": " + outputSession.getName()); //$NON-NLS-1$
639 }
640
641 if (sessionInfo.isSnapshotSession()) {
642 // Make it a snapshot session - content of snapshot info need to
643 // set afterwards using getSession() or getSnapshotInfo()
644 outputSession.setSnapshotInfo(new SnapshotInfo("")); //$NON-NLS-1$
645 }
646
647 return outputSession;
648 }
649
650 private @NonNull ISessionInfo createStreamedSession(ISessionInfo sessionInfo, IProgressMonitor monitor) throws ExecutionException {
651
652 ICommandInput command = prepareStreamedSessionCreationCommand(sessionInfo);
653
654 ICommandResult result = executeCommand(command, monitor);
655
656 Document document = getDocumentFromStrings(result.getOutput());
657 NodeList sessions = document.getElementsByTagName(MIStrings.SESSION);
658
659 // Number of session should be equal to 1
660 if (sessions.getLength() != 1) {
661 throw new ExecutionException(Messages.TraceControl_CommandError + " " + command + "\n" //$NON-NLS-1$//$NON-NLS-2$
662 + NLS.bind(Messages.TraceControl_UnexpectedNumberOfElementError, MIStrings.SESSION) + " " + sessions.getLength()); //$NON-NLS-1$
663 }
664
665 // Fetch a session from output
666 ISessionInfo outputSession = new SessionInfo(""); //$NON-NLS-1$
667 parseSession(outputSession, sessions.item(0));
668
669 // Verify session name
670 if ((outputSession.getName().equals("")) || (!"".equals(sessionInfo.getName()) && !outputSession.getName().equals(sessionInfo.getName()))) { //$NON-NLS-1$ //$NON-NLS-2$
671 // Unexpected name returned
672 throw new ExecutionException(Messages.TraceControl_CommandError + " " + command + "\n" + //$NON-NLS-1$ //$NON-NLS-2$
673 Messages.TraceControl_UnexpectedNameError + ": " + outputSession.getName()); //$NON-NLS-1$
674 }
675
676 sessionInfo.setName(outputSession.getName());
677 sessionInfo.setStreamedTrace(true);
678
679 // Verify session path
680 if (sessionInfo.getNetworkUrl() != null) {
681 if (!sessionInfo.isSnapshotSession() && (outputSession.getSessionPath() == null)) {
682 // Unexpected path
683 throw new ExecutionException(Messages.TraceControl_CommandError + " " + command + "\n" + //$NON-NLS-1$ //$NON-NLS-2$
684 Messages.TraceControl_UnexpectedPathError + ": " + outputSession.getName()); //$NON-NLS-1$
685 }
686
687 if (sessionInfo.isSnapshotSession()) {
688 sessionInfo.setStreamedTrace(false);
689 } else {
690 sessionInfo.setSessionPath(outputSession.getSessionPath());
691 // Check file protocol
692 Matcher matcher = LTTngControlServiceConstants.TRACE_FILE_PROTOCOL_PATTERN.matcher(outputSession.getSessionPath());
693 if (matcher.matches()) {
694 sessionInfo.setStreamedTrace(false);
695 }
696 }
697 }
698
699 // When using controlUrl and dataUrl the full session path is not known
700 // yet
701 // and will be set later on when listing the session
702 return sessionInfo;
703 }
704
705 @Override
706 public void destroySession(String sessionName, IProgressMonitor monitor) throws ExecutionException {
707 ICommandInput command = createCommand(LTTngControlServiceConstants.COMMAND_DESTROY_SESSION, sessionName);
708
709 ICommandResult result = executeCommand(command, monitor, false);
710 List<String> errorOutput = result.getErrorOutput();
711
712 if (isError(result)) {
713 // Don't treat this as an error
714 if (ignoredPattern(errorOutput, LTTngControlServiceConstants.SESSION_NOT_FOUND_ERROR_PATTERN)) {
715 return;
716
717 }
718 throw new ExecutionException(Messages.TraceControl_CommandError + " " + command.toString() + "\n" + result.toString()); //$NON-NLS-1$ //$NON-NLS-2$
719 }
720
721 // Check for action effect
722 Document doc = getDocumentFromStrings(result.getOutput());
723 NodeList sessions = doc.getElementsByTagName(MIStrings.SESSION);
724 if (sessions.getLength() != 1) {
725 throw new ExecutionException(NLS.bind(Messages.TraceControl_MiInvalidNumberOfElementError, MIStrings.SESSION));
726 }
727
728 Node rawSessionName = getFirstOf(sessions.item(0).getChildNodes(), MIStrings.NAME);
729 if (rawSessionName == null) {
730 throw new ExecutionException(Messages.TraceControl_MiMissingRequiredError);
731 }
732
733 // Validity check
734 if (!rawSessionName.getTextContent().equals(sessionName)) {
735 throw new ExecutionException(NLS.bind(Messages.TraceControl_UnexpectedValueError, rawSessionName.getTextContent(), sessionName));
736 }
737 }
738
739 @Override
740 protected ICommandInput createCommand(String... strings) {
741 ICommandInput command = getCommandShell().createCommand();
742 command.add(LTTngControlServiceConstants.CONTROL_COMMAND);
743 List<String> groupOption = getTracingGroupOption();
744 if (!groupOption.isEmpty()) {
745 command.addAll(groupOption);
746 }
747 command.add(LTTngControlServiceConstants.CONTROL_COMMAND_MI_OPTION);
748 command.add(LTTngControlServiceConstants.CONTROL_COMMAND_MI_XML);
749 for (String string : strings) {
750 command.add(checkNotNull(string));
751 }
752 return command;
753 }
754
755 /**
756 * @param xmlBaseEvents
757 * a Node list of base xml event element
758 * @param events
759 * list of event generated by the parsing of the xml event
760 * element
761 * @throws ExecutionException
762 * when a raw event is not a complete/valid xml event
763 */
764 private static void getBaseEventInfo(NodeList xmlBaseEvents, List<IBaseEventInfo> events) throws ExecutionException {
765 IBaseEventInfo eventInfo = null;
766 for (int i = 0; i < xmlBaseEvents.getLength(); i++) {
767 NodeList rawInfos = xmlBaseEvents.item(i).getChildNodes();
768 // Search for name
769 if (xmlBaseEvents.item(i).getNodeName().equalsIgnoreCase(MIStrings.EVENT)) {
770 Node rawName = getFirstOf(rawInfos, MIStrings.NAME);
771 if (rawName == null) {
772 throw new ExecutionException(Messages.TraceControl_MiMissingRequiredError);
773 }
774 eventInfo = new BaseEventInfo(rawName.getTextContent());
775
776 // Populate the event
777 for (int j = 0; j < rawInfos.getLength(); j++) {
778 Node infoNode = rawInfos.item(j);
779 switch (infoNode.getNodeName()) {
780 case MIStrings.TYPE:
781 eventInfo.setEventType(infoNode.getTextContent());
782 break;
783 case MIStrings.LOGLEVEL:
784 eventInfo.setLogLevel(infoNode.getTextContent());
785 break;
786 case MIStrings.EVENT_FIELDS:
787 List<IFieldInfo> fields = new ArrayList<>();
788 getFieldInfo(infoNode.getChildNodes(), fields);
789 eventInfo.setFields(fields);
790 break;
791 default:
792 break;
793 }
794 }
795 events.add(eventInfo);
796 }
797 }
798 }
799
800 /**
801 * @param xmlBaseEvents
802 * a Node list of xml event element linked to a session
803 * @param events
804 * list of event generated by the parsing of the xml event
805 * element
806 * @throws ExecutionException
807 * when a raw event is not a complete/valid xml event
808 */
809 static void getEventInfo(NodeList xmlEvents, List<IEventInfo> events) throws ExecutionException {
810 IEventInfo eventInfo = null;
811 for (int i = 0; i < xmlEvents.getLength(); i++) {
812 NodeList rawInfos = xmlEvents.item(i).getChildNodes();
813 // Search for name
814 if (xmlEvents.item(i).getNodeName().equalsIgnoreCase(MIStrings.EVENT)) {
815 Node rawName = getFirstOf(rawInfos, MIStrings.NAME);
816 if (rawName == null) {
817 throw new ExecutionException(Messages.TraceControl_MiMissingRequiredError);
818 }
819
820 eventInfo = new EventInfo(rawName.getTextContent());
821
822 // Basic information
823 for (int j = 0; j < rawInfos.getLength(); j++) {
824 Node infoNode = rawInfos.item(j);
825 switch (infoNode.getNodeName()) {
826 case MIStrings.TYPE:
827 eventInfo.setEventType(infoNode.getTextContent());
828 break;
829 case MIStrings.LOGLEVEL_TYPE:
830 eventInfo.setLogLevelType(LogLevelType.valueOfString(infoNode.getTextContent()));
831 break;
832 case MIStrings.LOGLEVEL:
833 eventInfo.setLogLevel(TraceLogLevel.valueOfString(infoNode.getTextContent()));
834 break;
835 case MIStrings.ENABLED:
836 eventInfo.setState(TraceEnablement.valueOfString(infoNode.getTextContent()));
837 break;
838 case MIStrings.FILTER:
839 // TODO
840 // See bug 334 http://bugs.lttng.org/issues/334 from
841 // LTTng
842 // For now we emulate the non-mi behavior and simply put
843 // "with filter"
844 eventInfo.setFilterExpression("with filter"); //$NON-NLS-1$
845 break;
846 case MIStrings.EXCLUSION:
847 // TODO: Currently not supported by tmf
848 // ExclusionS element is ignored
849 break;
850 default:
851 break;
852 }
853 }
854
855 boolean isProbeFunction = (eventInfo.getEventType().equals(TraceEventType.PROBE)) || (eventInfo.getEventType().equals(TraceEventType.FUNCTION));
856 if (isProbeFunction) {
857 IProbeEventInfo probeEvent = new ProbeEventInfo(eventInfo);
858 eventInfo = probeEvent;
859
860 Node rawDataNode = null;
861 switch (probeEvent.getEventType()) {
862 case FUNCTION:
863 case PROBE: {
864 // get attributes
865 Node rawAttributes = getFirstOf(rawInfos, MIStrings.ATTRIBUTES);
866 if (rawAttributes == null) {
867 throw new ExecutionException(Messages.TraceControl_MiMissingRequiredError);
868 }
869 rawDataNode = getFirstOf(rawAttributes.getChildNodes(), MIStrings.PROBE_ATTRIBUTES);
870 break;
871 }
872 case SYSCALL:
873 case TRACEPOINT:
874 case UNKNOWN:
875 default:
876 throw new ExecutionException(Messages.TraceControl_MiInvalidElementError);
877 }
878
879 if (rawDataNode == null) {
880 throw new ExecutionException(Messages.TraceControl_MiInvalidElementError);
881 }
882
883 // Extract info
884 NodeList rawDatas = rawDataNode.getChildNodes();
885 for (int j = 0; j < rawDatas.getLength(); j++) {
886 Node rawData = rawDatas.item(j);
887 switch (rawData.getNodeName()) {
888 case MIStrings.SYMBOL_NAME:
889 probeEvent.setSymbol(rawData.getTextContent());
890 break;
891 case MIStrings.ADDRESS:
892 probeEvent.setAddress(String.format("%#016x", new BigInteger(rawData.getTextContent()))); //$NON-NLS-1$
893 break;
894 case MIStrings.OFFSET:
895 probeEvent.setOffset(String.format("%#016x", new BigInteger(rawData.getTextContent()))); //$NON-NLS-1$
896 break;
897 default:
898 break;
899 }
900 }
901 }
902
903 // Add the event
904 events.add(eventInfo);
905 }
906 }
907 }
908
909 /**
910 * @param fieldsList
911 * a list of xml event_field element
912 * @param fields
913 * a list of field generated by xml parsing
914 * @throws ExecutionException
915 * when parsing fail or required elements are missing
916 */
917 private static void getFieldInfo(NodeList fieldsList, List<IFieldInfo> fields) throws ExecutionException {
918 IFieldInfo fieldInfo = null;
919 for (int i = 0; i < fieldsList.getLength(); i++) {
920 Node field = fieldsList.item(i);
921 if (field.getNodeName().equalsIgnoreCase(MIStrings.EVENT_FIELD)) {
922 // Get name
923 Node name = getFirstOf(field.getChildNodes(), MIStrings.NAME);
924 if (name == null) {
925 throw new ExecutionException(Messages.TraceControl_MiMissingRequiredError);
926 }
927 fieldInfo = new FieldInfo(name.getTextContent());
928
929 // Populate the field information
930 NodeList infos = field.getChildNodes();
931 for (int j = 0; j < infos.getLength(); j++) {
932 Node info = infos.item(j);
933 switch (info.getNodeName()) {
934 case MIStrings.TYPE:
935 fieldInfo.setFieldType(info.getTextContent());
936 break;
937 default:
938 break;
939 }
940 }
941 fields.add(fieldInfo);
942 }
943 }
944 }
945
946 /**
947 * Retrieve the fist instance of a given node with tag name equal to tagName
948 * parameter
949 *
950 * @param nodeList
951 * the list of Node to search against
952 * @param tagName
953 * the tag name of the desired node
954 * @return the first occurrence of a node with a tag name equals to tagName
955 */
956 private static @Nullable Node getFirstOf(NodeList nodeList, String tagName) {
957 Node node = null;
958 for (int i = 0; i < nodeList.getLength(); i++) {
959 if (NonNullUtils.equalsNullable(nodeList.item(i).getNodeName(), tagName)) {
960 node = nodeList.item(i);
961 break;
962 }
963 }
964 return node;
965 }
966
967 }
This page took 0.052854 seconds and 4 git commands to generate.