1 /**********************************************************************
2 * Copyright (c) 2012 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 * Bernd Hufmann - Initial API and implementation
11 **********************************************************************/
12 package org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.service
;
14 import java
.util
.ArrayList
;
15 import java
.util
.List
;
16 import java
.util
.regex
.Matcher
;
17 import java
.util
.regex
.Pattern
;
19 import org
.eclipse
.core
.commands
.ExecutionException
;
20 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
21 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
22 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.Messages
;
23 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.IBaseEventInfo
;
24 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.IChannelInfo
;
25 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.IDomainInfo
;
26 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.IEventInfo
;
27 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.ISessionInfo
;
28 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.IUstProviderInfo
;
29 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.TraceLogLevel
;
30 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.BaseEventInfo
;
31 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.ChannelInfo
;
32 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.DomainInfo
;
33 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.EventInfo
;
34 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.SessionInfo
;
35 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.UstProviderInfo
;
38 * <b><u>LTTngControlService</u></b>
40 * Service for sending LTTng trace control commands to remote host.
43 public class LTTngControlService
implements ILttngControlService
{
44 // ------------------------------------------------------------------------
46 // ------------------------------------------------------------------------
49 * The lttng tools command.
51 private final static String CONTROL_COMMAND
= "lttng"; //$NON-NLS-1$
53 * Command: lttng list.
55 private final static String COMMAND_LIST
= CONTROL_COMMAND
+ " list "; //$NON-NLS-1$
57 * Command to list kernel tracer information.
59 private final static String COMMAND_LIST_KERNEL
= COMMAND_LIST
+ "-k"; //$NON-NLS-1$
61 * Command to list user space trace information.
63 private final static String COMMAND_LIST_UST
= COMMAND_LIST
+ "-u"; //$NON-NLS-1$
67 * Pattern to match for error output
69 private final static Pattern ERROR_PATTERN
= Pattern
.compile("\\s*Error\\:.*"); //$NON-NLS-1$
71 * Pattern to match for session information (lttng list)
73 private final static Pattern SESSION_PATTERN
= Pattern
.compile("\\s+(\\d+)\\)\\s+(.*)\\s+\\((.*)\\)\\s+\\[(active|inactive)\\].*"); //$NON-NLS-1$
75 * Pattern to match for session information (lttng list <session>)
77 private final static Pattern TRACE_SESSION_PATTERN
= Pattern
.compile("\\s*Tracing\\s+session\\s+(.*)\\:\\s+\\[(active|inactive)\\].*"); //$NON-NLS-1$
79 * Pattern to match for session path information (lttng list <session>)
81 private final static Pattern TRACE_SESSION_PATH_PATTERN
= Pattern
.compile("\\s*Trace\\s+path\\:\\s+(.*)"); //$NON-NLS-1$
83 * Pattern to match for kernel domain information (lttng list <session>)
85 private final static Pattern DOMAIN_KERNEL_PATTERN
= Pattern
.compile("=== Domain: Kernel ==="); //$NON-NLS-1$
87 * Pattern to match for ust domain information (lttng list <session>)
89 private final static Pattern DOMAIN_UST_GLOBAL_PATTERN
= Pattern
.compile("=== Domain: UST global ==="); //$NON-NLS-1$
91 * Pattern to match for channels section (lttng list <session>)
93 private final static Pattern CHANNELS_SECTION_PATTERN
= Pattern
.compile("\\s*Channels\\:"); //$NON-NLS-1$
95 * Pattern to match for channel information (lttng list <session>)
97 private final static Pattern CHANNEL_PATTERN
= Pattern
.compile("\\s*-\\s+(.*)\\:\\s+\\[(enabled|disabled)\\]"); //$NON-NLS-1$
99 * Pattern to match for events section information (lttng list <session>)
101 private final static Pattern EVENT_SECTION_PATTERN
= Pattern
.compile("\\s*Events\\:"); //$NON-NLS-1$
103 * Pattern to match for event information (no enabled events) (lttng list
106 // private final static String EVENT_NONE_PATTERN = "\\s+None"; //$NON-NLS-1$
108 * Pattern to match for event information (lttng list <session>)
110 private final static Pattern EVENT_PATTERN
= Pattern
.compile("\\s+(.*)\\s+\\(loglevel:\\s+(.*)\\s+\\(\\d*\\)\\)\\s+\\(type:\\s+(.*)\\)\\s+\\[(enabled|disabled)\\].*"); //$NON-NLS-1$
112 * Pattern to match a wildcarded event information (lttng list <session>)
114 private final static Pattern WILDCARD_EVENT_PATTERN
= Pattern
.compile("\\s+(.*)\\s+\\(type:\\s+(.*)\\)\\s+\\[(enabled|disabled)\\].*"); //$NON-NLS-1$
116 * Pattern to match for channel (overwite mode) information (lttng list
119 private final static Pattern OVERWRITE_MODE_ATTRIBUTE
= Pattern
.compile("\\s+overwrite\\s+mode\\:.*"); //$NON-NLS-1$
121 * Pattern to match indicating false for overwrite mode
123 private final static String OVERWRITE_MODE_ATTRIBUTE_FALSE
= "0"; //$NON-NLS-1$
125 * Pattern to match for channel (sub-buffer size) information (lttng list
128 private final static Pattern SUBBUFFER_SIZE_ATTRIBUTE
= Pattern
.compile("\\s+subbufers\\s+size\\:.*"); //$NON-NLS-1$
130 * Pattern to match for channel (number of sub-buffers) information (lttng
133 private final static Pattern NUM_SUBBUFFERS_ATTRIBUTE
= Pattern
.compile("\\s+number\\s+of\\s+subbufers\\:.*"); //$NON-NLS-1$
135 * Pattern to match for channel (switch timer) information (lttng list
138 private final static Pattern SWITCH_TIMER_ATTRIBUTE
= Pattern
.compile("\\s+switch\\s+timer\\s+interval\\:.*"); //$NON-NLS-1$
140 * Pattern to match for channel (read timer) information (lttng list
143 private final static Pattern READ_TIMER_ATTRIBUTE
= Pattern
.compile("\\s+read\\s+timer\\s+interval\\:.*"); //$NON-NLS-1$
145 * Pattern to match for channel (output type) information (lttng list
148 private final static Pattern OUTPUT_ATTRIBUTE
= Pattern
.compile("\\s+output\\:.*"); //$NON-NLS-1$
150 * Pattern to match for provider information (lttng list -k/-u)
152 private final static Pattern PROVIDER_EVENT_PATTERN
= Pattern
.compile("\\s*(.*)\\s+\\(loglevel:\\s+(.*)\\s+\\(\\d*\\)\\)\\s+\\(type:\\s+(.*)\\)"); //$NON-NLS-1$
154 * Pattern to match for UST provider information (lttng list -u)
156 private final static Pattern UST_PROVIDER_PATTERN
= Pattern
.compile("\\s*PID\\:\\s+(\\d+)\\s+-\\s+Name\\:\\s+(.*)"); //$NON-NLS-1$
158 // ------------------------------------------------------------------------
160 // ------------------------------------------------------------------------
162 * The command shell implementation
164 private ICommandShell fCommandShell
= null;
166 // ------------------------------------------------------------------------
168 // ------------------------------------------------------------------------
174 * - the command shell implementation to use
176 public LTTngControlService(ICommandShell shell
) {
177 fCommandShell
= shell
;
180 // ------------------------------------------------------------------------
182 // ------------------------------------------------------------------------
188 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
192 public String
[] getSessionNames() throws ExecutionException
{
193 return getSessionNames(new NullProgressMonitor());
200 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
201 * #getSessionNames(org.eclipse.core.runtime.IProgressMonitor)
204 public String
[] getSessionNames(IProgressMonitor monitor
) throws ExecutionException
{
206 String command
= COMMAND_LIST
;
207 ICommandResult result
= fCommandShell
.executeCommand(command
, monitor
);
209 if (isError(result
)) {
210 // TODO: no session available shouldn't be an error!
211 if (result
.getOutput().length
> 0 && ERROR_PATTERN
.matcher(result
.getOutput()[0]).matches()) {
212 // no sessions available
213 return new String
[0];
215 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + formatOutput(result
.getOutput())); //$NON-NLS-1$ //$NON-NLS-2$
219 // Available tracing sessions:
220 // 1) mysession1 (/home/user/lttng-traces/mysession1-20120123-083928)
222 // 2) mysession (/home/user/lttng-traces/mysession-20120123-083318)
225 // Use lttng list <session_name> for more details
227 ArrayList
<String
> retArray
= new ArrayList
<String
>();
229 while (index
< result
.getOutput().length
) {
230 String line
= result
.getOutput()[index
];
231 Matcher matcher
= SESSION_PATTERN
.matcher(line
);
232 if (matcher
.matches()) {
233 retArray
.add(matcher
.group(2).trim());
237 return retArray
.toArray(new String
[retArray
.size()]);
244 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
245 * #getSession(java.lang.String)
248 public ISessionInfo
getSession(String sessionName
) throws ExecutionException
{
249 return getSession(sessionName
, new NullProgressMonitor());
256 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
257 * #getSession(java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
260 public ISessionInfo
getSession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
261 String command
= COMMAND_LIST
+ sessionName
;
262 ICommandResult result
= fCommandShell
.executeCommand(command
, monitor
);
264 if (isError(result
)) {
265 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + formatOutput(result
.getOutput())); //$NON-NLS-1$ //$NON-NLS-2$
271 // Tracing session mysession2: [inactive]
272 // Trace path: /home/eedbhu/lttng-traces/mysession2-20120123-110330
273 ISessionInfo sessionInfo
= new SessionInfo(sessionName
);
275 while (index
< result
.getOutput().length
) {
276 // Tracing session mysession2: [inactive]
277 // Trace path: /home/eedbhu/lttng-traces/mysession2-20120123-110330
279 // === Domain: Kernel ===
281 String line
= result
.getOutput()[index
];
282 Matcher matcher
= TRACE_SESSION_PATTERN
.matcher(line
);
283 if (matcher
.matches()) {
284 sessionInfo
.setSessionState(matcher
.group(2));
289 matcher
= TRACE_SESSION_PATH_PATTERN
.matcher(line
);
290 if (matcher
.matches()) {
291 sessionInfo
.setSessionPath(matcher
.group(1).trim());
296 matcher
= DOMAIN_KERNEL_PATTERN
.matcher(line
);
297 if (matcher
.matches()) {
299 IDomainInfo domainInfo
= new DomainInfo(Messages
.TraceControl_KernelDomainDisplayName
);
300 sessionInfo
.addDomain(domainInfo
);
303 ArrayList
<IChannelInfo
> channels
= new ArrayList
<IChannelInfo
>();
304 index
= parseDomain(result
.getOutput(), index
, channels
);
307 domainInfo
.setChannels(channels
);
311 matcher
= DOMAIN_UST_GLOBAL_PATTERN
.matcher(line
);
312 if (matcher
.matches()) {
313 IDomainInfo domainInfo
= new DomainInfo(Messages
.TraceControl_UstGlobalDomainDisplayName
);
314 sessionInfo
.addDomain(domainInfo
);
317 ArrayList
<IChannelInfo
> channels
= new ArrayList
<IChannelInfo
>();
318 index
= parseDomain(result
.getOutput(), index
, channels
);
321 domainInfo
.setChannels(channels
);
333 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
334 * #getKernelProvider()
337 public List
<IBaseEventInfo
> getKernelProvider() throws ExecutionException
{
338 return getKernelProvider(new NullProgressMonitor());
345 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
346 * #getKernelProvider(org.eclipse.core.runtime.IProgressMonitor)
349 public List
<IBaseEventInfo
> getKernelProvider(IProgressMonitor monitor
) throws ExecutionException
{
350 String command
= COMMAND_LIST_KERNEL
;
351 ICommandResult result
= fCommandShell
.executeCommand(command
, monitor
);
352 if (isError(result
)) {
353 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + formatOutput(result
.getOutput())); //$NON-NLS-1$ //$NON-NLS-2$
358 // sched_kthread_stop (type: tracepoint)
359 List
<IBaseEventInfo
> events
= new ArrayList
<IBaseEventInfo
>();
360 getProviderEventInfo(result
.getOutput(), 0, events
);
368 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
372 public List
<IUstProviderInfo
> getUstProvider() throws ExecutionException
{
373 return getUstProvider(new NullProgressMonitor());
380 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
381 * #getUstProvider(org.eclipse.core.runtime.IProgressMonitor)
384 public List
<IUstProviderInfo
> getUstProvider(IProgressMonitor monitor
) throws ExecutionException
{
385 String command
= COMMAND_LIST_UST
;
386 ICommandResult result
= fCommandShell
.executeCommand(command
, monitor
);
388 if (isError(result
)) {
389 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + formatOutput(result
.getOutput())); //$NON-NLS-1$ //$NON-NLS-2$
396 // /home/user/git/lttng-ust/tests/hello.cxx/.libs/lt-hello
397 // ust_tests_hello:tptest_sighandler (loglevel: TRACE_EMERG0) (type:
399 // ust_tests_hello:tptest (loglevel: TRACE_EMERG0) (type: tracepoint)
402 // /home/user/git/lttng-ust/tests/hello.cxx/.libs/lt-hello
403 // ust_tests_hello:tptest_sighandler (loglevel: TRACE_EMERG0) (type:
405 // ust_tests_hello:tptest (loglevel: TRACE_EMERG0) (type: tracepoint)
407 List
<IUstProviderInfo
> allProviders
= new ArrayList
<IUstProviderInfo
>();
408 IUstProviderInfo provider
= null;
411 while (index
< result
.getOutput().length
) {
412 String line
= result
.getOutput()[index
];
413 Matcher matcher
= UST_PROVIDER_PATTERN
.matcher(line
);
414 if (matcher
.matches()) {
416 provider
= new UstProviderInfo(matcher
.group(2).trim());
417 provider
.setPid(Integer
.valueOf(matcher
.group(1).trim()));
418 List
<IBaseEventInfo
> events
= new ArrayList
<IBaseEventInfo
>();
419 index
= getProviderEventInfo(result
.getOutput(), ++index
, events
);
420 provider
.setEvents(events
);
421 allProviders
.add(provider
);
431 // ------------------------------------------------------------------------
433 // ------------------------------------------------------------------------
435 * Checks if command result is an error result.
438 * - the command result to check
439 * @return true if error else false
441 private boolean isError(ICommandResult result
) {
442 if ((result
.getResult()) != 0 || (result
.getOutput().length
< 1 || ERROR_PATTERN
.matcher(result
.getOutput()[0]).matches())) {
449 * Formats the output string as single string.
453 * @return - the formatted output
455 private String
formatOutput(String
[] output
) {
456 if (output
== null || output
.length
== 0) {
457 return ""; //$NON-NLS-1$
460 StringBuffer ret
= new StringBuffer();
461 for (int i
= 0; i
< output
.length
; i
++) {
462 ret
.append(output
[i
] + "\n"); //$NON-NLS-1$
464 return ret
.toString();
468 * Parses the domain information.
471 * - a command output array
472 * @param currentIndex
473 * - current index in command output array
475 * - list for returning channel information
476 * @return the new current index in command output array
478 private int parseDomain(String
[] output
, int currentIndex
, List
<IChannelInfo
> channels
) {
479 int index
= currentIndex
;
483 // - channnel1: [enabled]
487 // subbufers size: 262144
488 // number of subbufers: 4
489 // switch timer interval: 0
490 // read timer interval: 200
493 while (index
< output
.length
) {
494 String line
= output
[index
];
496 Matcher outerMatcher
= CHANNELS_SECTION_PATTERN
.matcher(line
);
497 if (outerMatcher
.matches()) {
498 IChannelInfo channelInfo
= null;
499 while (index
< output
.length
) {
500 String subLine
= output
[index
];
502 Matcher innerMatcher
= CHANNEL_PATTERN
.matcher(subLine
);
503 if (innerMatcher
.matches()) {
504 channelInfo
= new ChannelInfo(""); //$NON-NLS-1$
506 channelInfo
.setName(innerMatcher
.group(1));
508 // get channel enablement
509 channelInfo
.setState(innerMatcher
.group(2));
512 channels
.add(channelInfo
);
514 } else if (OVERWRITE_MODE_ATTRIBUTE
.matcher(subLine
).matches()) {
515 String value
= getAttributeValue(subLine
);
516 channelInfo
.setOverwriteMode(!OVERWRITE_MODE_ATTRIBUTE_FALSE
.equals(value
));
517 } else if (SUBBUFFER_SIZE_ATTRIBUTE
.matcher(subLine
).matches()) {
518 channelInfo
.setSubBufferSize(Long
.valueOf(getAttributeValue(subLine
)));
520 } else if (NUM_SUBBUFFERS_ATTRIBUTE
.matcher(subLine
).matches()) {
521 channelInfo
.setNumberOfSubBuffers(Integer
.valueOf(getAttributeValue(subLine
)));
523 } else if (SWITCH_TIMER_ATTRIBUTE
.matcher(subLine
).matches()) {
524 channelInfo
.setSwitchTimer(Long
.valueOf(getAttributeValue(subLine
)));
526 } else if (READ_TIMER_ATTRIBUTE
.matcher(subLine
).matches()) {
527 channelInfo
.setReadTimer(Long
.valueOf(getAttributeValue(subLine
)));
529 } else if (OUTPUT_ATTRIBUTE
.matcher(subLine
).matches()) {
530 channelInfo
.setOutputType(getAttributeValue(subLine
));
532 } else if (EVENT_SECTION_PATTERN
.matcher(subLine
).matches()) {
533 List
<IEventInfo
> events
= new ArrayList
<IEventInfo
>();
534 index
= parseEvents(output
, index
, events
);
535 channelInfo
.setEvents(events
);
536 // we want to stay at the current index to be able to
539 } else if (DOMAIN_KERNEL_PATTERN
.matcher(subLine
).matches()) {
542 } else if (DOMAIN_UST_GLOBAL_PATTERN
.matcher(subLine
).matches()) {
554 * Parses the event information within a domain.
557 * - a command output array
558 * @param currentIndex
559 * - current index in command output array
561 * - list for returning event information
562 * @return the new current index in command output array
564 private int parseEvents(String
[] output
, int currentIndex
, List
<IEventInfo
> events
) {
565 int index
= currentIndex
;
567 while (index
< output
.length
) {
568 String line
= output
[index
];
569 if (CHANNEL_PATTERN
.matcher(line
).matches()) {
572 } else if (DOMAIN_KERNEL_PATTERN
.matcher(line
).matches()) {
575 } else if (DOMAIN_UST_GLOBAL_PATTERN
.matcher(line
).matches()) {
580 Matcher matcher
= EVENT_PATTERN
.matcher(line
);
581 Matcher matcher2
= WILDCARD_EVENT_PATTERN
.matcher(line
);
583 if (matcher
.matches()) {
584 IEventInfo eventInfo
= new EventInfo(matcher
.group(1).trim());
585 eventInfo
.setLogLevel(matcher
.group(2).trim());
586 eventInfo
.setEventType(matcher
.group(3).trim());
587 eventInfo
.setState(matcher
.group(4));
588 events
.add(eventInfo
);
589 } else if (matcher2
.matches()) {
590 IEventInfo eventInfo
= new EventInfo(matcher2
.group(1).trim());
591 eventInfo
.setLogLevel(TraceLogLevel
.LEVEL_UNKNOWN
);
592 eventInfo
.setEventType(matcher2
.group(2).trim());
593 eventInfo
.setState(matcher2
.group(3));
594 events
.add(eventInfo
);
596 // else if (line.matches(EVENT_NONE_PATTERN)) {
606 * Parses a line with attributes: <attribute Name>: <attribute value>
609 * - attribute line to parse
610 * @return the attribute value as string
612 private String
getAttributeValue(String line
) {
613 String
[] temp
= line
.split("\\: "); //$NON-NLS-1$
618 * Parses the event information within a provider.
621 * - a command output array
622 * @param currentIndex
623 * - current index in command output array
625 * - list for returning event information
626 * @return the new current index in command output array
628 private int getProviderEventInfo(String
[] output
, int currentIndex
, List
<IBaseEventInfo
> events
) {
629 int index
= currentIndex
;
630 while (index
< output
.length
) {
631 String line
= output
[index
];
632 Matcher matcher
= PROVIDER_EVENT_PATTERN
.matcher(line
);
633 if (matcher
.matches()) {
634 // sched_kthread_stop (loglevel: TRACE_EMERG0) (type:
636 IBaseEventInfo eventInfo
= new BaseEventInfo(matcher
.group(1).trim());
637 eventInfo
.setLogLevel(matcher
.group(2).trim());
638 eventInfo
.setEventType(matcher
.group(3).trim());
639 events
.add(eventInfo
);
640 } else if (UST_PROVIDER_PATTERN
.matcher(line
).matches()) {