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