1 /**********************************************************************
2 * Copyright (c) 2014, 2015 Ericsson
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
10 * Jonathan Rajotte - Initial support for machine interface lttng 2.6
11 * Bernd Hufmann - Fix check for live session
12 **********************************************************************/
14 package org
.eclipse
.tracecompass
.internal
.lttng2
.control
.ui
.views
.service
;
16 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
18 import java
.io
.IOException
;
19 import java
.io
.StringReader
;
20 import java
.math
.BigInteger
;
22 import java
.util
.ArrayList
;
23 import java
.util
.List
;
24 import java
.util
.regex
.Matcher
;
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
;
32 import org
.eclipse
.core
.commands
.ExecutionException
;
33 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
34 import org
.eclipse
.core
.runtime
.Platform
;
35 import org
.eclipse
.jdt
.annotation
.NonNull
;
36 import org
.eclipse
.jdt
.annotation
.Nullable
;
37 import org
.eclipse
.osgi
.util
.NLS
;
38 import org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
;
39 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.IBaseEventInfo
;
40 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.IChannelInfo
;
41 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.IDomainInfo
;
42 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.IEventInfo
;
43 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.IFieldInfo
;
44 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.IProbeEventInfo
;
45 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.ISessionInfo
;
46 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.ISnapshotInfo
;
47 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.IUstProviderInfo
;
48 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.LogLevelType
;
49 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.TraceDomainType
;
50 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.TraceEnablement
;
51 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.TraceEventType
;
52 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.TraceLogLevel
;
53 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.BaseEventInfo
;
54 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.BufferType
;
55 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.ChannelInfo
;
56 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.DomainInfo
;
57 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.EventInfo
;
58 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.FieldInfo
;
59 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.ProbeEventInfo
;
60 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.SessionInfo
;
61 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.SnapshotInfo
;
62 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.UstProviderInfo
;
63 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.ui
.Activator
;
64 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.ui
.views
.handlers
.XmlMiValidationErrorHandler
;
65 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.ui
.views
.messages
.Messages
;
66 import org
.eclipse
.tracecompass
.tmf
.remote
.core
.shell
.ICommandInput
;
67 import org
.eclipse
.tracecompass
.tmf
.remote
.core
.shell
.ICommandResult
;
68 import org
.eclipse
.tracecompass
.tmf
.remote
.core
.shell
.ICommandShell
;
69 import org
.w3c
.dom
.Document
;
70 import org
.w3c
.dom
.Node
;
71 import org
.w3c
.dom
.NodeList
;
72 import org
.xml
.sax
.InputSource
;
73 import org
.xml
.sax
.SAXException
;
76 * Service for sending LTTng trace control commands to remote host via machine
79 * @author Jonathan Rajotte
81 public class LTTngControlServiceMI
extends LTTngControlService
{
84 * The tracing key (.options) and System property to control whether or not schema validation should be used.
86 public static final String MI_SCHEMA_VALIDATION_KEY
= Activator
.PLUGIN_ID
+ "/mi/schema-validation"; //$NON-NLS-1$
88 // ------------------------------------------------------------------------
90 // ------------------------------------------------------------------------
92 private final DocumentBuilder fDocumentBuilder
;
94 // ------------------------------------------------------------------------
96 // ------------------------------------------------------------------------
102 * the command shell implementation to use
104 * the xsd schema file for validation
105 * @throws ExecutionException
106 * if the creation of the Schema and DocumentBuilder objects
109 public LTTngControlServiceMI(@NonNull ICommandShell shell
, @Nullable URL xsdUrl
) throws ExecutionException
{
112 DocumentBuilderFactory docBuilderFactory
= DocumentBuilderFactory
.newInstance();
113 docBuilderFactory
.setValidating(false);
115 if (isSchemaValidationEnabled()) {
116 // Validate XSD schema
117 if (xsdUrl
!= null) {
118 SchemaFactory schemaFactory
= SchemaFactory
.newInstance(XMLConstants
.W3C_XML_SCHEMA_NS_URI
);
120 docBuilderFactory
.setSchema(schemaFactory
.newSchema(xsdUrl
));
121 } catch (SAXException e
) {
122 throw new ExecutionException(Messages
.TraceControl_InvalidSchemaError
, e
);
128 fDocumentBuilder
= docBuilderFactory
.newDocumentBuilder();
129 } catch (ParserConfigurationException e
) {
130 throw new ExecutionException(Messages
.TraceControl_XmlDocumentBuilderError
, e
);
133 fDocumentBuilder
.setErrorHandler(new XmlMiValidationErrorHandler());
137 private static boolean isSchemaValidationEnabled() {
138 String schemaValidationKey
= Platform
.getDebugOption(MI_SCHEMA_VALIDATION_KEY
);
139 String systemProperty
= System
.getProperty(MI_SCHEMA_VALIDATION_KEY
);
140 return schemaValidationKey
!= null && Boolean
.parseBoolean(schemaValidationKey
) || systemProperty
!= null && Boolean
.parseBoolean(systemProperty
);
144 * Generate a Document object from an list of Strings.
147 * list of strings representing an xml input
148 * @return Document generated from strings input
149 * @throws ExecutionException
150 * when parsing has failed
152 private Document
getDocumentFromStrings(List
<String
> xmlStrings
) throws ExecutionException
{
153 StringBuilder concatenedString
= new StringBuilder();
154 for (String string
: xmlStrings
) {
155 concatenedString
.append(string
);
157 InputSource stream
= new InputSource(new StringReader(concatenedString
.toString()));
161 document
= fDocumentBuilder
.parse(stream
);
162 } catch (SAXException
| IOException e
) {
163 throw new ExecutionException(Messages
.TraceControl_XmlParsingError
+ ':' + e
.toString(), e
);
170 * Parse, populate and set the internal LTTngVersion variable
173 * the mi xml output of lttng version
174 * @throws ExecutionException
175 * when xml extraction fail
177 public void setVersion(List
<String
> xmlOutput
) throws ExecutionException
{
178 Document doc
= getDocumentFromStrings(xmlOutput
);
179 NodeList element
= doc
.getElementsByTagName(MIStrings
.VERSION
);
183 String license
= ""; //$NON-NLS-1$
184 String commit
= ""; //$NON-NLS-1$
185 String name
= ""; //$NON-NLS-1$
186 String description
= ""; //$NON-NLS-1$
187 String url
= ""; //$NON-NLS-1$
188 String fullVersion
= ""; //$NON-NLS-1$
189 if (element
.getLength() == 1) {
190 NodeList child
= element
.item(0).getChildNodes();
191 // Get basic information
192 for (int i
= 0; i
< child
.getLength(); i
++) {
193 Node node
= child
.item(i
);
194 switch (node
.getNodeName()) {
195 case MIStrings
.VERSION_MAJOR
:
196 major
= Integer
.parseInt(node
.getTextContent());
198 case MIStrings
.VERSION_MINOR
:
199 minor
= Integer
.parseInt(node
.getTextContent());
201 case MIStrings
.VERSION_PATCH_LEVEL
:
202 patchLevel
= Integer
.parseInt(node
.getTextContent());
204 case MIStrings
.VERSION_COMMIT
:
205 commit
= node
.getTextContent();
207 case MIStrings
.VERSION_DESCRIPTION
:
208 description
= node
.getTextContent();
210 case MIStrings
.VERSION_LICENSE
:
211 license
= node
.getTextContent();
213 case MIStrings
.VERSION_NAME
:
214 name
= node
.getTextContent();
216 case MIStrings
.VERSION_STR
:
217 fullVersion
= node
.getTextContent();
219 case MIStrings
.VERSION_WEB
:
220 url
= node
.getTextContent();
226 setVersion(new LttngVersion(major
, minor
, patchLevel
, license
, commit
, name
, description
, url
, fullVersion
));
228 throw new ExecutionException(Messages
.TraceControl_UnsupportedVersionError
);
233 public List
<String
> getSessionNames(IProgressMonitor monitor
) throws ExecutionException
{
234 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
);
235 ICommandResult result
= executeCommand(command
, monitor
);
237 Document doc
= getDocumentFromStrings(result
.getOutput());
239 NodeList elements
= doc
.getElementsByTagName(MIStrings
.NAME
);
241 ArrayList
<String
> retArray
= new ArrayList
<>();
242 for (int i
= 0; i
< elements
.getLength(); i
++) {
243 Node node
= elements
.item(i
);
244 if (node
.getParentNode().getNodeName().equalsIgnoreCase(MIStrings
.SESSION
)) {
245 retArray
.add(node
.getTextContent());
252 public ISessionInfo
getSession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
253 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
, sessionName
);
254 ICommandResult result
= executeCommand(command
, monitor
);
256 ISessionInfo sessionInfo
= new SessionInfo(sessionName
);
257 Document document
= getDocumentFromStrings(result
.getOutput());
259 NodeList sessionsNode
= document
.getElementsByTagName(MIStrings
.SESSION
);
260 // There should be only one session
261 if (sessionsNode
.getLength() != 1) {
262 throw new ExecutionException(NLS
.bind(Messages
.TraceControl_MiInvalidNumberOfElementError
, MIStrings
.SESSION
));
265 // Populate session information
266 Node rawSession
= sessionsNode
.item(0);
267 parseSession(sessionInfo
, rawSession
);
269 // Fetch the snapshot info
270 if (sessionInfo
.isSnapshotSession()) {
271 ISnapshotInfo snapshot
= getSnapshotInfo(sessionName
, monitor
);
272 sessionInfo
.setSnapshotInfo(snapshot
);
281 * @throws ExecutionException
283 private void parseSession(ISessionInfo sessionInfo
, Node rawSession
) throws ExecutionException
{
284 if (!rawSession
.getNodeName().equalsIgnoreCase(MIStrings
.SESSION
)) {
285 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
287 NodeList rawSessionInfos
= rawSession
.getChildNodes();
288 for (int i
= 0; i
< rawSessionInfos
.getLength(); i
++) {
289 Node rawInfo
= rawSessionInfos
.item(i
);
290 switch (rawInfo
.getNodeName()) {
292 sessionInfo
.setName(rawInfo
.getTextContent());
295 sessionInfo
.setSessionPath(rawInfo
.getTextContent());
297 case MIStrings
.ENABLED
:
298 sessionInfo
.setSessionState(rawInfo
.getTextContent());
300 case MIStrings
.SNAPSHOT_MODE
:
301 if (rawInfo
.getTextContent().equals(LTTngControlServiceConstants
.TRUE_NUMERICAL
)) {
302 // real name will be set later
303 ISnapshotInfo snapshotInfo
= new SnapshotInfo(""); //$NON-NLS-1$
304 sessionInfo
.setSnapshotInfo(snapshotInfo
);
307 case MIStrings
.LIVE_TIMER_INTERVAL
:
308 long liveDelay
= Long
.parseLong(rawInfo
.getTextContent());
309 if ((liveDelay
> 0 && (liveDelay
<= LTTngControlServiceConstants
.MAX_LIVE_TIMER_INTERVAL
))) {
310 sessionInfo
.setLive(true);
311 sessionInfo
.setLiveUrl(SessionInfo
.DEFAULT_LIVE_NETWORK_URL
);
312 sessionInfo
.setLivePort(SessionInfo
.DEFAULT_LIVE_PORT
);
313 sessionInfo
.setLiveDelay(liveDelay
);
316 case MIStrings
.DOMAINS
:
317 // Extract the domains node
318 NodeList rawDomains
= rawInfo
.getChildNodes();
319 IDomainInfo domain
= null;
320 for (int j
= 0; j
< rawDomains
.getLength(); j
++) {
321 if (rawDomains
.item(j
).getNodeName().equalsIgnoreCase(MIStrings
.DOMAIN
)) {
322 domain
= parseDomain(rawDomains
.item(j
));
323 sessionInfo
.addDomain(domain
);
332 if (!sessionInfo
.isSnapshotSession()) {
333 Matcher matcher
= LTTngControlServiceConstants
.TRACE_NETWORK_PATTERN
.matcher(sessionInfo
.getSessionPath());
334 if (matcher
.matches()) {
335 sessionInfo
.setStreamedTrace(true);
341 * Parse a raw domain XML node to a IDomainInfo object
345 * @return a populated {@link DomainInfo} object
346 * @throws ExecutionException
347 * when missing required xml element (type)
349 protected IDomainInfo
parseDomain(Node rawDomain
) throws ExecutionException
{
350 IDomainInfo domain
= null;
352 Node rawType
= getFirstOf(rawDomain
.getChildNodes(), MIStrings
.TYPE
);
353 if (rawType
== null) {
354 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
356 String rawTypeString
= rawType
.getTextContent().toLowerCase();
357 TraceDomainType domainType
= TraceDomainType
.valueOfString(rawTypeString
);
358 switch (domainType
) {
360 domain
= new DomainInfo(Messages
.TraceControl_KernelProviderDisplayName
);
361 domain
.setIsKernel(true);
364 domain
= new DomainInfo(Messages
.TraceControl_UstGlobalDomainDisplayName
);
365 domain
.setIsKernel(false);
369 * TODO: Support for JUL JUL substructure and semantic is not the
370 * same as a regular UST or Kernel Domain There is no channel under
371 * JUL domain only events. The channel is activated in UST Channel
373 domain
= new DomainInfo(Messages
.TraceControl_JULDomainDisplayName
);
374 domain
.setIsKernel(false);
377 domain
= new DomainInfo(Messages
.TraceControl_UnknownDomainDisplayName
);
378 domain
.setIsKernel(false);
381 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
384 NodeList rawInfos
= rawDomain
.getChildNodes();
385 for (int i
= 0; i
< rawInfos
.getLength(); i
++) {
386 Node rawInfo
= rawInfos
.item(i
);
387 switch (rawInfo
.getNodeName()) {
388 case MIStrings
.BUFFER_TYPE
:
389 BufferType bufferType
= BufferType
.valueOfString(rawInfo
.getTextContent());
390 domain
.setBufferType(bufferType
);
392 case MIStrings
.CHANNELS
:
393 ArrayList
<IChannelInfo
> channels
= new ArrayList
<>();
394 parseChannels(rawInfo
.getChildNodes(), channels
);
395 if (channels
.size() > 0) {
396 domain
.setChannels(channels
);
408 * Parse a list of raw channel XML node into an ArrayList of IChannelInfo
411 * List of raw channel XML node
413 * the parsed channels list
414 * @throws ExecutionException
415 * when missing required xml element (type)
417 private static void parseChannels(NodeList rawChannels
, ArrayList
<IChannelInfo
> channels
) throws ExecutionException
{
418 IChannelInfo channel
= null;
419 for (int i
= 0; i
< rawChannels
.getLength(); i
++) {
420 Node rawChannel
= rawChannels
.item(i
);
421 if (rawChannel
.getNodeName().equalsIgnoreCase(MIStrings
.CHANNEL
)) {
422 channel
= new ChannelInfo(""); //$NON-NLS-1$
424 // Populate the channel
425 NodeList rawInfos
= rawChannel
.getChildNodes();
427 for (int j
= 0; j
< rawInfos
.getLength(); j
++) {
428 rawInfo
= rawInfos
.item(j
);
429 switch (rawInfo
.getNodeName()) {
431 channel
.setName(rawInfo
.getTextContent());
433 case MIStrings
.ENABLED
:
434 channel
.setState(TraceEnablement
.valueOfString(rawInfo
.getTextContent()));
436 case MIStrings
.EVENTS
:
437 List
<IEventInfo
> events
= new ArrayList
<>();
438 getEventInfo(rawInfo
.getChildNodes(), events
);
439 channel
.setEvents(events
);
441 case MIStrings
.ATTRIBUTES
:
442 NodeList rawAttributes
= rawInfo
.getChildNodes();
443 for (int k
= 0; k
< rawAttributes
.getLength(); k
++) {
444 Node attribute
= rawAttributes
.item(k
);
445 switch (attribute
.getNodeName()) {
446 case MIStrings
.OVERWRITE_MODE
:
447 channel
.setOverwriteMode(!LTTngControlServiceConstants
.OVERWRITE_MODE_ATTRIBUTE_FALSE_MI
.equalsIgnoreCase(attribute
.getTextContent()));
449 case MIStrings
.SUBBUF_SIZE
:
450 channel
.setSubBufferSize(Long
.valueOf(attribute
.getTextContent()));
452 case MIStrings
.NUM_SUBBUF
:
453 channel
.setNumberOfSubBuffers(Integer
.valueOf(attribute
.getTextContent()));
455 case MIStrings
.SWITCH_TIMER_INTERVAL
:
456 channel
.setSwitchTimer(Long
.valueOf(attribute
.getTextContent()));
458 case MIStrings
.READ_TIMER_INTERVAL
:
459 channel
.setReadTimer(Long
.valueOf(attribute
.getTextContent()));
461 case MIStrings
.OUTPUT_TYPE
:
462 channel
.setOutputType(attribute
.getTextContent());
464 case MIStrings
.TRACEFILE_SIZE
:
465 channel
.setMaxSizeTraceFiles(Long
.parseLong(attribute
.getTextContent()));
467 case MIStrings
.TRACEFILE_COUNT
:
468 channel
.setMaxNumberTraceFiles(Integer
.parseInt(attribute
.getTextContent()));
470 case MIStrings
.LIVE_TIMER_INTERVAL
:
471 // TODO: currently not supported by tmf
482 channels
.add(channel
);
489 public ISnapshotInfo
getSnapshotInfo(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
490 // TODO A session can have multiple snapshot output. This need to be
491 // supported in the future.
492 // Currently the SessionInfo object does not support multiple snashot
494 // For now only keep the last one.
495 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_SNAPSHOT
, LTTngControlServiceConstants
.COMMAND_LIST_SNAPSHOT_OUTPUT
, LTTngControlServiceConstants
.OPTION_SESSION
, sessionName
);
496 ICommandResult result
= executeCommand(command
, monitor
);
497 Document doc
= getDocumentFromStrings(result
.getOutput());
498 NodeList rawSnapshotsOutputs
= doc
.getElementsByTagName(MIStrings
.SNAPSHOT_OUTPUTS
);
500 ISnapshotInfo snapshotInfo
= new SnapshotInfo(""); //$NON-NLS-1$
502 // TODO: tmf does not have a notion of a ctrl url.
503 for (int i
= 0; i
< rawSnapshotsOutputs
.getLength(); i
++) {
504 NodeList rawSnapshotOutput
= rawSnapshotsOutputs
.item(i
).getChildNodes();
505 for (int j
= 0; j
< rawSnapshotOutput
.getLength(); j
++) {
506 Node rawInfo
= rawSnapshotOutput
.item(j
);
507 switch (rawInfo
.getNodeName()) {
509 snapshotInfo
.setId(Integer
.parseInt(rawInfo
.getTextContent()));
512 snapshotInfo
.setName(rawInfo
.getTextContent());
514 case MIStrings
.SNAPSHOT_CTRL_URL
:
515 // The use of the ctrl_url for the snapshot path is to assure
516 // basic support. Refactoring is necessary in lttng and
518 // See http://bugs.lttng.org/issues/828 (+comment)
519 snapshotInfo
.setSnapshotPath(rawInfo
.getTextContent());
527 // Check if the snapshot output is Streamed
528 Matcher matcher2
= LTTngControlServiceConstants
.TRACE_NETWORK_PATTERN
.matcher(snapshotInfo
.getSnapshotPath());
529 if (matcher2
.matches()) {
530 snapshotInfo
.setStreamedSnapshot(true);
537 public List
<IBaseEventInfo
> getKernelProvider(IProgressMonitor monitor
) throws ExecutionException
{
538 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
, LTTngControlServiceConstants
.OPTION_KERNEL
);
539 ICommandResult result
= executeCommand(command
, monitor
, false);
540 List
<IBaseEventInfo
> events
= new ArrayList
<>();
542 if (isError(result
)) {
543 // Ignore the following 2 cases:
544 // Spawning a session daemon
545 // Error: Unable to list kernel events
547 // Error: Unable to list kernel events
548 if (ignoredPattern(result
.getErrorOutput(), LTTngControlServiceConstants
.LIST_KERNEL_NO_KERNEL_PROVIDER_PATTERN
)) {
551 throw new ExecutionException(Messages
.TraceControl_CommandError
+ command
.toString());
554 Document document
= getDocumentFromStrings(result
.getOutput());
555 NodeList rawEvents
= document
.getElementsByTagName(MIStrings
.EVENT
);
556 getBaseEventInfo(rawEvents
, events
);
561 public List
<IUstProviderInfo
> getUstProvider(IProgressMonitor monitor
) throws ExecutionException
{
562 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
, LTTngControlServiceConstants
.OPTION_UST
);
564 command
.add(LTTngControlServiceConstants
.OPTION_FIELDS
);
567 ICommandResult result
= executeCommand(command
, monitor
, false);
568 List
<IUstProviderInfo
> allProviders
= new ArrayList
<>();
570 if (isError(result
)) {
571 // Ignore the following 2 cases:
572 // Spawning a session daemon
573 // Error: Unable to list UST events: Listing UST events failed
575 // Error: Unable to list UST events: Listing UST events failed
576 if (ignoredPattern(result
.getErrorOutput(), LTTngControlServiceConstants
.LIST_UST_NO_UST_PROVIDER_PATTERN
)) {
579 throw new ExecutionException(Messages
.TraceControl_CommandError
+ command
.toString());
582 Document document
= getDocumentFromStrings(result
.getOutput());
583 NodeList rawProviders
= document
.getElementsByTagName(MIStrings
.PID
);
585 IUstProviderInfo providerInfo
= null;
587 for (int i
= 0; i
< rawProviders
.getLength(); i
++) {
588 Node provider
= rawProviders
.item(i
);
589 Node name
= getFirstOf(provider
.getChildNodes(), MIStrings
.NAME
);
591 throw new ExecutionException(Messages
.TraceControl_MiInvalidProviderError
);
593 providerInfo
= new UstProviderInfo(name
.getTextContent());
596 NodeList infos
= provider
.getChildNodes();
597 for (int j
= 0; j
< infos
.getLength(); j
++) {
598 Node info
= infos
.item(j
);
599 switch (info
.getNodeName()) {
600 case MIStrings
.PID_ID
:
601 providerInfo
.setPid(Integer
.parseInt(info
.getTextContent()));
603 case MIStrings
.EVENTS
:
604 List
<IBaseEventInfo
> events
= new ArrayList
<>();
605 NodeList rawEvents
= info
.getChildNodes();
606 getBaseEventInfo(rawEvents
, events
);
607 providerInfo
.setEvents(events
);
613 allProviders
.add(providerInfo
);
620 public ISessionInfo
createSession(ISessionInfo sessionInfo
, IProgressMonitor monitor
) throws ExecutionException
{
621 if (sessionInfo
.isStreamedTrace()) {
622 return createStreamedSession(sessionInfo
, monitor
);
625 ICommandInput command
= prepareSessionCreationCommand(sessionInfo
);
626 ICommandResult result
= executeCommand(command
, monitor
);
628 Document document
= getDocumentFromStrings(result
.getOutput());
629 NodeList sessions
= document
.getElementsByTagName(MIStrings
.SESSION
);
631 // Number of session should be equal to 1
632 if (sessions
.getLength() != 1) {
633 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" //$NON-NLS-1$//$NON-NLS-2$
634 + NLS
.bind(Messages
.TraceControl_UnexpectedNumberOfElementError
, MIStrings
.SESSION
) + " " + sessions
.getLength()); //$NON-NLS-1$
637 // Fetch a session from output
638 ISessionInfo outputSession
= new SessionInfo(""); //$NON-NLS-1$
639 parseSession(outputSession
, sessions
.item(0));
641 // Verify session name
642 if ((outputSession
.getName().equals("")) || (!"".equals(sessionInfo
.getName()) && !outputSession
.getName().equals(sessionInfo
.getName()))) { //$NON-NLS-1$ //$NON-NLS-2$
643 // Unexpected name returned
644 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + //$NON-NLS-1$ //$NON-NLS-2$
645 Messages
.TraceControl_UnexpectedNameError
+ ": " + outputSession
.getName()); //$NON-NLS-1$
648 // Verify session path
649 if (!sessionInfo
.isSnapshotSession() &&
650 ((outputSession
.getSessionPath() == null) || ((sessionInfo
.getSessionPath() != null) && (!outputSession
.getSessionPath().contains(sessionInfo
.getSessionPath()))))) {
652 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + //$NON-NLS-1$ //$NON-NLS-2$
653 Messages
.TraceControl_UnexpectedPathError
+ ": " + outputSession
.getName()); //$NON-NLS-1$
656 if (sessionInfo
.isSnapshotSession()) {
657 // Make it a snapshot session - content of snapshot info need to
658 // set afterwards using getSession() or getSnapshotInfo()
659 outputSession
.setSnapshotInfo(new SnapshotInfo("")); //$NON-NLS-1$
662 return outputSession
;
665 private @NonNull ISessionInfo
createStreamedSession(ISessionInfo sessionInfo
, IProgressMonitor monitor
) throws ExecutionException
{
667 ICommandInput command
= prepareStreamedSessionCreationCommand(sessionInfo
);
669 ICommandResult result
= executeCommand(command
, monitor
);
671 Document document
= getDocumentFromStrings(result
.getOutput());
672 NodeList sessions
= document
.getElementsByTagName(MIStrings
.SESSION
);
674 // Number of session should be equal to 1
675 if (sessions
.getLength() != 1) {
676 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" //$NON-NLS-1$//$NON-NLS-2$
677 + NLS
.bind(Messages
.TraceControl_UnexpectedNumberOfElementError
, MIStrings
.SESSION
) + " " + sessions
.getLength()); //$NON-NLS-1$
680 // Fetch a session from output
681 ISessionInfo outputSession
= new SessionInfo(""); //$NON-NLS-1$
682 parseSession(outputSession
, sessions
.item(0));
684 // Verify session name
685 if ((outputSession
.getName().equals("")) || (!"".equals(sessionInfo
.getName()) && !outputSession
.getName().equals(sessionInfo
.getName()))) { //$NON-NLS-1$ //$NON-NLS-2$
686 // Unexpected name returned
687 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + //$NON-NLS-1$ //$NON-NLS-2$
688 Messages
.TraceControl_UnexpectedNameError
+ ": " + outputSession
.getName()); //$NON-NLS-1$
691 sessionInfo
.setName(outputSession
.getName());
692 sessionInfo
.setStreamedTrace(true);
694 // Verify session path
695 if (sessionInfo
.getNetworkUrl() != null) {
696 if (!sessionInfo
.isSnapshotSession() && (outputSession
.getSessionPath() == null)) {
698 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + //$NON-NLS-1$ //$NON-NLS-2$
699 Messages
.TraceControl_UnexpectedPathError
+ ": " + outputSession
.getName()); //$NON-NLS-1$
702 if (sessionInfo
.isSnapshotSession()) {
703 sessionInfo
.setStreamedTrace(false);
705 sessionInfo
.setSessionPath(outputSession
.getSessionPath());
706 // Check file protocol
707 Matcher matcher
= LTTngControlServiceConstants
.TRACE_FILE_PROTOCOL_PATTERN
.matcher(outputSession
.getSessionPath());
708 if (matcher
.matches()) {
709 sessionInfo
.setStreamedTrace(false);
714 // When using controlUrl and dataUrl the full session path is not known
716 // and will be set later on when listing the session
721 public void destroySession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
722 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_DESTROY_SESSION
, sessionName
);
724 ICommandResult result
= executeCommand(command
, monitor
, false);
725 List
<String
> errorOutput
= result
.getErrorOutput();
727 if (isError(result
)) {
728 // Don't treat this as an error
729 if (ignoredPattern(errorOutput
, LTTngControlServiceConstants
.SESSION_NOT_FOUND_ERROR_PATTERN
)) {
733 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
.toString() + "\n" + result
.toString()); //$NON-NLS-1$ //$NON-NLS-2$
736 // Check for action effect
737 Document doc
= getDocumentFromStrings(result
.getOutput());
738 NodeList sessions
= doc
.getElementsByTagName(MIStrings
.SESSION
);
739 if (sessions
.getLength() != 1) {
740 throw new ExecutionException(NLS
.bind(Messages
.TraceControl_MiInvalidNumberOfElementError
, MIStrings
.SESSION
));
743 Node rawSessionName
= getFirstOf(sessions
.item(0).getChildNodes(), MIStrings
.NAME
);
744 if (rawSessionName
== null) {
745 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
749 if (!rawSessionName
.getTextContent().equals(sessionName
)) {
750 throw new ExecutionException(NLS
.bind(Messages
.TraceControl_UnexpectedValueError
, rawSessionName
.getTextContent(), sessionName
));
755 protected ICommandInput
createCommand(String
... strings
) {
756 ICommandInput command
= getCommandShell().createCommand();
757 command
.add(LTTngControlServiceConstants
.CONTROL_COMMAND
);
758 List
<@NonNull String
> groupOption
= getTracingGroupOption();
759 if (!groupOption
.isEmpty()) {
760 command
.addAll(groupOption
);
762 command
.add(LTTngControlServiceConstants
.CONTROL_COMMAND_MI_OPTION
);
763 command
.add(LTTngControlServiceConstants
.CONTROL_COMMAND_MI_XML
);
764 for (String string
: strings
) {
765 command
.add(checkNotNull(string
));
771 * @param xmlBaseEvents
772 * a Node list of base xml event element
774 * list of event generated by the parsing of the xml event
776 * @throws ExecutionException
777 * when a raw event is not a complete/valid xml event
779 private static void getBaseEventInfo(NodeList xmlBaseEvents
, List
<IBaseEventInfo
> events
) throws ExecutionException
{
780 IBaseEventInfo eventInfo
= null;
781 for (int i
= 0; i
< xmlBaseEvents
.getLength(); i
++) {
782 NodeList rawInfos
= xmlBaseEvents
.item(i
).getChildNodes();
784 if (xmlBaseEvents
.item(i
).getNodeName().equalsIgnoreCase(MIStrings
.EVENT
)) {
785 Node rawName
= getFirstOf(rawInfos
, MIStrings
.NAME
);
786 if (rawName
== null) {
787 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
789 eventInfo
= new BaseEventInfo(rawName
.getTextContent());
791 // Populate the event
792 for (int j
= 0; j
< rawInfos
.getLength(); j
++) {
793 Node infoNode
= rawInfos
.item(j
);
794 switch (infoNode
.getNodeName()) {
796 eventInfo
.setEventType(infoNode
.getTextContent());
798 case MIStrings
.LOGLEVEL
:
799 eventInfo
.setLogLevel(infoNode
.getTextContent());
801 case MIStrings
.EVENT_FIELDS
:
802 List
<IFieldInfo
> fields
= new ArrayList
<>();
803 getFieldInfo(infoNode
.getChildNodes(), fields
);
804 eventInfo
.setFields(fields
);
810 events
.add(eventInfo
);
816 * @param xmlBaseEvents
817 * a Node list of xml event element linked to a session
819 * list of event generated by the parsing of the xml event
821 * @throws ExecutionException
822 * when a raw event is not a complete/valid xml event
824 static void getEventInfo(NodeList xmlEvents
, List
<IEventInfo
> events
) throws ExecutionException
{
825 IEventInfo eventInfo
= null;
826 for (int i
= 0; i
< xmlEvents
.getLength(); i
++) {
827 NodeList rawInfos
= xmlEvents
.item(i
).getChildNodes();
829 if (xmlEvents
.item(i
).getNodeName().equalsIgnoreCase(MIStrings
.EVENT
)) {
830 Node rawName
= getFirstOf(rawInfos
, MIStrings
.NAME
);
831 if (rawName
== null) {
832 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
835 eventInfo
= new EventInfo(rawName
.getTextContent());
838 for (int j
= 0; j
< rawInfos
.getLength(); j
++) {
839 Node infoNode
= rawInfos
.item(j
);
840 switch (infoNode
.getNodeName()) {
842 eventInfo
.setEventType(infoNode
.getTextContent());
844 case MIStrings
.LOGLEVEL_TYPE
:
845 eventInfo
.setLogLevelType(LogLevelType
.valueOfString(infoNode
.getTextContent()));
847 case MIStrings
.LOGLEVEL
:
848 eventInfo
.setLogLevel(TraceLogLevel
.valueOfString(infoNode
.getTextContent()));
850 case MIStrings
.ENABLED
:
851 eventInfo
.setState(TraceEnablement
.valueOfString(infoNode
.getTextContent()));
853 case MIStrings
.FILTER
:
854 // Before LTTng 2.8: We emulate the non-mi behavior and simply put
856 if (Boolean
.TRUE
.toString().equals(infoNode
.getTextContent())) {
857 eventInfo
.setFilterExpression(Messages
.TraceControl_DefaultEventFilterString
);
860 case MIStrings
.FILTER_EXPRESSION
:
861 eventInfo
.setFilterExpression(infoNode
.getTextContent());
863 case MIStrings
.EXCLUSION
:
864 // TODO: Currently not supported by tmf
865 // ExclusionS element is ignored
872 boolean isProbeFunction
= (eventInfo
.getEventType().equals(TraceEventType
.PROBE
)) || (eventInfo
.getEventType().equals(TraceEventType
.FUNCTION
));
873 if (isProbeFunction
) {
874 IProbeEventInfo probeEvent
= new ProbeEventInfo(eventInfo
);
875 eventInfo
= probeEvent
;
877 Node rawDataNode
= null;
878 switch (probeEvent
.getEventType()) {
882 Node rawAttributes
= getFirstOf(rawInfos
, MIStrings
.ATTRIBUTES
);
883 if (rawAttributes
== null) {
884 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
886 rawDataNode
= getFirstOf(rawAttributes
.getChildNodes(), MIStrings
.PROBE_ATTRIBUTES
);
893 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
896 if (rawDataNode
== null) {
897 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
901 NodeList rawDatas
= rawDataNode
.getChildNodes();
902 for (int j
= 0; j
< rawDatas
.getLength(); j
++) {
903 Node rawData
= rawDatas
.item(j
);
904 switch (rawData
.getNodeName()) {
905 case MIStrings
.SYMBOL_NAME
:
906 probeEvent
.setSymbol(rawData
.getTextContent());
908 case MIStrings
.ADDRESS
:
909 probeEvent
.setAddress(String
.format("%#016x", new BigInteger(rawData
.getTextContent()))); //$NON-NLS-1$
911 case MIStrings
.OFFSET
:
912 probeEvent
.setOffset(String
.format("%#016x", new BigInteger(rawData
.getTextContent()))); //$NON-NLS-1$
921 events
.add(eventInfo
);
928 * a list of xml event_field element
930 * a list of field generated by xml parsing
931 * @throws ExecutionException
932 * when parsing fail or required elements are missing
934 private static void getFieldInfo(NodeList fieldsList
, List
<IFieldInfo
> fields
) throws ExecutionException
{
935 IFieldInfo fieldInfo
= null;
936 for (int i
= 0; i
< fieldsList
.getLength(); i
++) {
937 Node field
= fieldsList
.item(i
);
938 if (field
.getNodeName().equalsIgnoreCase(MIStrings
.EVENT_FIELD
)) {
940 Node name
= getFirstOf(field
.getChildNodes(), MIStrings
.NAME
);
942 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
944 fieldInfo
= new FieldInfo(name
.getTextContent());
946 // Populate the field information
947 NodeList infos
= field
.getChildNodes();
948 for (int j
= 0; j
< infos
.getLength(); j
++) {
949 Node info
= infos
.item(j
);
950 switch (info
.getNodeName()) {
952 fieldInfo
.setFieldType(info
.getTextContent());
958 fields
.add(fieldInfo
);
964 * Retrieve the fist instance of a given node with tag name equal to tagName
968 * the list of Node to search against
970 * the tag name of the desired node
971 * @return the first occurrence of a node with a tag name equals to tagName
973 private static @Nullable Node
getFirstOf(NodeList nodeList
, String tagName
) {
975 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
976 if (NonNullUtils
.equalsNullable(nodeList
.item(i
).getNodeName(), tagName
)) {
977 node
= nodeList
.item(i
);