5f896b76c1cf5fba5b8d1d8f2a84ce23ded6fa54
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng2.control.core / src / org / eclipse / linuxtools / lttng2 / control / core / session / SessionConfigGenerator.java
1 /**********************************************************************
2 * Copyright (c) 2014 École Polytechnique de Montréal
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Guilliano Molaire - Initial API and implementation
11 *********************************************************************/
12 package org.eclipse.linuxtools.lttng2.control.core.session;
13
14 import java.io.File;
15 import java.io.IOException;
16 import java.net.URL;
17 import java.util.Set;
18
19 import javax.xml.XMLConstants;
20 import javax.xml.parsers.DocumentBuilder;
21 import javax.xml.parsers.DocumentBuilderFactory;
22 import javax.xml.parsers.ParserConfigurationException;
23 import javax.xml.transform.OutputKeys;
24 import javax.xml.transform.Source;
25 import javax.xml.transform.Transformer;
26 import javax.xml.transform.TransformerException;
27 import javax.xml.transform.TransformerFactory;
28 import javax.xml.transform.dom.DOMSource;
29 import javax.xml.transform.stream.StreamResult;
30 import javax.xml.transform.stream.StreamSource;
31 import javax.xml.validation.Schema;
32 import javax.xml.validation.SchemaFactory;
33 import javax.xml.validation.Validator;
34
35 import org.eclipse.core.runtime.IPath;
36 import org.eclipse.core.runtime.IStatus;
37 import org.eclipse.core.runtime.Status;
38 import org.eclipse.linuxtools.internal.lttng2.control.core.Activator;
39 import org.eclipse.linuxtools.internal.lttng2.control.core.model.IChannelInfo;
40 import org.eclipse.linuxtools.internal.lttng2.control.core.model.IDomainInfo;
41 import org.eclipse.linuxtools.internal.lttng2.control.core.model.IEventInfo;
42 import org.eclipse.linuxtools.internal.lttng2.control.core.model.ISessionInfo;
43 import org.eclipse.linuxtools.internal.lttng2.control.core.model.TraceEnablement;
44 import org.eclipse.linuxtools.internal.lttng2.control.core.model.TraceEventType;
45 import org.eclipse.linuxtools.internal.lttng2.control.core.model.TraceLogLevel;
46 import org.eclipse.linuxtools.internal.lttng2.control.core.model.TraceSessionState;
47 import org.eclipse.osgi.util.NLS;
48 import org.w3c.dom.Document;
49 import org.w3c.dom.Element;
50 import org.xml.sax.SAXException;
51 import org.xml.sax.SAXParseException;
52
53 /**
54 * Class for generating a session configuration file. A session configuration is
55 * used to configure a trace session. It is a XML formatted file that contains
56 * values defining the behavior of that specific trace session.
57 * <p>
58 * Kernel session configuration example:
59 *
60 * <pre>
61 * {@code
62 * <sessions>
63 * <session>
64 * <name>test_kernel</name>
65 * <domains>
66 * <domain>
67 * <type>KERNEL</type>
68 * <buffer_type>GLOBAL</buffer_type>
69 * <channels>
70 * <channel>
71 * <name>channel0</name>
72 * <enabled>false</enabled>
73 * <overwrite_mode>DISCARD</overwrite_mode>
74 * <subbuffer_size>262144</subbuffer_size>
75 * <subbuffer_count>4</subbuffer_count>
76 * <switch_timer_interval>0</switch_timer_interval>
77 * <read_timer_interval>200000</read_timer_interval>
78 * <output_type>SPLICE</output_type>
79 * <tracefile_size>0</tracefile_size>
80 * <tracefile_count>0</tracefile_count>
81 * <live_timer_interval>0</live_timer_interval>
82 * <events>
83 * <event>
84 * <enabled>true</enabled>
85 * <type>SYSCALL</type>
86 * </event>
87 * <event>
88 * <name>snd_soc_cache_sync</name>
89 * <enabled>true</enabled>
90 * <type>TRACEPOINT</type>
91 * </event>
92 * </events>
93 * </channel>
94 * </channels>
95 * </domain>
96 * </domains>
97 * <started>false</started>
98 * <output>
99 * <consumer_output>
100 * <enabled>true</enabled>
101 * <destination>
102 * <path>/home/user/lttng-traces/test_kernel</path>
103 * </destination>
104 * </consumer_output>
105 * </output>
106 * </session>
107 * </sessions>
108 * }
109 * </pre>
110 *
111 * </p>
112 *
113 * @author Guilliano Molaire
114 * @since 3.0
115 */
116 public final class SessionConfigGenerator {
117
118 /** The name of the session schema */
119 private static final String SESSION_XSD_FILENAME = "session.xsd"; //$NON-NLS-1$
120
121 /** The indent size used for the session configuration XML file */
122 private static final String INDENT_AMOUNT_PROPERTY_NAME = "{http://xml.apache.org/xslt}indent-amount"; //$NON-NLS-1$
123 private static final String INDENT_AMOUNT_PROPERTY_VALUE = "4"; //$NON-NLS-1$
124
125 /**
126 * Private constructor. The class should not be instantiated.
127 */
128 private SessionConfigGenerator() {
129 }
130
131 // ---------------------------------------------------------
132 // Methods to generate session configuration files
133 // ---------------------------------------------------------
134
135 /**
136 * Generates a session configuration file from a set of session information.
137 *
138 * @param sessions
139 * The session informations
140 * @param sessionFileDestination
141 * The path of the locally saved session configuration file
142 * @return The status of the session configuration generation
143 */
144 public static IStatus generateSessionConfig(Set<ISessionInfo> sessions, IPath sessionFileDestination) {
145 /* Parameters validation */
146 if (sessions == null || sessions.isEmpty()) {
147 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SessionConfigXML_InvalidSessionInfoList);
148 } else if (sessionFileDestination == null) {
149 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SessionConfigXML_InvalidTraceSessionPath);
150 }
151
152 /* Generate the session configuration file */
153 try {
154 Document sessionConfigDocument = generateSessionConfig(sessions);
155
156 if (sessionConfigDocument != null) {
157 saveSessionConfig(sessionConfigDocument, sessionFileDestination.toString());
158 } else {
159 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SessionConfigXML_SessionConfigGenerationError);
160 }
161 } catch (TransformerException | IllegalArgumentException | ParserConfigurationException e) {
162 Activator.getDefault().logError("Error generating the session configuration file: " + sessionFileDestination.toString(), e); //$NON-NLS-1$
163 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage());
164 }
165
166 return Status.OK_STATUS;
167 }
168
169 /**
170 * Generates a session configuration from a set of session informations.
171 *
172 * @param sessions
173 * The session informations
174 * @return The document with all session configuration nodes
175 * @throws IllegalArgumentException
176 * On an illegal argument inside sessions
177 * @throws ParserConfigurationException
178 * On an parser configuration error
179 */
180 private static Document generateSessionConfig(Iterable<ISessionInfo> sessions) throws IllegalArgumentException, ParserConfigurationException {
181 DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
182 DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
183
184 Document document = docBuilder.newDocument();
185
186 Element rootElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_SESSIONS);
187 document.appendChild(rootElement);
188
189 for (ISessionInfo session : sessions) {
190 /* All elements under "sessions" elements */
191 Element sessionElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_SESSION);
192
193 /* Contents of session element */
194 String enabled = session.getSessionState().equals(TraceSessionState.ACTIVE) ? SessionConfigStrings.CONFIG_STRING_TRUE : SessionConfigStrings.CONFIG_STRING_FALSE;
195
196 addElementContent(document, sessionElement, SessionConfigStrings.CONFIG_ELEMENT_NAME, session.getName());
197 addElementContent(document, sessionElement, SessionConfigStrings.CONFIG_ELEMENT_STARTED, enabled);
198
199 if (session.isSnapshotSession()) {
200 /* If it's a snapshot, we must add an attribute telling it is */
201 Element attributesElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_ATTRIBUTES);
202 addElementContent(document, attributesElement, SessionConfigStrings.CONFIG_ELEMENT_SNAPSHOT_MODE, SessionConfigStrings.CONFIG_STRING_TRUE);
203 sessionElement.appendChild(attributesElement);
204 }
205
206 sessionElement.appendChild(getDomainsElement(document, session));
207 sessionElement.appendChild(getOutputElement(document, session));
208 rootElement.appendChild(sessionElement);
209 }
210
211 return document;
212 }
213
214 // ---------------------------------------------------------
215 // Getters for each element of the configuration file
216 // ---------------------------------------------------------
217
218 /**
219 * Gets the 'domains' element after creating it.
220 *
221 * @param document
222 * The document in which the nodes are being added
223 * @param session
224 * The session informations
225 * @return The domains element as an XML element
226 */
227 private static Element getDomainsElement(Document document, ISessionInfo session) {
228 Element domainsElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_DOMAINS);
229
230 for (IDomainInfo domain : session.getDomains()) {
231 Element domainElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_DOMAIN);
232
233 /*
234 * Add everything specific to a domain
235 *
236 * TODO: We suppose here that domain is either kernel or UST. It
237 * will have to change if other domains are supported
238 */
239 String domainType = domain.isKernel() ? SessionConfigStrings.CONFIG_DOMAIN_TYPE_KERNEL : SessionConfigStrings.CONFIG_DOMAIN_TYPE_UST;
240 addElementContent(document, domainElement, SessionConfigStrings.CONFIG_ELEMENT_TYPE, domainType);
241
242 String bufferType = null;
243 switch (domain.getBufferType()) {
244 case BUFFER_PER_UID:
245 bufferType = SessionConfigStrings.CONFIG_BUFFER_TYPE_PER_UID;
246 break;
247 case BUFFER_PER_PID:
248 bufferType = SessionConfigStrings.CONFIG_BUFFER_TYPE_PER_PID;
249 break;
250 case BUFFER_SHARED:
251 bufferType = SessionConfigStrings.CONFIG_BUFFER_TYPE_GLOBAL;
252 break;
253 case BUFFER_TYPE_UNKNOWN:
254 default:
255 throw new IllegalArgumentException(Messages.SessionConfigXML_UnknownDomainBufferType);
256 }
257 addElementContent(document, domainElement, SessionConfigStrings.CONFIG_ELEMENT_DOMAIN_BUFFER_TYPE, bufferType);
258
259 /* Add the channels */
260 domainElement.appendChild(getChannelsElement(document, domain.isKernel(), domain.getChannels()));
261 domainsElement.appendChild(domainElement);
262 }
263
264 return domainsElement;
265 }
266
267 /**
268 * Gets the 'output' element after creating it. If the session is a
269 * snapshot, it will be composed of a snapshot outputs element. Otherwise,
270 * it will contain the consumer output element.
271 *
272 * @param document
273 * The document in which the nodes are being added
274 * @param session
275 * The session informations
276 * @return The output element as an XML node
277 */
278 private static Element getOutputElement(Document document, ISessionInfo session) {
279 Element outputElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_OUTPUT);
280
281 if (session.isSnapshotSession()) {
282 outputElement.appendChild(getSnapshotOuputsElement(document, session));
283 } else if (session.isStreamedTrace()) {
284 outputElement.appendChild(getNetOutputElement(document, session));
285 } else {
286 outputElement.appendChild(getConsumerOutputElement(document, session));
287 }
288
289 return outputElement;
290 }
291
292 /**
293 * Gets the 'channels' element after creating it.
294 *
295 * @param document
296 * The document in which the nodes are being added
297 * @param isKernel
298 * Is it a kernel domain type
299 * @param channels
300 * The channels to be added as elements
301 * @return The channels element as an XML element
302 */
303 private static Element getChannelsElement(Document document, boolean isKernel, IChannelInfo[] channels) {
304 Element channelsElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_CHANNELS);
305
306 for (IChannelInfo channel : channels) {
307 Element channelElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_CHANNEL);
308
309 /* Add everything related to a channel */
310 addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_NAME, channel.getName());
311
312 String overwriteMode = channel.isOverwriteMode() ? SessionConfigStrings.CONFIG_OVERWRITE_MODE_OVERWRITE : SessionConfigStrings.CONFIG_OVERWRITE_MODE_DISCARD;
313 String enabled = channel.getState().equals(TraceEnablement.ENABLED) ? SessionConfigStrings.CONFIG_STRING_TRUE : SessionConfigStrings.CONFIG_STRING_FALSE;
314
315 addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_ENABLED, enabled);
316 addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_OVERWRITE_MODE, overwriteMode);
317 addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_SUBBUFFER_SIZE, channel.getSubBufferSize());
318 addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_SUBBUFFER_COUNT, channel.getNumberOfSubBuffers());
319 addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_SWITCH_TIMER_INTERVAL, channel.getSwitchTimer());
320 addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_READ_TIMER_INTERVAL, channel.getReadTimer());
321
322 String outputType = channel.getOutputType().startsWith(SessionConfigStrings.CONFIG_OUTPUT_TYPE_MMAP) ?
323 outputType = SessionConfigStrings.CONFIG_OUTPUT_TYPE_MMAP : SessionConfigStrings.CONFIG_OUTPUT_TYPE_SPLICE;
324 addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_OUTPUT_TYPE, outputType);
325 addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_TRACEFILE_SIZE, channel.getMaxSizeTraceFiles());
326 addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_TRACEFILE_COUNT, channel.getMaxNumberTraceFiles());
327
328 /*
329 * TODO: Replace the 0 value by the channel live timer property from
330 * SessionInfo once live session tracing is supported
331 */
332 addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_LIVE_TIMER_INTERVAL, SessionConfigStrings.CONFIG_STRING_ZERO);
333
334 /* Add the events */
335 channelElement.appendChild(getEventsElement(document, isKernel, channel.getEvents()));
336 channelsElement.appendChild(channelElement);
337 }
338
339 return channelsElement;
340 }
341
342 /**
343 * Gets the 'events' element after creating it. It is composed of the event
344 * informations from a list of IEventInfo.
345 *
346 * @param document
347 * The document in which the nodes are being added
348 * @param isKernel
349 * Is the domain type kernel
350 * @param events
351 * The event informations to be added
352 * @return An element containing all the event informations as XML elements
353 */
354 private static Element getEventsElement(Document document, boolean isKernel, IEventInfo[] events) {
355 Element eventsElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_EVENTS);
356
357 for (IEventInfo event : events) {
358 Element eventElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_EVENT);
359
360 /* Enabled attribute */
361 String enabled = event.getState().equals(TraceEnablement.ENABLED) ? SessionConfigStrings.CONFIG_STRING_TRUE : SessionConfigStrings.CONFIG_STRING_FALSE;
362
363 /* Add the attributes to the event node */
364 addElementContent(document, eventElement, SessionConfigStrings.CONFIG_ELEMENT_NAME, event.getName());
365 addElementContent(document, eventElement, SessionConfigStrings.CONFIG_ELEMENT_ENABLED, enabled);
366 TraceEventType eventType = event.getEventType();
367 if (!eventType.equals(TraceEventType.UNKNOWN)) {
368 addElementContent(document, eventElement, SessionConfigStrings.CONFIG_ELEMENT_TYPE, eventType.getInName().toUpperCase());
369 } else {
370 throw new IllegalArgumentException(Messages.SessionConfigXML_UnknownEventType);
371 }
372
373 /* Specific to UST session config: the log level */
374 if (!isKernel && !event.getLogLevel().equals(TraceLogLevel.LEVEL_UNKNOWN)) {
375 addElementContent(document, eventElement, SessionConfigStrings.CONFIG_ELEMENT_LOGLEVEL, event.getLogLevel().ordinal());
376 }
377
378 /* Add the node to the parent node events */
379 eventsElement.appendChild(eventElement);
380 }
381
382 return eventsElement;
383 }
384
385 /**
386 * Gets the 'consumer_output' element after creating it.
387 *
388 * @param document
389 * The document in which the nodes are being added
390 * @param session
391 * The session informations
392 * @return The consumer output element with his informations as XML elements
393 */
394 private static Element getConsumerOutputElement(Document document, ISessionInfo session) {
395 Element consumerOutputElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_CONSUMER_OUTPUT);
396 Element destinationElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_DESTINATION);
397
398 /* Value of consumer output element */
399 addElementContent(document, consumerOutputElement, SessionConfigStrings.CONFIG_ELEMENT_ENABLED, SessionConfigStrings.CONFIG_STRING_TRUE);
400
401 if (session.isStreamedTrace()) {
402 /* If it is a streamed session, add the net output element */
403 destinationElement.appendChild(getNetOutputElement(document, session));
404 } else {
405 addElementContent(document, destinationElement, SessionConfigStrings.CONFIG_ELEMENT_PATH, session.getSessionPath());
406 }
407
408 consumerOutputElement.appendChild(destinationElement);
409 return consumerOutputElement;
410 }
411
412 /**
413 * Gets the 'net_output' element after creating it. It is composed of the
414 * control and data URIs.
415 *
416 * @param document
417 * The document in which the nodes are being added
418 * @param session
419 * The session informations
420 * @return The net output element
421 */
422 private static Element getNetOutputElement(Document document, ISessionInfo session) {
423 Element netOutputElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_NET_OUTPUT);
424
425 String networkUrl = session.getNetworkUrl();
426 String controlUri = networkUrl == null ? session.getControlUrl() : networkUrl;
427 String dataUri = networkUrl == null ? session.getDataUrl() : networkUrl;
428 addElementContent(document, netOutputElement, SessionConfigStrings.CONFIG_ELEMENT_CONTROL_URI, controlUri);
429 addElementContent(document, netOutputElement, SessionConfigStrings.CONFIG_ELEMENT_DATA_URI, dataUri);
430
431 return netOutputElement;
432 }
433
434 /**
435 * Gets the 'snapshot_outputs' element after creating it.
436 *
437 * @param document
438 * The document in which the nodes are being added
439 * @param session
440 * The session informations
441 * @return The snapshot outputs element with snapshot informations as XML
442 * elements
443 */
444 private static Element getSnapshotOuputsElement(Document document, ISessionInfo session) {
445 Element snapshotOutputsElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_SNAPSHOT_OUTPUTS);
446 Element outputElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_OUTPUT);
447
448 /* Add the name of the snapshot and the max size element */
449 addElementContent(document, outputElement, SessionConfigStrings.CONFIG_ELEMENT_NAME, session.getSnapshotInfo().getName());
450
451 /*
452 * TODO: find the proper max size value of output element. For now it is
453 * set to the default 0 value which means unlimited for lttng.
454 */
455 addElementContent(document, outputElement, SessionConfigStrings.CONFIG_ELEMENT_MAX_SIZE, SessionConfigStrings.CONFIG_STRING_ZERO);
456 outputElement.appendChild(getConsumerOutputElement(document, session));
457
458 snapshotOutputsElement.appendChild(outputElement);
459 return snapshotOutputsElement;
460 }
461
462 // ---------------------------------------------------------
463 // Utilities
464 // ---------------------------------------------------------
465
466 /**
467 * Validates the session configuration file against its schema.
468 *
469 * @param sessionFile
470 * The session configuration file
471 * @return The status of the validation
472 */
473 public static IStatus sessionValidate(File sessionFile) {
474 URL url = SessionConfigGenerator.class.getResource(SESSION_XSD_FILENAME);
475 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
476 Source xmlSource = new StreamSource(sessionFile);
477
478 try {
479 Schema schema = schemaFactory.newSchema(url);
480 Validator validator = schema.newValidator();
481 validator.validate(xmlSource);
482 } catch (SAXParseException e) {
483 String error = NLS.bind(Messages.SessionConfigXML_XmlParseError, e.getLineNumber(), e.getLocalizedMessage());
484 Activator.getDefault().logError(error);
485 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, error, e);
486 } catch (SAXException e) {
487 String error = NLS.bind(Messages.SessionConfigXML_XmlValidationError, e.getLocalizedMessage());
488 Activator.getDefault().logError(error);
489 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, error, e);
490 } catch (IOException e) {
491 String error = Messages.SessionConfigXML_XmlValidateError;
492 Activator.getDefault().logError("IO exception occurred", e); //$NON-NLS-1$
493 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, error, e);
494 }
495 return Status.OK_STATUS;
496 }
497
498 /**
499 * Saves the session configuration into a XML file.
500 *
501 * @param document
502 * The document representing the session configuration file
503 * @param destination
504 * The path of the locally saved session configuration file
505 * @throws TransformerException
506 * On an transformation process
507 */
508 private static void saveSessionConfig(Document document, String destination) throws TransformerException {
509 /* Write the content into a XML file */
510 TransformerFactory transformerFactory = TransformerFactory.newInstance();
511 Transformer transformer = transformerFactory.newTransformer();
512
513 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
514 transformer.setOutputProperty(INDENT_AMOUNT_PROPERTY_NAME, INDENT_AMOUNT_PROPERTY_VALUE);
515
516 DOMSource source = new DOMSource(document);
517 StreamResult result = new StreamResult(new File(destination));
518
519 transformer.transform(source, result);
520 }
521
522 /**
523 * Adds to a parent node an element with his content.
524 *
525 * @param document
526 * The document in which the nodes are being added
527 * @param parent
528 * The parent node that contains the element and his content
529 * @param elementName
530 * The element container name
531 * @param elementContent
532 * The content itself
533 */
534 private static void addElementContent(Document document, Element parent, String elementName, Object elementContent) {
535 Element contentElement = document.createElement(elementName);
536 contentElement.appendChild(document.createTextNode(elementContent.toString()));
537 parent.appendChild(contentElement);
538 }
539 }
This page took 0.044118 seconds and 4 git commands to generate.