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
.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
;
74 * Service for sending LTTng trace control commands to remote host via machine
77 * @author Jonathan Rajotte
79 public class LTTngControlServiceMI
extends LTTngControlService
{
81 // ------------------------------------------------------------------------
83 // ------------------------------------------------------------------------
85 private final DocumentBuilder fDocumentBuilder
;
87 // ------------------------------------------------------------------------
89 // ------------------------------------------------------------------------
95 * the command shell implementation to use
97 * the xsd schema file for validation
98 * @throws ExecutionException
99 * if the creation of the Schema and DocumentBuilder objects
102 public LTTngControlServiceMI(@NonNull ICommandShell shell
, @Nullable URL xsdUrl
) throws ExecutionException
{
105 DocumentBuilderFactory docBuilderFactory
= DocumentBuilderFactory
.newInstance();
106 docBuilderFactory
.setValidating(false);
108 // Validate XSD schema
109 if (xsdUrl
!= null) {
110 SchemaFactory schemaFactory
= SchemaFactory
.newInstance(XMLConstants
.W3C_XML_SCHEMA_NS_URI
);
112 docBuilderFactory
.setSchema(schemaFactory
.newSchema(xsdUrl
));
113 } catch (SAXException e
) {
114 throw new ExecutionException(Messages
.TraceControl_InvalidSchemaError
, e
);
119 fDocumentBuilder
= docBuilderFactory
.newDocumentBuilder();
120 } catch (ParserConfigurationException e
) {
121 throw new ExecutionException(Messages
.TraceControl_XmlDocumentBuilderError
, e
);
124 fDocumentBuilder
.setErrorHandler(new XmlMiValidationErrorHandler());
129 * Generate a Document object from an list of Strings.
132 * list of strings representing an xml input
133 * @return Document generated from strings input
134 * @throws ExecutionException
135 * when parsing has failed
137 private Document
getDocumentFromStrings(List
<String
> xmlStrings
) throws ExecutionException
{
138 StringBuilder concatenedString
= new StringBuilder();
139 for (String string
: xmlStrings
) {
140 concatenedString
.append(string
);
142 InputSource stream
= new InputSource(new StringReader(concatenedString
.toString()));
146 document
= fDocumentBuilder
.parse(stream
);
147 } catch (SAXException
| IOException e
) {
148 throw new ExecutionException(Messages
.TraceControl_XmlParsingError
+ ':' + e
.toString(), e
);
155 * Parse, populate and set the internal LTTngVersion variable
158 * the mi xml output of lttng version
159 * @throws ExecutionException
160 * when xml extraction fail
162 public void setVersion(List
<String
> xmlOutput
) throws ExecutionException
{
163 Document doc
= getDocumentFromStrings(xmlOutput
);
164 NodeList element
= doc
.getElementsByTagName(MIStrings
.VERSION
);
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());
183 case MIStrings
.VERSION_MINOR
:
184 minor
= Integer
.parseInt(node
.getTextContent());
186 case MIStrings
.VERSION_PATCH_LEVEL
:
187 patchLevel
= Integer
.parseInt(node
.getTextContent());
189 case MIStrings
.VERSION_COMMIT
:
190 commit
= node
.getTextContent();
192 case MIStrings
.VERSION_DESCRIPTION
:
193 description
= node
.getTextContent();
195 case MIStrings
.VERSION_LICENSE
:
196 license
= node
.getTextContent();
198 case MIStrings
.VERSION_NAME
:
199 name
= node
.getTextContent();
201 case MIStrings
.VERSION_STR
:
202 fullVersion
= node
.getTextContent();
204 case MIStrings
.VERSION_WEB
:
205 url
= node
.getTextContent();
211 setVersion(new LttngVersion(major
, minor
, patchLevel
, license
, commit
, name
, description
, url
, fullVersion
));
213 throw new ExecutionException(Messages
.TraceControl_UnsupportedVersionError
);
218 public List
<String
> getSessionNames(IProgressMonitor monitor
) throws ExecutionException
{
219 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
);
220 ICommandResult result
= executeCommand(command
, monitor
);
222 Document doc
= getDocumentFromStrings(result
.getOutput());
224 NodeList elements
= doc
.getElementsByTagName(MIStrings
.NAME
);
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());
237 public ISessionInfo
getSession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
238 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
, sessionName
);
239 ICommandResult result
= executeCommand(command
, monitor
);
241 ISessionInfo sessionInfo
= new SessionInfo(sessionName
);
242 Document document
= getDocumentFromStrings(result
.getOutput());
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
));
250 // Populate session information
251 Node rawSession
= sessionsNode
.item(0);
252 parseSession(sessionInfo
, rawSession
);
254 // Fetch the snapshot info
255 if (sessionInfo
.isSnapshotSession()) {
256 ISnapshotInfo snapshot
= getSnapshotInfo(sessionName
, monitor
);
257 sessionInfo
.setSnapshotInfo(snapshot
);
266 * @throws ExecutionException
268 private void parseSession(ISessionInfo sessionInfo
, Node rawSession
) throws ExecutionException
{
269 if (!rawSession
.getNodeName().equalsIgnoreCase(MIStrings
.SESSION
)) {
270 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
272 NodeList rawSessionInfos
= rawSession
.getChildNodes();
273 for (int i
= 0; i
< rawSessionInfos
.getLength(); i
++) {
274 Node rawInfo
= rawSessionInfos
.item(i
);
275 switch (rawInfo
.getNodeName()) {
277 sessionInfo
.setName(rawInfo
.getTextContent());
280 sessionInfo
.setSessionPath(rawInfo
.getTextContent());
282 case MIStrings
.ENABLED
:
283 sessionInfo
.setSessionState(rawInfo
.getTextContent());
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
);
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
);
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
);
317 if (!sessionInfo
.isSnapshotSession()) {
318 Matcher matcher
= LTTngControlServiceConstants
.TRACE_NETWORK_PATTERN
.matcher(sessionInfo
.getSessionPath());
319 if (matcher
.matches()) {
320 sessionInfo
.setStreamedTrace(true);
326 * Parse a raw domain XML node to a IDomainInfo object
330 * @return a populated {@link DomainInfo} object
331 * @throws ExecutionException
332 * when missing required xml element (type)
334 protected IDomainInfo
parseDomain(Node rawDomain
) throws ExecutionException
{
335 IDomainInfo domain
= null;
337 Node rawType
= getFirstOf(rawDomain
.getChildNodes(), MIStrings
.TYPE
);
338 if (rawType
== null) {
339 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
341 String rawTypeString
= rawType
.getTextContent().toLowerCase();
342 TraceDomainType domainType
= TraceDomainType
.valueOfString(rawTypeString
);
343 switch (domainType
) {
345 domain
= new DomainInfo(Messages
.TraceControl_KernelProviderDisplayName
);
346 domain
.setIsKernel(true);
349 domain
= new DomainInfo(Messages
.TraceControl_UstGlobalDomainDisplayName
);
350 domain
.setIsKernel(false);
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
358 domain
= new DomainInfo(Messages
.TraceControl_JULDomainDisplayName
);
359 domain
.setIsKernel(false);
362 domain
= new DomainInfo(Messages
.TraceControl_UnknownDomainDisplayName
);
363 domain
.setIsKernel(false);
366 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
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
);
377 case MIStrings
.CHANNELS
:
378 ArrayList
<IChannelInfo
> channels
= new ArrayList
<>();
379 parseChannels(rawInfo
.getChildNodes(), channels
);
380 if (channels
.size() > 0) {
381 domain
.setChannels(channels
);
393 * Parse a list of raw channel XML node into an ArrayList of IChannelInfo
396 * List of raw channel XML node
398 * the parsed channels list
399 * @throws ExecutionException
400 * when missing required xml element (type)
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$
409 // Populate the channel
410 NodeList rawInfos
= rawChannel
.getChildNodes();
412 for (int j
= 0; j
< rawInfos
.getLength(); j
++) {
413 rawInfo
= rawInfos
.item(j
);
414 switch (rawInfo
.getNodeName()) {
416 channel
.setName(rawInfo
.getTextContent());
418 case MIStrings
.ENABLED
:
419 channel
.setState(TraceEnablement
.valueOfString(rawInfo
.getTextContent()));
421 case MIStrings
.EVENTS
:
422 List
<IEventInfo
> events
= new ArrayList
<>();
423 getEventInfo(rawInfo
.getChildNodes(), events
);
424 channel
.setEvents(events
);
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()));
434 case MIStrings
.SUBBUF_SIZE
:
435 channel
.setSubBufferSize(Long
.valueOf(attribute
.getTextContent()));
437 case MIStrings
.NUM_SUBBUF
:
438 channel
.setNumberOfSubBuffers(Integer
.valueOf(attribute
.getTextContent()));
440 case MIStrings
.SWITCH_TIMER_INTERVAL
:
441 channel
.setSwitchTimer(Long
.valueOf(attribute
.getTextContent()));
443 case MIStrings
.READ_TIMER_INTERVAL
:
444 channel
.setReadTimer(Long
.valueOf(attribute
.getTextContent()));
446 case MIStrings
.OUTPUT_TYPE
:
447 channel
.setOutputType(attribute
.getTextContent());
449 case MIStrings
.TRACEFILE_SIZE
:
450 channel
.setMaxSizeTraceFiles(Long
.parseLong(attribute
.getTextContent()));
452 case MIStrings
.TRACEFILE_COUNT
:
453 channel
.setMaxNumberTraceFiles(Integer
.parseInt(attribute
.getTextContent()));
455 case MIStrings
.LIVE_TIMER_INTERVAL
:
456 // TODO: currently not supported by tmf
467 channels
.add(channel
);
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
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
);
485 ISnapshotInfo snapshotInfo
= new SnapshotInfo(""); //$NON-NLS-1$
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()) {
494 snapshotInfo
.setId(Integer
.parseInt(rawInfo
.getTextContent()));
497 snapshotInfo
.setName(rawInfo
.getTextContent());
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
503 // See http://bugs.lttng.org/issues/828 (+comment)
504 snapshotInfo
.setSnapshotPath(rawInfo
.getTextContent());
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);
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
<>();
527 if (isError(result
)) {
528 // Ignore the following 2 cases:
529 // Spawning a session daemon
530 // Error: Unable to list kernel events
532 // Error: Unable to list kernel events
533 if (ignoredPattern(result
.getErrorOutput(), LTTngControlServiceConstants
.LIST_KERNEL_NO_KERNEL_PROVIDER_PATTERN
)) {
536 throw new ExecutionException(Messages
.TraceControl_CommandError
+ command
.toString());
539 Document document
= getDocumentFromStrings(result
.getOutput());
540 NodeList rawEvents
= document
.getElementsByTagName(MIStrings
.EVENT
);
541 getBaseEventInfo(rawEvents
, events
);
546 public List
<IUstProviderInfo
> getUstProvider(IProgressMonitor monitor
) throws ExecutionException
{
547 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
, LTTngControlServiceConstants
.OPTION_UST
);
549 command
.add(LTTngControlServiceConstants
.OPTION_FIELDS
);
552 ICommandResult result
= executeCommand(command
, monitor
, false);
553 List
<IUstProviderInfo
> allProviders
= new ArrayList
<>();
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
560 // Error: Unable to list UST events: Listing UST events failed
561 if (ignoredPattern(result
.getErrorOutput(), LTTngControlServiceConstants
.LIST_UST_NO_UST_PROVIDER_PATTERN
)) {
564 throw new ExecutionException(Messages
.TraceControl_CommandError
+ command
.toString());
567 Document document
= getDocumentFromStrings(result
.getOutput());
568 NodeList rawProviders
= document
.getElementsByTagName(MIStrings
.PID
);
570 IUstProviderInfo providerInfo
= null;
572 for (int i
= 0; i
< rawProviders
.getLength(); i
++) {
573 Node provider
= rawProviders
.item(i
);
574 Node name
= getFirstOf(provider
.getChildNodes(), MIStrings
.NAME
);
576 throw new ExecutionException(Messages
.TraceControl_MiInvalidProviderError
);
578 providerInfo
= new UstProviderInfo(name
.getTextContent());
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()));
588 case MIStrings
.EVENTS
:
589 List
<IBaseEventInfo
> events
= new ArrayList
<>();
590 NodeList rawEvents
= info
.getChildNodes();
591 getBaseEventInfo(rawEvents
, events
);
592 providerInfo
.setEvents(events
);
598 allProviders
.add(providerInfo
);
605 public ISessionInfo
createSession(ISessionInfo sessionInfo
, IProgressMonitor monitor
) throws ExecutionException
{
606 if (sessionInfo
.isStreamedTrace()) {
607 return createStreamedSession(sessionInfo
, monitor
);
610 ICommandInput command
= prepareSessionCreationCommand(sessionInfo
);
611 ICommandResult result
= executeCommand(command
, monitor
);
613 Document document
= getDocumentFromStrings(result
.getOutput());
614 NodeList sessions
= document
.getElementsByTagName(MIStrings
.SESSION
);
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$
622 // Fetch a session from output
623 ISessionInfo outputSession
= new SessionInfo(""); //$NON-NLS-1$
624 parseSession(outputSession
, sessions
.item(0));
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$
633 // Verify session path
634 if (!sessionInfo
.isSnapshotSession() &&
635 ((outputSession
.getSessionPath() == null) || ((sessionInfo
.getSessionPath() != null) && (!outputSession
.getSessionPath().contains(sessionInfo
.getSessionPath()))))) {
637 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + //$NON-NLS-1$ //$NON-NLS-2$
638 Messages
.TraceControl_UnexpectedPathError
+ ": " + outputSession
.getName()); //$NON-NLS-1$
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$
647 return outputSession
;
650 private @NonNull ISessionInfo
createStreamedSession(ISessionInfo sessionInfo
, IProgressMonitor monitor
) throws ExecutionException
{
652 ICommandInput command
= prepareStreamedSessionCreationCommand(sessionInfo
);
654 ICommandResult result
= executeCommand(command
, monitor
);
656 Document document
= getDocumentFromStrings(result
.getOutput());
657 NodeList sessions
= document
.getElementsByTagName(MIStrings
.SESSION
);
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$
665 // Fetch a session from output
666 ISessionInfo outputSession
= new SessionInfo(""); //$NON-NLS-1$
667 parseSession(outputSession
, sessions
.item(0));
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$
676 sessionInfo
.setName(outputSession
.getName());
677 sessionInfo
.setStreamedTrace(true);
679 // Verify session path
680 if (sessionInfo
.getNetworkUrl() != null) {
681 if (!sessionInfo
.isSnapshotSession() && (outputSession
.getSessionPath() == null)) {
683 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + //$NON-NLS-1$ //$NON-NLS-2$
684 Messages
.TraceControl_UnexpectedPathError
+ ": " + outputSession
.getName()); //$NON-NLS-1$
687 if (sessionInfo
.isSnapshotSession()) {
688 sessionInfo
.setStreamedTrace(false);
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);
699 // When using controlUrl and dataUrl the full session path is not known
701 // and will be set later on when listing the session
706 public void destroySession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
707 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_DESTROY_SESSION
, sessionName
);
709 ICommandResult result
= executeCommand(command
, monitor
, false);
710 List
<String
> errorOutput
= result
.getErrorOutput();
712 if (isError(result
)) {
713 // Don't treat this as an error
714 if (ignoredPattern(errorOutput
, LTTngControlServiceConstants
.SESSION_NOT_FOUND_ERROR_PATTERN
)) {
718 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
.toString() + "\n" + result
.toString()); //$NON-NLS-1$ //$NON-NLS-2$
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
));
728 Node rawSessionName
= getFirstOf(sessions
.item(0).getChildNodes(), MIStrings
.NAME
);
729 if (rawSessionName
== null) {
730 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
734 if (!rawSessionName
.getTextContent().equals(sessionName
)) {
735 throw new ExecutionException(NLS
.bind(Messages
.TraceControl_UnexpectedValueError
, rawSessionName
.getTextContent(), sessionName
));
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
);
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
));
756 * @param xmlBaseEvents
757 * a Node list of base xml event element
759 * list of event generated by the parsing of the xml event
761 * @throws ExecutionException
762 * when a raw event is not a complete/valid xml event
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();
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
);
774 eventInfo
= new BaseEventInfo(rawName
.getTextContent());
776 // Populate the event
777 for (int j
= 0; j
< rawInfos
.getLength(); j
++) {
778 Node infoNode
= rawInfos
.item(j
);
779 switch (infoNode
.getNodeName()) {
781 eventInfo
.setEventType(infoNode
.getTextContent());
783 case MIStrings
.LOGLEVEL
:
784 eventInfo
.setLogLevel(infoNode
.getTextContent());
786 case MIStrings
.EVENT_FIELDS
:
787 List
<IFieldInfo
> fields
= new ArrayList
<>();
788 getFieldInfo(infoNode
.getChildNodes(), fields
);
789 eventInfo
.setFields(fields
);
795 events
.add(eventInfo
);
801 * @param xmlBaseEvents
802 * a Node list of xml event element linked to a session
804 * list of event generated by the parsing of the xml event
806 * @throws ExecutionException
807 * when a raw event is not a complete/valid xml event
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();
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
);
820 eventInfo
= new EventInfo(rawName
.getTextContent());
823 for (int j
= 0; j
< rawInfos
.getLength(); j
++) {
824 Node infoNode
= rawInfos
.item(j
);
825 switch (infoNode
.getNodeName()) {
827 eventInfo
.setEventType(infoNode
.getTextContent());
829 case MIStrings
.LOGLEVEL_TYPE
:
830 eventInfo
.setLogLevelType(LogLevelType
.valueOfString(infoNode
.getTextContent()));
832 case MIStrings
.LOGLEVEL
:
833 eventInfo
.setLogLevel(TraceLogLevel
.valueOfString(infoNode
.getTextContent()));
835 case MIStrings
.ENABLED
:
836 eventInfo
.setState(TraceEnablement
.valueOfString(infoNode
.getTextContent()));
838 case MIStrings
.FILTER
:
840 // See bug 334 http://bugs.lttng.org/issues/334 from
842 // For now we emulate the non-mi behavior and simply put
844 eventInfo
.setFilterExpression("with filter"); //$NON-NLS-1$
846 case MIStrings
.EXCLUSION
:
847 // TODO: Currently not supported by tmf
848 // ExclusionS element is ignored
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
;
860 Node rawDataNode
= null;
861 switch (probeEvent
.getEventType()) {
865 Node rawAttributes
= getFirstOf(rawInfos
, MIStrings
.ATTRIBUTES
);
866 if (rawAttributes
== null) {
867 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
869 rawDataNode
= getFirstOf(rawAttributes
.getChildNodes(), MIStrings
.PROBE_ATTRIBUTES
);
876 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
879 if (rawDataNode
== null) {
880 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
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());
891 case MIStrings
.ADDRESS
:
892 probeEvent
.setAddress(String
.format("%#016x", new BigInteger(rawData
.getTextContent()))); //$NON-NLS-1$
894 case MIStrings
.OFFSET
:
895 probeEvent
.setOffset(String
.format("%#016x", new BigInteger(rawData
.getTextContent()))); //$NON-NLS-1$
904 events
.add(eventInfo
);
911 * a list of xml event_field element
913 * a list of field generated by xml parsing
914 * @throws ExecutionException
915 * when parsing fail or required elements are missing
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
)) {
923 Node name
= getFirstOf(field
.getChildNodes(), MIStrings
.NAME
);
925 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
927 fieldInfo
= new FieldInfo(name
.getTextContent());
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()) {
935 fieldInfo
.setFieldType(info
.getTextContent());
941 fields
.add(fieldInfo
);
947 * Retrieve the fist instance of a given node with tag name equal to tagName
951 * the list of Node to search against
953 * the tag name of the desired node
954 * @return the first occurrence of a node with a tag name equals to tagName
956 private static @Nullable Node
getFirstOf(NodeList nodeList
, String tagName
) {
958 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
959 if (NonNullUtils
.equalsNullable(nodeList
.item(i
).getNodeName(), tagName
)) {
960 node
= nodeList
.item(i
);