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
.Objects
;
25 import java
.util
.regex
.Matcher
;
27 import javax
.xml
.XMLConstants
;
28 import javax
.xml
.parsers
.DocumentBuilder
;
29 import javax
.xml
.parsers
.DocumentBuilderFactory
;
30 import javax
.xml
.parsers
.ParserConfigurationException
;
31 import javax
.xml
.validation
.SchemaFactory
;
33 import org
.eclipse
.core
.commands
.ExecutionException
;
34 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
35 import org
.eclipse
.core
.runtime
.Platform
;
36 import org
.eclipse
.jdt
.annotation
.NonNull
;
37 import org
.eclipse
.jdt
.annotation
.Nullable
;
38 import org
.eclipse
.osgi
.util
.NLS
;
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
.ILoggerInfo
;
45 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.IProbeEventInfo
;
46 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.ISessionInfo
;
47 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.ISnapshotInfo
;
48 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.IUstProviderInfo
;
49 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.LogLevelType
;
50 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.TraceDomainType
;
51 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.TraceEnablement
;
52 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.TraceEventType
;
53 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.TraceJulLogLevel
;
54 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.TraceLogLevel
;
55 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.BaseEventInfo
;
56 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.BufferType
;
57 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.ChannelInfo
;
58 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.DomainInfo
;
59 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.EventInfo
;
60 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.FieldInfo
;
61 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.LoggerInfo
;
62 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.ProbeEventInfo
;
63 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.SessionInfo
;
64 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.SnapshotInfo
;
65 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.core
.model
.impl
.UstProviderInfo
;
66 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.ui
.Activator
;
67 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.ui
.views
.handlers
.XmlMiValidationErrorHandler
;
68 import org
.eclipse
.tracecompass
.internal
.lttng2
.control
.ui
.views
.messages
.Messages
;
69 import org
.eclipse
.tracecompass
.tmf
.remote
.core
.shell
.ICommandInput
;
70 import org
.eclipse
.tracecompass
.tmf
.remote
.core
.shell
.ICommandResult
;
71 import org
.eclipse
.tracecompass
.tmf
.remote
.core
.shell
.ICommandShell
;
72 import org
.w3c
.dom
.Document
;
73 import org
.w3c
.dom
.Node
;
74 import org
.w3c
.dom
.NodeList
;
75 import org
.xml
.sax
.InputSource
;
76 import org
.xml
.sax
.SAXException
;
79 * Service for sending LTTng trace control commands to remote host via machine
82 * @author Jonathan Rajotte
84 public class LTTngControlServiceMI
extends LTTngControlService
{
87 * The tracing key (.options) and System property to control whether or not schema validation should be used.
89 public static final String MI_SCHEMA_VALIDATION_KEY
= Activator
.PLUGIN_ID
+ "/mi/schema-validation"; //$NON-NLS-1$
91 // ------------------------------------------------------------------------
93 // ------------------------------------------------------------------------
95 private final DocumentBuilder fDocumentBuilder
;
97 // ------------------------------------------------------------------------
99 // ------------------------------------------------------------------------
105 * the command shell implementation to use
108 * @throws ExecutionException
109 * if the creation of the Schema and DocumentBuilder objects
112 public LTTngControlServiceMI(@NonNull ICommandShell shell
, @Nullable LttngVersion version
) throws ExecutionException
{
116 DocumentBuilderFactory docBuilderFactory
= DocumentBuilderFactory
.newInstance();
117 docBuilderFactory
.setValidating(false);
119 if (isSchemaValidationEnabled()) {
120 if (version
!= null) {
121 SchemaFactory schemaFactory
= SchemaFactory
.newInstance(XMLConstants
.W3C_XML_SCHEMA_NS_URI
);
123 URL xsdUrl
= LTTngControlService
.class.getResource(LTTngControlServiceConstants
.MI_XSD_FILENAME
);
124 if (version
.compareTo(new LttngVersion(2, 8, 0, null, null, null, null, null, null)) >= 0) {
125 xsdUrl
= LTTngControlService
.class.getResource(LTTngControlServiceConstants
.MI3_XSD_FILENAME
);
126 // MI 3.0 added name spaces. It will fail to validate if this is not set to true.
127 docBuilderFactory
.setNamespaceAware(true);
129 docBuilderFactory
.setSchema(schemaFactory
.newSchema(xsdUrl
));
130 } catch (SAXException e
) {
131 throw new ExecutionException(Messages
.TraceControl_InvalidSchemaError
, e
);
137 fDocumentBuilder
= docBuilderFactory
.newDocumentBuilder();
138 } catch (ParserConfigurationException e
) {
139 throw new ExecutionException(Messages
.TraceControl_XmlDocumentBuilderError
, e
);
142 fDocumentBuilder
.setErrorHandler(new XmlMiValidationErrorHandler());
146 private static boolean isSchemaValidationEnabled() {
147 String schemaValidationKey
= Platform
.getDebugOption(MI_SCHEMA_VALIDATION_KEY
);
148 String systemProperty
= System
.getProperty(MI_SCHEMA_VALIDATION_KEY
);
149 return schemaValidationKey
!= null && Boolean
.parseBoolean(schemaValidationKey
) || systemProperty
!= null && Boolean
.parseBoolean(systemProperty
);
153 * Generate a Document object from an list of Strings.
156 * list of strings representing an xml input
157 * @param documentBuilder
158 * the builder used to get the document
159 * @return Document generated from strings input
160 * @throws ExecutionException
161 * when parsing has failed
163 private static Document
getDocumentFromStrings(List
<String
> xmlStrings
, DocumentBuilder documentBuilder
) throws ExecutionException
{
164 StringBuilder concatenedString
= new StringBuilder();
165 for (String string
: xmlStrings
) {
166 concatenedString
.append(string
);
168 InputSource stream
= new InputSource(new StringReader(concatenedString
.toString()));
172 document
= documentBuilder
.parse(stream
);
173 } catch (SAXException
| IOException e
) {
174 throw new ExecutionException(Messages
.TraceControl_XmlParsingError
+ ':' + e
.toString(), e
);
181 * Parse LTTng version from a MI command result
183 * @param commandResult
184 * the result obtained from a MI command
185 * @return the LTTng version
186 * @throws ExecutionException
187 * when xml extraction fail
189 public static LttngVersion
parseVersion(ICommandResult commandResult
) throws ExecutionException
{
190 DocumentBuilderFactory docBuilderFactory
= DocumentBuilderFactory
.newInstance();
191 DocumentBuilder documentBuilder
;
193 documentBuilder
= docBuilderFactory
.newDocumentBuilder();
194 } catch (ParserConfigurationException e
) {
195 throw new ExecutionException(Messages
.TraceControl_XmlDocumentBuilderError
, e
);
198 Document doc
= getDocumentFromStrings(commandResult
.getOutput(), documentBuilder
);
199 NodeList element
= doc
.getElementsByTagName(MIStrings
.VERSION
);
200 if (element
.getLength() != 1) {
201 throw new ExecutionException(Messages
.TraceControl_UnsupportedVersionError
);
207 String license
= ""; //$NON-NLS-1$
208 String commit
= ""; //$NON-NLS-1$
209 String name
= ""; //$NON-NLS-1$
210 String description
= ""; //$NON-NLS-1$
211 String url
= ""; //$NON-NLS-1$
212 String fullVersion
= ""; //$NON-NLS-1$
213 NodeList child
= element
.item(0).getChildNodes();
214 // Get basic information
215 for (int i
= 0; i
< child
.getLength(); i
++) {
216 Node node
= child
.item(i
);
217 switch (node
.getNodeName()) {
218 case MIStrings
.VERSION_MAJOR
:
219 major
= Integer
.parseInt(node
.getTextContent());
221 case MIStrings
.VERSION_MINOR
:
222 minor
= Integer
.parseInt(node
.getTextContent());
224 case MIStrings
.VERSION_PATCH_LEVEL
:
225 patchLevel
= Integer
.parseInt(node
.getTextContent());
227 case MIStrings
.VERSION_COMMIT
:
228 commit
= node
.getTextContent();
230 case MIStrings
.VERSION_DESCRIPTION
:
231 description
= node
.getTextContent();
233 case MIStrings
.VERSION_LICENSE
:
234 license
= node
.getTextContent();
236 case MIStrings
.VERSION_NAME
:
237 name
= node
.getTextContent();
239 case MIStrings
.VERSION_STR
:
240 fullVersion
= node
.getTextContent();
242 case MIStrings
.VERSION_WEB
:
243 url
= node
.getTextContent();
249 return new LttngVersion(major
, minor
, patchLevel
, license
, commit
, name
, description
, url
, fullVersion
);
253 public List
<String
> getSessionNames(IProgressMonitor monitor
) throws ExecutionException
{
254 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
);
255 ICommandResult result
= executeCommand(command
, monitor
);
257 Document doc
= getDocumentFromStrings(result
.getOutput(), fDocumentBuilder
);
259 NodeList elements
= doc
.getElementsByTagName(MIStrings
.NAME
);
261 ArrayList
<String
> retArray
= new ArrayList
<>();
262 for (int i
= 0; i
< elements
.getLength(); i
++) {
263 Node node
= elements
.item(i
);
264 if (node
.getParentNode().getNodeName().equalsIgnoreCase(MIStrings
.SESSION
)) {
265 retArray
.add(node
.getTextContent());
272 public ISessionInfo
getSession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
273 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
, sessionName
);
274 ICommandResult result
= executeCommand(command
, monitor
);
276 ISessionInfo sessionInfo
= new SessionInfo(sessionName
);
277 Document document
= getDocumentFromStrings(result
.getOutput(), fDocumentBuilder
);
279 NodeList sessionsNode
= document
.getElementsByTagName(MIStrings
.SESSION
);
280 // There should be only one session
281 if (sessionsNode
.getLength() != 1) {
282 throw new ExecutionException(NLS
.bind(Messages
.TraceControl_MiInvalidNumberOfElementError
, MIStrings
.SESSION
));
285 // Populate session information
286 Node rawSession
= sessionsNode
.item(0);
287 parseSession(sessionInfo
, rawSession
);
289 // Fetch the snapshot info
290 if (sessionInfo
.isSnapshotSession()) {
291 ISnapshotInfo snapshot
= getSnapshotInfo(sessionName
, monitor
);
292 sessionInfo
.setSnapshotInfo(snapshot
);
301 * @throws ExecutionException
303 private void parseSession(ISessionInfo sessionInfo
, Node rawSession
) throws ExecutionException
{
304 if (!rawSession
.getNodeName().equalsIgnoreCase(MIStrings
.SESSION
)) {
305 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
307 NodeList rawSessionInfos
= rawSession
.getChildNodes();
308 for (int i
= 0; i
< rawSessionInfos
.getLength(); i
++) {
309 Node rawInfo
= rawSessionInfos
.item(i
);
310 switch (rawInfo
.getNodeName()) {
312 sessionInfo
.setName(rawInfo
.getTextContent());
315 sessionInfo
.setSessionPath(rawInfo
.getTextContent());
317 case MIStrings
.ENABLED
:
318 sessionInfo
.setSessionState(rawInfo
.getTextContent());
320 case MIStrings
.SNAPSHOT_MODE
:
321 if (rawInfo
.getTextContent().equals(LTTngControlServiceConstants
.TRUE_NUMERICAL
)) {
322 // real name will be set later
323 ISnapshotInfo snapshotInfo
= new SnapshotInfo(""); //$NON-NLS-1$
324 sessionInfo
.setSnapshotInfo(snapshotInfo
);
327 case MIStrings
.LIVE_TIMER_INTERVAL
:
328 long liveDelay
= Long
.parseLong(rawInfo
.getTextContent());
329 if ((liveDelay
> 0 && (liveDelay
<= LTTngControlServiceConstants
.MAX_LIVE_TIMER_INTERVAL
))) {
330 sessionInfo
.setLive(true);
331 sessionInfo
.setLiveUrl(SessionInfo
.DEFAULT_LIVE_NETWORK_URL
);
332 sessionInfo
.setLivePort(SessionInfo
.DEFAULT_LIVE_PORT
);
333 sessionInfo
.setLiveDelay(liveDelay
);
336 case MIStrings
.DOMAINS
:
337 // Extract the domains node
338 NodeList rawDomains
= rawInfo
.getChildNodes();
339 IDomainInfo domain
= null;
340 for (int j
= 0; j
< rawDomains
.getLength(); j
++) {
341 if (rawDomains
.item(j
).getNodeName().equalsIgnoreCase(MIStrings
.DOMAIN
)) {
342 domain
= parseDomain(rawDomains
.item(j
));
343 sessionInfo
.addDomain(domain
);
352 if (!sessionInfo
.isSnapshotSession()) {
353 Matcher matcher
= LTTngControlServiceConstants
.TRACE_NETWORK_PATTERN
.matcher(sessionInfo
.getSessionPath());
354 if (matcher
.matches()) {
355 sessionInfo
.setStreamedTrace(true);
361 * Parse a raw domain XML node to a IDomainInfo object
365 * @return a populated {@link DomainInfo} object
366 * @throws ExecutionException
367 * when missing required xml element (type)
369 protected IDomainInfo
parseDomain(Node rawDomain
) throws ExecutionException
{
370 IDomainInfo domain
= null;
372 Node rawType
= getFirstOf(rawDomain
.getChildNodes(), MIStrings
.TYPE
);
373 if (rawType
== null) {
374 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
376 String rawTypeString
= rawType
.getTextContent().toLowerCase();
377 TraceDomainType domainType
= TraceDomainType
.valueOfString(rawTypeString
);
378 switch (domainType
) {
380 domain
= new DomainInfo(Messages
.TraceControl_KernelProviderDisplayName
);
381 domain
.setDomain(TraceDomainType
.KERNEL
);
384 domain
= new DomainInfo(Messages
.TraceControl_UstGlobalDomainDisplayName
);
385 domain
.setDomain(TraceDomainType
.UST
);
389 * TODO: Support for JUL JUL substructure and semantic is not the
390 * same as a regular UST or Kernel Domain There is no channel under
391 * JUL domain only events. The channel is activated in UST Channel
393 domain
= new DomainInfo(Messages
.TraceControl_JULDomainDisplayName
);
394 domain
.setDomain(TraceDomainType
.JUL
);
397 domain
= new DomainInfo(Messages
.TraceControl_UnknownDomainDisplayName
);
398 domain
.setDomain(TraceDomainType
.UNKNOWN
);
402 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
405 NodeList rawInfos
= rawDomain
.getChildNodes();
406 for (int i
= 0; i
< rawInfos
.getLength(); i
++) {
407 Node rawInfo
= rawInfos
.item(i
);
408 switch (rawInfo
.getNodeName()) {
409 case MIStrings
.BUFFER_TYPE
:
410 BufferType bufferType
= BufferType
.valueOfString(rawInfo
.getTextContent());
411 domain
.setBufferType(bufferType
);
413 case MIStrings
.CHANNELS
:
414 ArrayList
<IChannelInfo
> channels
= new ArrayList
<>();
415 parseChannels(rawInfo
.getChildNodes(), channels
);
416 if (channels
.size() > 0) {
417 domain
.setChannels(channels
);
420 case MIStrings
.EVENTS
:
421 ArrayList
<ILoggerInfo
> loggers
= new ArrayList
<>();
422 getLoggerInfo(rawInfo
.getChildNodes(), loggers
, domain
.getDomain());
423 domain
.setLoggers(loggers
);
434 * Parse a list of raw channel XML node into an ArrayList of IChannelInfo
437 * List of raw channel XML node
439 * the parsed channels list
440 * @throws ExecutionException
441 * when missing required xml element (type)
443 private static void parseChannels(NodeList rawChannels
, ArrayList
<IChannelInfo
> channels
) throws ExecutionException
{
444 IChannelInfo channel
= null;
445 for (int i
= 0; i
< rawChannels
.getLength(); i
++) {
446 Node rawChannel
= rawChannels
.item(i
);
447 if (rawChannel
.getNodeName().equalsIgnoreCase(MIStrings
.CHANNEL
)) {
448 channel
= new ChannelInfo(""); //$NON-NLS-1$
450 // Populate the channel
451 NodeList rawInfos
= rawChannel
.getChildNodes();
453 for (int j
= 0; j
< rawInfos
.getLength(); j
++) {
454 rawInfo
= rawInfos
.item(j
);
455 switch (rawInfo
.getNodeName()) {
457 channel
.setName(rawInfo
.getTextContent());
459 case MIStrings
.ENABLED
:
460 channel
.setState(TraceEnablement
.valueOfString(rawInfo
.getTextContent()));
462 case MIStrings
.EVENTS
:
463 List
<IEventInfo
> events
= new ArrayList
<>();
464 getEventInfo(rawInfo
.getChildNodes(), events
);
465 channel
.setEvents(events
);
467 case MIStrings
.ATTRIBUTES
:
468 NodeList rawAttributes
= rawInfo
.getChildNodes();
469 for (int k
= 0; k
< rawAttributes
.getLength(); k
++) {
470 Node attribute
= rawAttributes
.item(k
);
471 switch (attribute
.getNodeName()) {
472 case MIStrings
.OVERWRITE_MODE
:
473 channel
.setOverwriteMode(!LTTngControlServiceConstants
.OVERWRITE_MODE_ATTRIBUTE_FALSE_MI
.equalsIgnoreCase(attribute
.getTextContent()));
475 case MIStrings
.SUBBUF_SIZE
:
476 channel
.setSubBufferSize(Long
.valueOf(attribute
.getTextContent()));
478 case MIStrings
.NUM_SUBBUF
:
479 channel
.setNumberOfSubBuffers(Integer
.valueOf(attribute
.getTextContent()));
481 case MIStrings
.SWITCH_TIMER_INTERVAL
:
482 channel
.setSwitchTimer(Long
.valueOf(attribute
.getTextContent()));
484 case MIStrings
.READ_TIMER_INTERVAL
:
485 channel
.setReadTimer(Long
.valueOf(attribute
.getTextContent()));
487 case MIStrings
.OUTPUT_TYPE
:
488 channel
.setOutputType(attribute
.getTextContent());
490 case MIStrings
.TRACEFILE_SIZE
:
491 channel
.setMaxSizeTraceFiles(Long
.parseLong(attribute
.getTextContent()));
493 case MIStrings
.TRACEFILE_COUNT
:
494 channel
.setMaxNumberTraceFiles(Integer
.parseInt(attribute
.getTextContent()));
496 case MIStrings
.LIVE_TIMER_INTERVAL
:
497 // TODO: currently not supported by tmf
499 case MIStrings
.DISCARDED_EVENTS
:
500 channel
.setNumberOfDiscardedEvents(Long
.parseLong(attribute
.getTextContent()));
502 case MIStrings
.LOST_PACKETS
:
503 channel
.setNumberOfLostPackets(Long
.parseLong(attribute
.getTextContent()));
514 channels
.add(channel
);
521 public ISnapshotInfo
getSnapshotInfo(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
522 // TODO A session can have multiple snapshot output. This need to be
523 // supported in the future.
524 // Currently the SessionInfo object does not support multiple snashot
526 // For now only keep the last one.
527 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_SNAPSHOT
, LTTngControlServiceConstants
.COMMAND_LIST_SNAPSHOT_OUTPUT
, LTTngControlServiceConstants
.OPTION_SESSION
, sessionName
);
528 ICommandResult result
= executeCommand(command
, monitor
);
529 Document doc
= getDocumentFromStrings(result
.getOutput(), fDocumentBuilder
);
530 NodeList rawSnapshotsOutputs
= doc
.getElementsByTagName(MIStrings
.SNAPSHOT_OUTPUTS
);
532 ISnapshotInfo snapshotInfo
= new SnapshotInfo(""); //$NON-NLS-1$
534 // TODO: tmf does not have a notion of a ctrl url.
535 for (int i
= 0; i
< rawSnapshotsOutputs
.getLength(); i
++) {
536 NodeList rawSnapshotOutput
= rawSnapshotsOutputs
.item(i
).getChildNodes();
537 for (int j
= 0; j
< rawSnapshotOutput
.getLength(); j
++) {
538 Node rawInfo
= rawSnapshotOutput
.item(j
);
539 switch (rawInfo
.getNodeName()) {
541 snapshotInfo
.setId(Integer
.parseInt(rawInfo
.getTextContent()));
544 snapshotInfo
.setName(rawInfo
.getTextContent());
546 case MIStrings
.SNAPSHOT_CTRL_URL
:
547 // The use of the ctrl_url for the snapshot path is to assure
548 // basic support. Refactoring is necessary in lttng and
550 // See http://bugs.lttng.org/issues/828 (+comment)
551 snapshotInfo
.setSnapshotPath(rawInfo
.getTextContent());
559 // Check if the snapshot output is Streamed
560 Matcher matcher2
= LTTngControlServiceConstants
.TRACE_NETWORK_PATTERN
.matcher(snapshotInfo
.getSnapshotPath());
561 if (matcher2
.matches()) {
562 snapshotInfo
.setStreamedSnapshot(true);
569 public List
<IBaseEventInfo
> getKernelProvider(IProgressMonitor monitor
) throws ExecutionException
{
571 ICommandInput tracepointCommand
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
, LTTngControlServiceConstants
.OPTION_KERNEL
);
572 ICommandResult tracepointResult
= executeCommand(tracepointCommand
, monitor
, false);
573 List
<IBaseEventInfo
> events
= new ArrayList
<>();
575 if (isError(tracepointResult
)) {
576 // Ignore the following 2 cases:
577 // Spawning a session daemon
578 // Error: Unable to list kernel events
580 // Error: Unable to list kernel events
581 if (ignoredPattern(tracepointResult
.getErrorOutput(), LTTngControlServiceConstants
.LIST_KERNEL_NO_KERNEL_PROVIDER_PATTERN
)) {
584 throw new ExecutionException(Messages
.TraceControl_CommandError
+ tracepointCommand
.toString());
587 Document tracepointDocument
= getDocumentFromStrings(tracepointResult
.getOutput(), fDocumentBuilder
);
588 NodeList rawTracepointEvents
= tracepointDocument
.getElementsByTagName(MIStrings
.EVENT
);
589 getBaseEventInfo(rawTracepointEvents
, events
);
592 ICommandInput syscallCommand
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
, LTTngControlServiceConstants
.OPTION_KERNEL
, LTTngControlServiceConstants
.OPTION_SYSCALL
);
593 ICommandResult syscallResult
= executeCommand(syscallCommand
, monitor
, false);
594 List
<IBaseEventInfo
> syscallEvents
= new ArrayList
<>();
596 if (isError(syscallResult
)) {
597 throw new ExecutionException(Messages
.TraceControl_CommandError
+ syscallCommand
.toString());
600 Document syscallDocument
= getDocumentFromStrings(syscallResult
.getOutput(), fDocumentBuilder
);
601 NodeList rawSyscallEvents
= syscallDocument
.getElementsByTagName(MIStrings
.EVENT
);
602 getBaseEventInfo(rawSyscallEvents
, syscallEvents
);
604 // Merge the tracepoint events with the syscall events (all under the Kernel provider)
605 events
.addAll(syscallEvents
);
610 public List
<IUstProviderInfo
> getUstProvider(IProgressMonitor monitor
) throws ExecutionException
{
611 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
, LTTngControlServiceConstants
.OPTION_UST
);
613 command
.add(LTTngControlServiceConstants
.OPTION_FIELDS
);
614 // Execute UST listing
615 ICommandResult result
= executeCommand(command
, monitor
, false);
616 List
<IUstProviderInfo
> allProviders
= new ArrayList
<>();
618 if (isError(result
)) {
619 // Ignore the following 2 cases:
620 // Spawning a session daemon
621 // Error: Unable to list UST events: Listing UST events failed
623 // Error: Unable to list UST events: Listing UST events failed
624 if (ignoredPattern(result
.getErrorOutput(), LTTngControlServiceConstants
.LIST_UST_NO_UST_PROVIDER_PATTERN
)) {
627 throw new ExecutionException(Messages
.TraceControl_CommandError
+ command
.toString());
630 Document document
= getDocumentFromStrings(result
.getOutput(), fDocumentBuilder
);
631 NodeList rawProviders
= document
.getElementsByTagName(MIStrings
.PID
);
633 IUstProviderInfo providerInfo
= null;
635 for (int i
= 0; i
< rawProviders
.getLength(); i
++) {
636 Node provider
= rawProviders
.item(i
);
637 Node name
= getFirstOf(provider
.getChildNodes(), MIStrings
.NAME
);
639 throw new ExecutionException(Messages
.TraceControl_MiInvalidProviderError
);
641 providerInfo
= new UstProviderInfo(name
.getTextContent());
644 NodeList infos
= provider
.getChildNodes();
645 for (int j
= 0; j
< infos
.getLength(); j
++) {
646 Node info
= infos
.item(j
);
647 switch (info
.getNodeName()) {
648 case MIStrings
.PID_ID
:
649 providerInfo
.setPid(Integer
.parseInt(info
.getTextContent()));
651 case MIStrings
.EVENTS
:
652 List
<IBaseEventInfo
> events
= new ArrayList
<>();
653 NodeList rawEvents
= info
.getChildNodes();
654 getBaseEventInfo(rawEvents
, events
);
655 providerInfo
.setEvents(events
);
661 allProviders
.add(providerInfo
);
664 // Getting the loggers information since those are under the UST provider
665 ICommandInput commandJul
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
, LTTngControlServiceConstants
.OPTION_JUL
);
666 // Execute JUL listing
667 ICommandResult resultJul
= executeCommand(commandJul
, monitor
, false);
669 if (isError(resultJul
)) {
670 throw new ExecutionException(Messages
.TraceControl_CommandError
+ commandJul
.toString());
673 Document documentJul
= getDocumentFromStrings(resultJul
.getOutput(), fDocumentBuilder
);
674 NodeList rawProvidersJul
= documentJul
.getElementsByTagName(MIStrings
.PID
);
676 for (int i
= 0; i
< rawProvidersJul
.getLength(); i
++) {
677 Node provider
= rawProvidersJul
.item(i
);
678 Node name
= getFirstOf(provider
.getChildNodes(), MIStrings
.NAME
);
680 throw new ExecutionException(Messages
.TraceControl_MiInvalidProviderError
);
683 Node id
= getFirstOf(provider
.getChildNodes(), MIStrings
.PID_ID
);
686 for (int k
= 0; k
< allProviders
.size(); k
++) {
687 if (allProviders
.get(k
).getPid() == Integer
.parseInt(id
.getTextContent())) {
688 Node events
= getFirstOf(provider
.getChildNodes(), MIStrings
.EVENTS
);
689 if (events
!= null) {
690 List
<ILoggerInfo
> loggers
= new ArrayList
<>();
691 NodeList rawEvents
= events
.getChildNodes();
692 getLoggerInfo(rawEvents
, loggers
, TraceDomainType
.JUL
);
693 allProviders
.get(k
).setLoggers(loggers
);
703 public ISessionInfo
createSession(ISessionInfo sessionInfo
, IProgressMonitor monitor
) throws ExecutionException
{
704 if (sessionInfo
.isStreamedTrace()) {
705 return createStreamedSession(sessionInfo
, monitor
);
708 ICommandInput command
= prepareSessionCreationCommand(sessionInfo
);
709 ICommandResult result
= executeCommand(command
, monitor
);
711 Document document
= getDocumentFromStrings(result
.getOutput(), fDocumentBuilder
);
712 NodeList sessions
= document
.getElementsByTagName(MIStrings
.SESSION
);
714 // Number of session should be equal to 1
715 if (sessions
.getLength() != 1) {
716 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" //$NON-NLS-1$//$NON-NLS-2$
717 + NLS
.bind(Messages
.TraceControl_UnexpectedNumberOfElementError
, MIStrings
.SESSION
) + " " + sessions
.getLength()); //$NON-NLS-1$
720 // Fetch a session from output
721 ISessionInfo outputSession
= new SessionInfo(""); //$NON-NLS-1$
722 parseSession(outputSession
, sessions
.item(0));
724 // Verify session name
725 if ((outputSession
.getName().equals("")) || (!"".equals(sessionInfo
.getName()) && !outputSession
.getName().equals(sessionInfo
.getName()))) { //$NON-NLS-1$ //$NON-NLS-2$
726 // Unexpected name returned
727 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + //$NON-NLS-1$ //$NON-NLS-2$
728 Messages
.TraceControl_UnexpectedNameError
+ ": " + outputSession
.getName()); //$NON-NLS-1$
731 // Verify session path
732 if (!sessionInfo
.isSnapshotSession() &&
733 ((outputSession
.getSessionPath() == null) || ((sessionInfo
.getSessionPath() != null) && (!outputSession
.getSessionPath().contains(sessionInfo
.getSessionPath()))))) {
735 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + //$NON-NLS-1$ //$NON-NLS-2$
736 Messages
.TraceControl_UnexpectedPathError
+ ": " + outputSession
.getName()); //$NON-NLS-1$
739 if (sessionInfo
.isSnapshotSession()) {
740 // Make it a snapshot session - content of snapshot info need to
741 // set afterwards using getSession() or getSnapshotInfo()
742 outputSession
.setSnapshotInfo(new SnapshotInfo("")); //$NON-NLS-1$
745 return outputSession
;
748 private @NonNull ISessionInfo
createStreamedSession(ISessionInfo sessionInfo
, IProgressMonitor monitor
) throws ExecutionException
{
750 ICommandInput command
= prepareStreamedSessionCreationCommand(sessionInfo
);
752 ICommandResult result
= executeCommand(command
, monitor
);
754 Document document
= getDocumentFromStrings(result
.getOutput(), fDocumentBuilder
);
755 NodeList sessions
= document
.getElementsByTagName(MIStrings
.SESSION
);
757 // Number of session should be equal to 1
758 if (sessions
.getLength() != 1) {
759 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" //$NON-NLS-1$//$NON-NLS-2$
760 + NLS
.bind(Messages
.TraceControl_UnexpectedNumberOfElementError
, MIStrings
.SESSION
) + " " + sessions
.getLength()); //$NON-NLS-1$
763 // Fetch a session from output
764 ISessionInfo outputSession
= new SessionInfo(""); //$NON-NLS-1$
765 parseSession(outputSession
, sessions
.item(0));
767 // Verify session name
768 if ((outputSession
.getName().equals("")) || (!"".equals(sessionInfo
.getName()) && !outputSession
.getName().equals(sessionInfo
.getName()))) { //$NON-NLS-1$ //$NON-NLS-2$
769 // Unexpected name returned
770 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + //$NON-NLS-1$ //$NON-NLS-2$
771 Messages
.TraceControl_UnexpectedNameError
+ ": " + outputSession
.getName()); //$NON-NLS-1$
774 sessionInfo
.setName(outputSession
.getName());
775 sessionInfo
.setStreamedTrace(true);
777 // Verify session path
778 if (sessionInfo
.getNetworkUrl() != null) {
779 if (!sessionInfo
.isSnapshotSession() && (outputSession
.getSessionPath() == null)) {
781 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + //$NON-NLS-1$ //$NON-NLS-2$
782 Messages
.TraceControl_UnexpectedPathError
+ ": " + outputSession
.getName()); //$NON-NLS-1$
785 if (sessionInfo
.isSnapshotSession()) {
786 sessionInfo
.setStreamedTrace(false);
788 sessionInfo
.setSessionPath(outputSession
.getSessionPath());
789 // Check file protocol
790 Matcher matcher
= LTTngControlServiceConstants
.TRACE_FILE_PROTOCOL_PATTERN
.matcher(outputSession
.getSessionPath());
791 if (matcher
.matches()) {
792 sessionInfo
.setStreamedTrace(false);
797 // When using controlUrl and dataUrl the full session path is not known
799 // and will be set later on when listing the session
804 public void destroySession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
805 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_DESTROY_SESSION
, sessionName
);
807 ICommandResult result
= executeCommand(command
, monitor
, false);
808 List
<String
> errorOutput
= result
.getErrorOutput();
810 if (isError(result
)) {
811 // Don't treat this as an error
812 if (ignoredPattern(errorOutput
, LTTngControlServiceConstants
.SESSION_NOT_FOUND_ERROR_PATTERN
)) {
816 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
.toString() + "\n" + result
.toString()); //$NON-NLS-1$ //$NON-NLS-2$
819 // Check for action effect
820 Document doc
= getDocumentFromStrings(result
.getOutput(), fDocumentBuilder
);
821 NodeList sessions
= doc
.getElementsByTagName(MIStrings
.SESSION
);
822 if (sessions
.getLength() != 1) {
823 throw new ExecutionException(NLS
.bind(Messages
.TraceControl_MiInvalidNumberOfElementError
, MIStrings
.SESSION
));
826 Node rawSessionName
= getFirstOf(sessions
.item(0).getChildNodes(), MIStrings
.NAME
);
827 if (rawSessionName
== null) {
828 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
832 if (!rawSessionName
.getTextContent().equals(sessionName
)) {
833 throw new ExecutionException(NLS
.bind(Messages
.TraceControl_UnexpectedValueError
, rawSessionName
.getTextContent(), sessionName
));
838 protected ICommandInput
createCommand(String
... strings
) {
839 ICommandInput command
= getCommandShell().createCommand();
840 command
.add(LTTngControlServiceConstants
.CONTROL_COMMAND
);
841 List
<@NonNull String
> groupOption
= getTracingGroupOption();
842 if (!groupOption
.isEmpty()) {
843 command
.addAll(groupOption
);
845 command
.add(LTTngControlServiceConstants
.CONTROL_COMMAND_MI_OPTION
);
846 command
.add(LTTngControlServiceConstants
.CONTROL_COMMAND_MI_XML
);
847 for (String string
: strings
) {
848 command
.add(checkNotNull(string
));
854 * @param xmlBaseEvents
855 * a Node list of base xml event element
857 * list of event generated by the parsing of the xml event
859 * @throws ExecutionException
860 * when a raw event is not a complete/valid xml event
862 private static void getBaseEventInfo(NodeList xmlBaseEvents
, List
<IBaseEventInfo
> events
) throws ExecutionException
{
863 IBaseEventInfo eventInfo
= null;
864 for (int i
= 0; i
< xmlBaseEvents
.getLength(); i
++) {
865 NodeList rawInfos
= xmlBaseEvents
.item(i
).getChildNodes();
867 if (xmlBaseEvents
.item(i
).getNodeName().equalsIgnoreCase(MIStrings
.EVENT
)) {
868 Node rawName
= getFirstOf(rawInfos
, MIStrings
.NAME
);
869 if (rawName
== null) {
870 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
872 eventInfo
= new BaseEventInfo(rawName
.getTextContent());
874 // Populate the event
875 for (int j
= 0; j
< rawInfos
.getLength(); j
++) {
876 Node infoNode
= rawInfos
.item(j
);
877 switch (infoNode
.getNodeName()) {
879 eventInfo
.setEventType(infoNode
.getTextContent());
881 case MIStrings
.LOGLEVEL
:
882 eventInfo
.setLogLevel(infoNode
.getTextContent());
884 case MIStrings
.EVENT_FIELDS
:
885 List
<IFieldInfo
> fields
= new ArrayList
<>();
886 getFieldInfo(infoNode
.getChildNodes(), fields
);
887 eventInfo
.setFields(fields
);
893 events
.add(eventInfo
);
899 * @param xmlBaseEvents
900 * a Node list of xml event element linked to a session
902 * list of event generated by the parsing of the xml event
904 * @throws ExecutionException
905 * when a raw event is not a complete/valid xml event
907 static void getEventInfo(NodeList xmlEvents
, List
<IEventInfo
> events
) throws ExecutionException
{
908 IEventInfo eventInfo
= null;
909 for (int i
= 0; i
< xmlEvents
.getLength(); i
++) {
910 NodeList rawInfos
= xmlEvents
.item(i
).getChildNodes();
912 if (xmlEvents
.item(i
).getNodeName().equalsIgnoreCase(MIStrings
.EVENT
)) {
913 Node rawName
= getFirstOf(rawInfos
, MIStrings
.NAME
);
914 if (rawName
== null) {
915 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
918 eventInfo
= new EventInfo(rawName
.getTextContent());
921 for (int j
= 0; j
< rawInfos
.getLength(); j
++) {
922 Node infoNode
= rawInfos
.item(j
);
923 switch (infoNode
.getNodeName()) {
925 eventInfo
.setEventType(infoNode
.getTextContent());
927 case MIStrings
.LOGLEVEL_TYPE
:
928 eventInfo
.setLogLevelType(LogLevelType
.valueOfString(infoNode
.getTextContent()));
930 case MIStrings
.LOGLEVEL
:
931 eventInfo
.setLogLevel(TraceLogLevel
.valueOfString(infoNode
.getTextContent()));
933 case MIStrings
.ENABLED
:
934 eventInfo
.setState(TraceEnablement
.valueOfString(infoNode
.getTextContent()));
936 case MIStrings
.FILTER
:
937 // Before LTTng 2.8: We emulate the non-mi behavior and simply put
939 if (Boolean
.TRUE
.toString().equals(infoNode
.getTextContent())) {
940 eventInfo
.setFilterExpression(Messages
.TraceControl_DefaultEventFilterString
);
943 case MIStrings
.FILTER_EXPRESSION
:
944 eventInfo
.setFilterExpression(infoNode
.getTextContent());
946 case MIStrings
.EXCLUSION
:
947 // Before LTTng 2.8: We emulate the non-mi behavior and simply put
949 if (Boolean
.TRUE
.toString().equals(infoNode
.getTextContent())) {
950 eventInfo
.setExcludedEvents(Messages
.TraceControl_DefaultEventExcludeString
);
953 case MIStrings
.EXCLUSIONS
:
954 StringBuilder tmpString
= new StringBuilder();
955 // If there is multiple events excluded.
956 for (int k
= 0; k
< infoNode
.getChildNodes().getLength(); k
++) {
958 tmpString
.append(", "); //$NON-NLS-1$
960 tmpString
.append(infoNode
.getChildNodes().item(k
).getTextContent());
962 eventInfo
.setExcludedEvents(tmpString
.toString());
969 boolean isProbeFunction
= (eventInfo
.getEventType().equals(TraceEventType
.PROBE
)) || (eventInfo
.getEventType().equals(TraceEventType
.FUNCTION
));
970 if (isProbeFunction
) {
971 IProbeEventInfo probeEvent
= new ProbeEventInfo(eventInfo
);
972 eventInfo
= probeEvent
;
974 Node rawDataNode
= null;
975 switch (probeEvent
.getEventType()) {
979 Node rawAttributes
= getFirstOf(rawInfos
, MIStrings
.ATTRIBUTES
);
980 if (rawAttributes
== null) {
981 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
983 rawDataNode
= getFirstOf(rawAttributes
.getChildNodes(), MIStrings
.PROBE_ATTRIBUTES
);
990 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
993 if (rawDataNode
== null) {
994 throw new ExecutionException(Messages
.TraceControl_MiInvalidElementError
);
998 NodeList rawDatas
= rawDataNode
.getChildNodes();
999 for (int j
= 0; j
< rawDatas
.getLength(); j
++) {
1000 Node rawData
= rawDatas
.item(j
);
1001 switch (rawData
.getNodeName()) {
1002 case MIStrings
.SYMBOL_NAME
:
1003 probeEvent
.setSymbol(rawData
.getTextContent());
1005 case MIStrings
.ADDRESS
:
1006 probeEvent
.setAddress(String
.format("%#016x", new BigInteger(rawData
.getTextContent()))); //$NON-NLS-1$
1008 case MIStrings
.OFFSET
:
1009 probeEvent
.setOffset(String
.format("%#016x", new BigInteger(rawData
.getTextContent()))); //$NON-NLS-1$
1018 events
.add(eventInfo
);
1023 static void getLoggerInfo(NodeList xmlEvents
, List
<ILoggerInfo
> loggers
, TraceDomainType domain
) throws ExecutionException
{
1024 ILoggerInfo loggerInfo
= null;
1025 for (int i
= 0; i
< xmlEvents
.getLength(); i
++) {
1026 NodeList rawInfos
= xmlEvents
.item(i
).getChildNodes();
1028 if (xmlEvents
.item(i
).getNodeName().equalsIgnoreCase(MIStrings
.EVENT
)) {
1029 Node rawName
= getFirstOf(rawInfos
, MIStrings
.NAME
);
1030 if (rawName
== null) {
1031 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
1034 loggerInfo
= new LoggerInfo(rawName
.getTextContent());
1035 loggerInfo
.setDomain(domain
);
1037 // Basic information
1038 for (int j
= 0; j
< rawInfos
.getLength(); j
++) {
1039 Node infoNode
= rawInfos
.item(j
);
1040 switch (infoNode
.getNodeName()) {
1041 case MIStrings
.LOGLEVEL_TYPE
:
1042 loggerInfo
.setLogLevelType(LogLevelType
.valueOfString(infoNode
.getTextContent()));
1044 case MIStrings
.LOGLEVEL
:
1045 loggerInfo
.setLogLevel(TraceJulLogLevel
.valueOfString(infoNode
.getTextContent()));
1047 case MIStrings
.ENABLED
:
1048 loggerInfo
.setState(TraceEnablement
.valueOfString(infoNode
.getTextContent()));
1055 loggers
.add(loggerInfo
);
1062 * a list of xml event_field element
1064 * a list of field generated by xml parsing
1065 * @throws ExecutionException
1066 * when parsing fail or required elements are missing
1068 private static void getFieldInfo(NodeList fieldsList
, List
<IFieldInfo
> fields
) throws ExecutionException
{
1069 IFieldInfo fieldInfo
= null;
1070 for (int i
= 0; i
< fieldsList
.getLength(); i
++) {
1071 Node field
= fieldsList
.item(i
);
1072 if (field
.getNodeName().equalsIgnoreCase(MIStrings
.EVENT_FIELD
)) {
1074 Node name
= getFirstOf(field
.getChildNodes(), MIStrings
.NAME
);
1076 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
1078 fieldInfo
= new FieldInfo(name
.getTextContent());
1080 // Populate the field information
1081 NodeList infos
= field
.getChildNodes();
1082 for (int j
= 0; j
< infos
.getLength(); j
++) {
1083 Node info
= infos
.item(j
);
1084 switch (info
.getNodeName()) {
1085 case MIStrings
.TYPE
:
1086 fieldInfo
.setFieldType(info
.getTextContent());
1092 fields
.add(fieldInfo
);
1098 * Retrieve the fist instance of a given node with tag name equal to tagName
1102 * the list of Node to search against
1104 * the tag name of the desired node
1105 * @return the first occurrence of a node with a tag name equals to tagName
1107 private static @Nullable Node
getFirstOf(NodeList nodeList
, String tagName
) {
1109 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
1110 if (Objects
.equals(nodeList
.item(i
).getNodeName(), tagName
)) {
1111 node
= nodeList
.item(i
);
1119 public @NonNull List
<String
> getContextList(IProgressMonitor monitor
) throws ExecutionException
{
1120 if (!isVersionSupported("2.8.0")) { //$NON-NLS-1$
1121 return super.getContextList(monitor
);
1124 ICommandInput command
= createCommand(LTTngControlServiceConstants
.COMMAND_ADD_CONTEXT
, LTTngControlServiceConstants
.OPTION_LIST
);
1125 ICommandResult result
= executeCommand(command
, monitor
);
1126 return result
.getOutput();