1 /**********************************************************************
2 * Copyright (c) 2014 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 **********************************************************************/
13 package org
.eclipse
.linuxtools
.internal
.lttng2
.control
.ui
.views
.service
;
15 import java
.io
.IOException
;
16 import java
.io
.StringReader
;
18 import java
.util
.ArrayList
;
19 import java
.util
.List
;
20 import java
.util
.regex
.Matcher
;
22 import javax
.xml
.parsers
.DocumentBuilder
;
23 import javax
.xml
.parsers
.DocumentBuilderFactory
;
24 import javax
.xml
.parsers
.ParserConfigurationException
;
26 import org
.eclipse
.core
.commands
.ExecutionException
;
27 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
28 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.IBaseEventInfo
;
29 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.IChannelInfo
;
30 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.IDomainInfo
;
31 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.IFieldInfo
;
32 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.ISessionInfo
;
33 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.ISnapshotInfo
;
34 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.IUstProviderInfo
;
35 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.LogLevelType
;
36 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.TraceLogLevel
;
37 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.impl
.BaseEventInfo
;
38 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.impl
.FieldInfo
;
39 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.impl
.SessionInfo
;
40 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.impl
.SnapshotInfo
;
41 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.core
.model
.impl
.UstProviderInfo
;
42 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.ui
.views
.handlers
.XmlMiValidationErrorHandler
;
43 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.ui
.views
.messages
.Messages
;
44 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.ui
.views
.remote
.ICommandResult
;
45 import org
.eclipse
.linuxtools
.internal
.lttng2
.control
.ui
.views
.remote
.ICommandShell
;
46 import org
.w3c
.dom
.Document
;
47 import org
.w3c
.dom
.Node
;
48 import org
.w3c
.dom
.NodeList
;
49 import org
.xml
.sax
.InputSource
;
50 import org
.xml
.sax
.SAXException
;
53 * Service for sending LTTng trace control commands to remote host via machine
56 * @author Jonathan Rajotte
58 public class LTTngControlServiceMI
extends LTTngControlService
{
60 // ------------------------------------------------------------------------
62 // ------------------------------------------------------------------------
64 private final DocumentBuilder fDocumentBuilder
;
66 // ------------------------------------------------------------------------
68 // ------------------------------------------------------------------------
74 * the command shell implementation to use
76 * the xsd schema file for validation
77 * @throws ExecutionException
78 * if the creation of the Schema and DocumentBuilder objects
81 public LTTngControlServiceMI(ICommandShell shell
, URL xsdUrl
) throws ExecutionException
{
84 DocumentBuilderFactory docBuilderFactory
= DocumentBuilderFactory
.newInstance();
85 docBuilderFactory
.setValidating(false);
87 // TODO: Add xsd validation for machine interface via mi_lttng.xsd from LTTng
89 fDocumentBuilder
= docBuilderFactory
.newDocumentBuilder();
90 } catch (ParserConfigurationException e
) {
91 throw new ExecutionException(Messages
.TraceControl_XmlDocumentBuilderError
, e
);
94 fDocumentBuilder
.setErrorHandler(new XmlMiValidationErrorHandler());
99 * Generate a Document object from an array of String.
102 * array of strings representing an xml input
103 * @return Document generated from strings input
104 * @throws ExecutionException
105 * when parsing has failed
107 private Document
getDocumentFromStrings(String
[] xmlStrings
) throws ExecutionException
{
108 StringBuilder concatenedString
= new StringBuilder();
109 for (String string
: xmlStrings
) {
110 concatenedString
.append(string
);
112 InputSource stream
= new InputSource(new StringReader(concatenedString
.toString()));
116 document
= fDocumentBuilder
.parse(stream
);
117 } catch (SAXException
| IOException e
) {
118 throw new ExecutionException(Messages
.TraceControl_XmlParsingError
, e
);
125 * Parse, populate and set the internal LTTngVersion variable
128 * the mi xml output of lttng version
129 * @throws ExecutionException
130 * when xml extraction fail
132 public void setVersion(String
[] xmlOutput
) throws ExecutionException
{
133 Document doc
= getDocumentFromStrings(xmlOutput
);
134 NodeList element
= doc
.getElementsByTagName(MIStrings
.VERSION
);
138 String license
= ""; //$NON-NLS-1$
139 String commit
= ""; //$NON-NLS-1$
140 String name
= ""; //$NON-NLS-1$
141 String description
= ""; //$NON-NLS-1$
142 String url
= ""; //$NON-NLS-1$
143 String fullVersion
= ""; //$NON-NLS-1$
144 if (element
.getLength() == 1) {
145 NodeList child
= element
.item(0).getChildNodes();
146 // Get basic information
147 for (int i
= 0; i
< child
.getLength(); i
++) {
148 Node node
= child
.item(i
);
149 switch (node
.getNodeName()) {
150 case MIStrings
.VERSION_MAJOR
:
151 major
= Integer
.parseInt(node
.getTextContent());
153 case MIStrings
.VERSION_MINOR
:
154 minor
= Integer
.parseInt(node
.getTextContent());
156 case MIStrings
.VERSION_PATCH_LEVEL
:
157 patchLevel
= Integer
.parseInt(node
.getTextContent());
159 case MIStrings
.VERSION_COMMIT
:
160 commit
= node
.getTextContent();
162 case MIStrings
.VERSION_DESCRIPTION
:
163 description
= node
.getTextContent();
165 case MIStrings
.VERSION_LICENSE
:
166 license
= node
.getTextContent();
168 case MIStrings
.VERSION_NAME
:
169 name
= node
.getTextContent();
171 case MIStrings
.VERSION_STR
:
172 fullVersion
= node
.getTextContent();
174 case MIStrings
.VERSION_WEB
:
175 url
= node
.getTextContent();
181 setVersion(new LttngVersion(major
, minor
, patchLevel
, license
, commit
, name
, description
, url
, fullVersion
));
183 throw new ExecutionException(Messages
.TraceControl_UnsupportedVersionError
);
188 public String
[] getSessionNames(IProgressMonitor monitor
) throws ExecutionException
{
189 StringBuffer command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
);
190 ICommandResult result
= executeCommand(command
.toString(), monitor
);
192 Document doc
= getDocumentFromStrings(result
.getOutput());
194 NodeList elements
= doc
.getElementsByTagName(MIStrings
.NAME
);
196 ArrayList
<String
> retArray
= new ArrayList
<>();
197 for (int i
= 0; i
< elements
.getLength(); i
++) {
198 Node node
= elements
.item(i
);
199 if (node
.getParentNode().getNodeName().equalsIgnoreCase(MIStrings
.SESSION
)) {
200 retArray
.add(node
.getTextContent());
203 return retArray
.toArray(new String
[retArray
.size()]);
207 public ISessionInfo
getSession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
208 StringBuffer command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST
, sessionName
);
209 ICommandResult result
= executeCommand(command
.toString(), monitor
);
211 ISessionInfo sessionInfo
= new SessionInfo(sessionName
);
212 Document document
= getDocumentFromStrings(result
.getOutput());
214 NodeList sessionsNode
= document
.getElementsByTagName(MIStrings
.SESSION
);
215 // There should be only one session
216 if (sessionsNode
.getLength() != 1) {
217 throw new ExecutionException(Messages
.TraceControl_MiInvalidNumberOfElementError
);
220 // Populate session information
221 NodeList rawSessionInfos
= sessionsNode
.item(0).getChildNodes();
222 for (int i
= 0; i
< rawSessionInfos
.getLength(); i
++) {
223 Node rawInfo
= rawSessionInfos
.item(i
);
224 switch (rawInfo
.getNodeName()) {
226 sessionInfo
.setSessionPath(rawInfo
.getTextContent());
228 case MIStrings
.ENABLED
:
229 sessionInfo
.setSessionState(rawInfo
.getTextContent());
231 case MIStrings
.SNAPSHOT_MODE
:
232 if (rawInfo
.getTextContent().equals(LTTngControlServiceConstants
.TRUE_NUMERICAL
)) {
233 // real name will be set later
234 ISnapshotInfo snapshotInfo
= new SnapshotInfo(""); //$NON-NLS-1$
235 sessionInfo
.setSnapshotInfo(snapshotInfo
);
238 case MIStrings
.LIVE_TIMER_INTERVAL
:
239 // TODO : live mode not supported yet in TMF:lttng-control
241 case MIStrings
.DOMAINS
:
242 // Extract the domains node
243 NodeList rawDomains
= rawInfo
.getChildNodes();
244 IDomainInfo domain
= null;
245 for (int j
= 0; j
< rawDomains
.getLength(); j
++) {
246 if (rawDomains
.item(j
).getNodeName().equalsIgnoreCase(MIStrings
.DOMAIN
)) {
247 domain
= parseDomain(rawDomains
.item(j
));
248 sessionInfo
.addDomain(domain
);
257 if (!sessionInfo
.isSnapshotSession()) {
258 Matcher matcher
= LTTngControlServiceConstants
.TRACE_NETWORK_PATTERN
.matcher(sessionInfo
.getSessionPath());
259 if (matcher
.matches()) {
260 sessionInfo
.setStreamedTrace(true);
265 // Fetch the snapshot info
266 if (sessionInfo
.isSnapshotSession()) {
267 ISnapshotInfo snapshot
= getSnapshotInfo(sessionName
, monitor
);
268 sessionInfo
.setSnapshotInfo(snapshot
);
277 * @return {@link IDomainInfo}
279 protected IDomainInfo
parseDomain(Node domain
) {
285 public ISnapshotInfo
getSnapshotInfo(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
291 public List
<IBaseEventInfo
> getKernelProvider(IProgressMonitor monitor
) throws ExecutionException
{
292 StringBuffer command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST_KERNEL
);
293 ICommandResult result
= executeCommand(command
.toString(), monitor
, false);
294 List
<IBaseEventInfo
> events
= new ArrayList
<>();
296 if (isError(result
)) {
300 Document document
= getDocumentFromStrings(result
.getOutput());
301 NodeList rawEvents
= document
.getElementsByTagName(MIStrings
.EVENT
);
302 parseXmlEvents(rawEvents
, events
);
307 public List
<IUstProviderInfo
> getUstProvider(IProgressMonitor monitor
) throws ExecutionException
{
308 StringBuffer command
= createCommand(LTTngControlServiceConstants
.COMMAND_LIST_UST
);
310 command
.append(LTTngControlServiceConstants
.OPTION_FIELDS
);
313 ICommandResult result
= executeCommand(command
.toString(), monitor
, false);
314 List
<IUstProviderInfo
> allProviders
= new ArrayList
<>();
316 if (isError(result
)) {
320 Document document
= getDocumentFromStrings(result
.getOutput());
321 NodeList rawProviders
= document
.getElementsByTagName(MIStrings
.PID
);
323 IUstProviderInfo providerInfo
= null;
325 for (int i
= 0; i
< rawProviders
.getLength(); i
++) {
326 Node provider
= rawProviders
.item(i
);
327 Node name
= getFirstOf(provider
.getChildNodes(), MIStrings
.NAME
);
329 throw new ExecutionException(Messages
.TraceControl_MiInvalidProviderError
);
331 providerInfo
= new UstProviderInfo(name
.getTextContent());
334 NodeList infos
= provider
.getChildNodes();
335 for (int j
= 0; j
< infos
.getLength(); j
++) {
336 Node info
= infos
.item(j
);
337 switch (info
.getNodeName()) {
338 case MIStrings
.PID_ID
:
339 providerInfo
.setPid(Integer
.parseInt(info
.getTextContent()));
341 case MIStrings
.EVENTS
:
342 List
<IBaseEventInfo
> events
= new ArrayList
<>();
343 NodeList rawEvents
= info
.getChildNodes();
344 parseXmlEvents(rawEvents
, events
);
345 providerInfo
.setEvents(events
);
351 allProviders
.add(providerInfo
);
358 public ISessionInfo
createSession(ISessionInfo sessionInfo
, IProgressMonitor monitor
) throws ExecutionException
{
359 // TODO Auto-generated method stub
364 public void destroySession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
365 // TODO Auto-generated method stub
370 public void startSession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
371 // TODO Auto-generated method stub
376 public void stopSession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
377 // TODO Auto-generated method stub
382 public void enableChannels(String sessionName
, List
<String
> channelNames
, boolean isKernel
, IChannelInfo info
, IProgressMonitor monitor
) throws ExecutionException
{
383 // TODO Auto-generated method stub
388 public void disableChannels(String sessionName
, List
<String
> channelNames
, boolean isKernel
, IProgressMonitor monitor
) throws ExecutionException
{
389 // TODO Auto-generated method stub
394 public void enableEvents(String sessionName
, String channelName
, List
<String
> eventNames
, boolean isKernel
, String filterExpression
, IProgressMonitor monitor
) throws ExecutionException
{
395 // TODO Auto-generated method stub
400 public void enableSyscalls(String sessionName
, String channelName
, IProgressMonitor monitor
) throws ExecutionException
{
401 // TODO Auto-generated method stub
406 public void enableProbe(String sessionName
, String channelName
, String eventName
, boolean isFunction
, String probe
, IProgressMonitor monitor
) throws ExecutionException
{
407 // TODO Auto-generated method stub
412 public void enableLogLevel(String sessionName
, String channelName
, String eventName
, LogLevelType logLevelType
, TraceLogLevel level
, String filterExpression
, IProgressMonitor monitor
) throws ExecutionException
{
413 // TODO Auto-generated method stub
418 public void disableEvent(String sessionName
, String channelName
, List
<String
> eventNames
, boolean isKernel
, IProgressMonitor monitor
) throws ExecutionException
{
419 // TODO Auto-generated method stub
424 public List
<String
> getContextList(IProgressMonitor monitor
) throws ExecutionException
{
425 // TODO Auto-generated method stub
430 public void addContexts(String sessionName
, String channelName
, String eventName
, boolean isKernel
, List
<String
> contexts
, IProgressMonitor monitor
) throws ExecutionException
{
431 // TODO Auto-generated method stub
436 public void calibrate(boolean isKernel
, IProgressMonitor monitor
) throws ExecutionException
{
437 // TODO Auto-generated method stub
442 public void recordSnapshot(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
443 // TODO Auto-generated method stub
448 public void runCommands(IProgressMonitor monitor
, List
<String
> commands
) throws ExecutionException
{
449 // TODO Auto-generated method stub
455 * array of string that make up a command line
456 * @return string buffer with created command line
459 protected StringBuffer
createCommand(String
... strings
) {
460 StringBuffer command
= new StringBuffer();
461 command
.append(LTTngControlServiceConstants
.CONTROL_COMMAND_MI_XML
);
462 command
.append(getTracingGroupOption());
463 for (String string
: strings
) {
464 command
.append(string
);
471 * a Node list of xml event element
473 * list of event generated by the parsing of the xml event
475 * @throws ExecutionException
476 * when a raw event is not a complete/valid xml event
478 protected void parseXmlEvents(NodeList xmlEvents
, List
<IBaseEventInfo
> events
) throws ExecutionException
{
479 IBaseEventInfo eventInfo
= null;
480 for (int i
= 0; i
< xmlEvents
.getLength(); i
++) {
481 NodeList rawInfos
= xmlEvents
.item(i
).getChildNodes();
483 if (xmlEvents
.item(i
).getNodeName().equalsIgnoreCase(MIStrings
.EVENT
)) {
484 Node rawName
= getFirstOf(rawInfos
, MIStrings
.NAME
);
485 if (rawName
== null) {
486 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
488 eventInfo
= new BaseEventInfo(rawName
.getTextContent());
490 // Populate the event
491 for (int j
= 0; j
< rawInfos
.getLength(); j
++) {
492 Node infoNode
= rawInfos
.item(j
);
493 switch (infoNode
.getNodeName()) {
495 eventInfo
.setEventType(infoNode
.getTextContent());
497 case MIStrings
.LOGLEVEL
:
498 eventInfo
.setLogLevel(infoNode
.getTextContent());
500 case MIStrings
.EVENT_FIELDS
:
501 List
<IFieldInfo
> fields
= new ArrayList
<>();
502 getFieldInfo(infoNode
.getChildNodes(), fields
);
503 eventInfo
.setFields(fields
);
509 events
.add(eventInfo
);
516 * a list of xml event_field element
518 * a list of field generated by xml parsing
519 * @throws ExecutionException
520 * when parsing fail or required elements are missing
522 private static void getFieldInfo(NodeList fieldsList
, List
<IFieldInfo
> fields
) throws ExecutionException
{
523 IFieldInfo fieldInfo
= null;
524 for (int i
= 0; i
< fieldsList
.getLength(); i
++) {
525 Node field
= fieldsList
.item(i
);
526 if (field
.getNodeName().equalsIgnoreCase(MIStrings
.EVENT_FIELD
)) {
528 Node name
= getFirstOf(field
.getChildNodes(), MIStrings
.NAME
);
530 throw new ExecutionException(Messages
.TraceControl_MiMissingRequiredError
);
532 fieldInfo
= new FieldInfo(name
.getTextContent());
534 // Populate the field information
535 NodeList infos
= field
.getChildNodes();
536 for (int j
= 0; j
< infos
.getLength(); j
++) {
537 Node info
= infos
.item(j
);
538 switch (info
.getNodeName()) {
540 fieldInfo
.setFieldType(info
.getTextContent());
546 fields
.add(fieldInfo
);
552 * Retrieve the fist instance of a given node with tag name equal to tagName
556 * the list of Node to search against
558 * the tag name of the desired node
559 * @return the first occurrence of a node with a tag name equals to tagName
561 private static Node
getFirstOf(NodeList nodeList
, String tagName
) {
563 for (int i
= 0; i
< nodeList
.getLength(); i
++) {
564 if (nodeList
.item(i
).getNodeName() == tagName
) {
565 node
= nodeList
.item(i
);