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
;
18 import java
.util
.regex
.PatternSyntaxException
;
20 import org
.eclipse
.core
.commands
.ExecutionException
;
21 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
22 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
23 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.Messages
;
24 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.IBaseEventInfo
;
25 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.IChannelInfo
;
26 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.IDomainInfo
;
27 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.IEventInfo
;
28 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.ISessionInfo
;
29 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.IUstProviderInfo
;
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
;
37 * <b><u>LTTngControlService</u></b>
39 * Service for sending LTTng trace control commands to remote host.
42 public class LTTngControlService
implements ILttngControlService
{
43 // ------------------------------------------------------------------------
45 // ------------------------------------------------------------------------
48 * The lttng tools command.
50 private final static String CONTROL_COMMAND
= "lttng"; //$NON-NLS-1$
52 * Command: lttng list.
54 private final static String COMMAND_LIST
= CONTROL_COMMAND
+ " list "; //$NON-NLS-1$
56 * Command to list kernel tracer information.
58 private final static String COMMAND_LIST_KERNEL
= COMMAND_LIST
+ "-k"; //$NON-NLS-1$
60 * Command to list user space trace information.
62 private final static String COMMAND_LIST_UST
= COMMAND_LIST
+ "-u"; //$NON-NLS-1$
66 * Pattern to match for error output
68 private final static String ERROR_PATTERN
= "\\s*Error\\:.*"; //$NON-NLS-1$
70 * Pattern to match for session information (lttng list)
72 private final static String SESSION_PATTERN
= "\\s+(\\d+)\\)\\s+(.*)\\s+\\((.*)\\)\\s+\\[(active|inactive)\\].*"; //$NON-NLS-1$
74 * Pattern to match for session information (lttng list <session>)
76 private final static String TRACE_SESSION_PATTERN
= "\\s*Tracing\\s+session\\s+(.*)\\:\\s+\\[(active|inactive)\\].*"; //$NON-NLS-1$
78 * Pattern to match for session path information (lttng list <session>)
80 private final static String TRACE_SESSION_PATH_PATTERN
= "\\s*Trace\\s+path\\:\\s+(.*)"; //$NON-NLS-1$
82 * Pattern to match for kernel domain information (lttng list <session>)
84 private final static String DOMAIN_KERNEL_PATTERN
= "=== Domain: Kernel ==="; //$NON-NLS-1$
86 * Pattern to match for ust domain information (lttng list <session>)
88 private final static String DOMAIN_UST_GLOBAL_PATTERN
= "=== Domain: UST global ==="; //$NON-NLS-1$
90 * Pattern to match for channels section (lttng list <session>)
92 private final static String CHANNELS_SECTION_PATTERN
= "\\s*Channels\\:"; //$NON-NLS-1$
94 * Pattern to match for channel information (lttng list <session>)
96 private final static String CHANNEL_PATTERN
= "\\s*-\\s+(.*)\\:\\s+\\[(enabled|disabled)\\]"; //$NON-NLS-1$
98 * Pattern to match for events section information (lttng list <session>)
100 private final static String EVENT_SECTION_PATTERN
= "\\s*Events\\:"; //$NON-NLS-1$
102 * Pattern to match for event information (no enabled events) (lttng list <session>)
104 // private final static String EVENT_NONE_PATTERN = "\\s+None"; //$NON-NLS-1$
106 * Pattern to match for event information (lttng list <session>)
108 private final static String EVENT_PATTERN
= "\\s+(.*)\\s+\\(loglevel:\\s+(.*)\\)\\s+\\(type:\\s+(.*)\\)\\s+\\[(enabled|disabled)\\].*"; //$NON-NLS-1$
110 * Pattern to match for channel (overwite mode) information (lttng list <session>)
112 private final static String OVERWRITE_MODE_ATTRIBUTE
= "\\s+overwrite\\s+mode\\:.*"; //$NON-NLS-1$
114 * Pattern to match indicating false for overwrite mode
116 private final static String OVERWRITE_MODE_ATTRIBUTE_FALSE
= "0"; //$NON-NLS-1$
118 * Pattern to match for channel (sub-buffer size) information (lttng list <session>)
120 private final static String SUBBUFFER_SIZE_ATTRIBUTE
= "\\s+subbufers\\s+size\\:.*"; //$NON-NLS-1$
122 * Pattern to match for channel (number of sub-buffers) information (lttng list <session>)
124 private final static String NUM_SUBBUFFERS_ATTRIBUTE
= "\\s+number\\s+of\\s+subbufers\\:.*"; //$NON-NLS-1$
126 * Pattern to match for channel (switch timer) information (lttng list <session>)
128 private final static String SWITCH_TIMER_ATTRIBUTE
= "\\s+switch\\s+timer\\s+interval\\:.*"; //$NON-NLS-1$
130 * Pattern to match for channel (read timer) information (lttng list <session>)
132 private final static String READ_TIMER_ATTRIBUTE
= "\\s+read\\s+timer\\s+interval\\:.*"; //$NON-NLS-1$
134 * Pattern to match for channel (output type) information (lttng list <session>)
136 private final static String OUTPUT_ATTRIBUTE
= "\\s+output\\:.*"; //$NON-NLS-1$
138 * Pattern to match for provider information (lttng list -k/-u)
140 private final static String PROVIDER_EVENT_PATTERN
= "\\s*(.*)\\s+\\(loglevel:\\s+(.*)\\)\\s+\\(type:\\s+(.*)\\)"; //$NON-NLS-1$
142 * Pattern to match for UST provider information (lttng list -u)
144 private final static String UST_PROVIDER_PATTERN
= "\\s*PID\\:\\s+(\\d+)\\s+-\\s+Name\\:\\s+(.*)"; //$NON-NLS-1$
146 // ------------------------------------------------------------------------
148 // ------------------------------------------------------------------------
150 * The command shell implementation
152 private ICommandShell fCommandShell
= null;
154 // ------------------------------------------------------------------------
156 // ------------------------------------------------------------------------
160 * @param shell - the command shell implementation to use
162 public LTTngControlService(ICommandShell shell
) {
163 fCommandShell
= shell
;
165 // ------------------------------------------------------------------------
167 // ------------------------------------------------------------------------
171 * @see org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService#getSessionNames()
174 public String
[] getSessionNames() throws ExecutionException
{
175 return getSessionNames(new NullProgressMonitor());
180 * @see org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService#getSessionNames(org.eclipse.core.runtime.IProgressMonitor)
183 public String
[] getSessionNames(IProgressMonitor monitor
) throws ExecutionException
{
185 String command
= COMMAND_LIST
;
186 ICommandResult result
= fCommandShell
.executeCommand(command
, monitor
);
188 if (isError(result
)) {
189 // TODO: no session available shouldn't be an error!
190 if (result
.getOutput().length
> 0 && result
.getOutput()[0].matches(ERROR_PATTERN
)) {
191 // no sessions available
192 return new String
[0];
194 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + formatOutput(result
.getOutput())); //$NON-NLS-1$ //$NON-NLS-2$
198 // Available tracing sessions:
199 // 1) mysession1 (/home/user/lttng-traces/mysession1-20120123-083928) [inactive]
200 // 2) mysession (/home/user/lttng-traces/mysession-20120123-083318) [inactive]
202 // Use lttng list <session_name> for more details
204 ArrayList
<String
> retArray
= new ArrayList
<String
>();
206 while (index
< result
.getOutput().length
) {
207 String line
= result
.getOutput()[index
];
209 Pattern pattern
= Pattern
.compile(SESSION_PATTERN
);
210 Matcher matcher
= pattern
.matcher(line
);
211 if (matcher
.matches()) {
212 retArray
.add(matcher
.group(2).trim());
214 } catch (PatternSyntaxException e
) {
218 return retArray
.toArray(new String
[retArray
.size()]);
223 * @see org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService#getSession(java.lang.String)
226 public ISessionInfo
getSession(String sessionName
) throws ExecutionException
{
227 return getSession(sessionName
, new NullProgressMonitor());
232 * @see org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService#getSession(java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
235 public ISessionInfo
getSession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
236 String command
= COMMAND_LIST
+ sessionName
;
237 ICommandResult result
= fCommandShell
.executeCommand(command
, monitor
);
239 if (isError(result
)) {
240 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + formatOutput(result
.getOutput())); //$NON-NLS-1$ //$NON-NLS-2$
246 // Tracing session mysession2: [inactive]
247 // Trace path: /home/eedbhu/lttng-traces/mysession2-20120123-110330
248 ISessionInfo sessionInfo
= new SessionInfo(sessionName
);
251 while (index
< result
.getOutput().length
) {
252 // Tracing session mysession2: [inactive]
253 // Trace path: /home/eedbhu/lttng-traces/mysession2-20120123-110330
255 // === Domain: Kernel ===
257 String line
= result
.getOutput()[index
];
258 if (line
.matches(TRACE_SESSION_PATTERN
)) {
259 Pattern pattern
= Pattern
.compile(TRACE_SESSION_PATTERN
);
260 Matcher matcher
= pattern
.matcher(line
);
261 if (matcher
.matches()) {
262 sessionInfo
.setSessionState(matcher
.group(2));
265 } else if (line
.matches(TRACE_SESSION_PATH_PATTERN
)) {
266 Pattern pattern
= Pattern
.compile(TRACE_SESSION_PATH_PATTERN
);
267 Matcher matcher
= pattern
.matcher(line
);
268 if (matcher
.matches()) {
269 sessionInfo
.setSessionPath(matcher
.group(1).trim());
273 else if (line
.matches(DOMAIN_KERNEL_PATTERN
)) {
275 IDomainInfo domainInfo
= new DomainInfo(Messages
.TraceControl_KernelDomainDisplayName
);
276 sessionInfo
.addDomain(domainInfo
);
279 ArrayList
<IChannelInfo
> channels
= new ArrayList
<IChannelInfo
>();
280 index
= parseDomain(result
.getOutput(), index
, channels
);
283 domainInfo
.setChannels(channels
);
285 } else if (line
.contains(DOMAIN_UST_GLOBAL_PATTERN
)) {
286 IDomainInfo domainInfo
= new DomainInfo(Messages
.TraceControl_UstGlobalDomainDisplayName
);
287 sessionInfo
.addDomain(domainInfo
);
290 ArrayList
<IChannelInfo
> channels
= new ArrayList
<IChannelInfo
>();
291 index
= parseDomain(result
.getOutput(), index
, channels
);
294 domainInfo
.setChannels(channels
);
299 } catch (PatternSyntaxException e
) {
300 throw new ExecutionException("Invalid regular expression", e
); //$NON-NLS-1$
307 * @see org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService#getKernelProvider()
310 public List
<IBaseEventInfo
> getKernelProvider() throws ExecutionException
{
311 return getKernelProvider(new NullProgressMonitor());
316 * @see org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService#getKernelProvider(org.eclipse.core.runtime.IProgressMonitor)
319 public List
<IBaseEventInfo
> getKernelProvider(IProgressMonitor monitor
) throws ExecutionException
{
320 String command
= COMMAND_LIST_KERNEL
;
321 ICommandResult result
= fCommandShell
.executeCommand(command
, monitor
);
322 if (isError(result
)) {
323 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + formatOutput(result
.getOutput())); //$NON-NLS-1$ //$NON-NLS-2$
328 // sched_kthread_stop (type: tracepoint)
329 List
<IBaseEventInfo
> events
= new ArrayList
<IBaseEventInfo
>();
330 getProviderEventInfo(result
.getOutput(), 0, events
);
336 * @see org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService#getUstProvider()
339 public List
<IUstProviderInfo
> getUstProvider() throws ExecutionException
{
340 return getUstProvider(new NullProgressMonitor());
345 * @see org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService#getUstProvider(org.eclipse.core.runtime.IProgressMonitor)
348 public List
<IUstProviderInfo
> getUstProvider(IProgressMonitor monitor
) throws ExecutionException
{
349 String command
= COMMAND_LIST_UST
;
350 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$
359 // PID: 3635 - Name: /home/user/git/lttng-ust/tests/hello.cxx/.libs/lt-hello
360 // ust_tests_hello:tptest_sighandler (loglevel: TRACE_EMERG0) (type: tracepoint)
361 // ust_tests_hello:tptest (loglevel: TRACE_EMERG0) (type: tracepoint)
363 // PID: 6459 - Name: /home/user/git/lttng-ust/tests/hello.cxx/.libs/lt-hello
364 // ust_tests_hello:tptest_sighandler (loglevel: TRACE_EMERG0) (type: tracepoint)
365 // ust_tests_hello:tptest (loglevel: TRACE_EMERG0) (type: tracepoint)
367 List
<IUstProviderInfo
> allProviders
= new ArrayList
<IUstProviderInfo
>();
368 IUstProviderInfo provider
= null;
371 while (index
< result
.getOutput().length
) {
372 String line
= result
.getOutput()[index
];
373 if (line
.matches(UST_PROVIDER_PATTERN
)) {
374 Pattern pattern
= Pattern
.compile(UST_PROVIDER_PATTERN
);
376 Matcher matcher
= pattern
.matcher(line
);
378 if (matcher
.matches()) {
380 provider
= new UstProviderInfo(matcher
.group(2).trim());
381 provider
.setPid(Integer
.valueOf(matcher
.group(1).trim()));
382 List
<IBaseEventInfo
> events
= new ArrayList
<IBaseEventInfo
>();
383 index
= getProviderEventInfo(result
.getOutput(), ++index
, events
);
384 provider
.setEvents(events
);
385 allProviders
.add(provider
);
396 // ------------------------------------------------------------------------
398 // ------------------------------------------------------------------------
400 * Checks if command result is an error result.
401 * @param result - the command result to check
402 * @return true if error else false
404 private boolean isError(ICommandResult result
) {
405 if ((result
.getResult()) != 0 || (result
.getOutput().length
< 1 || result
.getOutput()[0].matches(ERROR_PATTERN
))) {
412 * Formats the output string as single string.
413 * @param output - output array
414 * @return - the formatted output
416 private String
formatOutput(String
[] output
) {
417 if (output
== null || output
.length
== 0) {
418 return ""; //$NON-NLS-1$
421 StringBuffer ret
= new StringBuffer();
422 for (int i
= 0; i
< output
.length
; i
++) {
423 ret
.append(output
[i
] + "\n"); //$NON-NLS-1$
425 return ret
.toString();
429 * Parses the domain information.
431 * @param output - a command output array
432 * @param currentIndex - current index in command output array
433 * @param channels - list for returning channel information
434 * @return the new current index in command output array
435 * @throws PatternSyntaxException
437 private int parseDomain(String
[] output
, int currentIndex
, List
<IChannelInfo
> channels
) throws PatternSyntaxException
{
438 int index
= currentIndex
;
442 // - channnel1: [enabled]
446 // subbufers size: 262144
447 // number of subbufers: 4
448 // switch timer interval: 0
449 // read timer interval: 200
452 while (index
< output
.length
) {
453 String line
= output
[index
];
454 if (line
.matches(CHANNELS_SECTION_PATTERN
)) {
455 IChannelInfo channelInfo
= null;
456 while (index
< output
.length
) {
457 String subLine
= output
[index
];
458 if (subLine
.matches(CHANNEL_PATTERN
)) {
460 Pattern pattern
= Pattern
.compile(CHANNEL_PATTERN
);
461 Matcher matcher
= pattern
.matcher(subLine
);
462 channelInfo
= new ChannelInfo(""); //$NON-NLS-1$
463 if (matcher
.matches()) {
465 channelInfo
.setName(matcher
.group(1));
467 // get channel enablement
468 channelInfo
.setState(matcher
.group(2));
471 channels
.add(channelInfo
);
473 } else if (subLine
.matches(OVERWRITE_MODE_ATTRIBUTE
)) {
474 String value
= getAttributeValue(subLine
);
475 channelInfo
.setOverwriteMode(!OVERWRITE_MODE_ATTRIBUTE_FALSE
.equals(value
));
476 } else if (subLine
.matches(SUBBUFFER_SIZE_ATTRIBUTE
)) {
477 channelInfo
.setSubBufferSize(Long
.valueOf(getAttributeValue(subLine
)));
479 } else if (subLine
.matches(NUM_SUBBUFFERS_ATTRIBUTE
)) {
480 channelInfo
.setNumberOfSubBuffers(Integer
.valueOf(getAttributeValue(subLine
)));
482 } else if (subLine
.matches(SWITCH_TIMER_ATTRIBUTE
)) {
483 channelInfo
.setSwitchTimer(Long
.valueOf(getAttributeValue(subLine
)));
485 } else if (subLine
.matches(READ_TIMER_ATTRIBUTE
)) {
486 channelInfo
.setReadTimer(Long
.valueOf(getAttributeValue(subLine
)));
488 } else if (subLine
.matches(OUTPUT_ATTRIBUTE
)) {
489 channelInfo
.setOutputType(getAttributeValue(subLine
));
491 } else if (subLine
.matches(EVENT_SECTION_PATTERN
)) {
492 List
<IEventInfo
> events
= new ArrayList
<IEventInfo
>();
493 index
= parseEvents(output
, index
, events
);
494 channelInfo
.setEvents(events
);
495 // we want to stay at the current index to be able to exit the domain
498 else if (subLine
.matches(DOMAIN_KERNEL_PATTERN
)) {
501 } else if (subLine
.contains(DOMAIN_UST_GLOBAL_PATTERN
)) {
513 * Parses the event information within a domain.
515 * @param output - a command output array
516 * @param currentIndex - current index in command output array
517 * @param events - list for returning event information
518 * @return the new current index in command output array
519 * @throws PatternSyntaxException
521 private int parseEvents(String
[] output
, int currentIndex
, List
<IEventInfo
> events
) throws PatternSyntaxException
{
522 int index
= currentIndex
;
524 while (index
< output
.length
) {
525 String line
= output
[index
];
526 if (line
.matches(CHANNEL_PATTERN
)) {
529 } else if (line
.matches(DOMAIN_KERNEL_PATTERN
)) {
532 } else if (line
.contains(DOMAIN_UST_GLOBAL_PATTERN
)) {
535 } else if (line
.matches(EVENT_PATTERN
)) {
536 Pattern pattern
= Pattern
.compile(EVENT_PATTERN
);
538 Matcher matcher
= pattern
.matcher(line
);
540 if (matcher
.matches()) {
541 IEventInfo eventInfo
= new EventInfo(matcher
.group(1).trim());
542 eventInfo
.setLogLevel(matcher
.group(2).trim());
543 eventInfo
.setEventType(matcher
.group(3).trim());
544 eventInfo
.setState(matcher
.group(4));
545 events
.add(eventInfo
);
548 // else if (line.matches(EVENT_NONE_PATTERN)) {
558 * Parses a line with attributes: <attribute Name>: <attribute value>
560 * @param line - attribute line to parse
561 * @return the attribute value as string
562 * @throws PatternSyntaxException
564 private String
getAttributeValue(String line
) {
565 String
[] temp
= line
.split("\\: "); //$NON-NLS-1$
570 * Parses the event information within a provider.
572 * @param output - a command output array
573 * @param currentIndex - current index in command output array
574 * @param events - list for returning event information
575 * @return the new current index in command output array
577 private int getProviderEventInfo(String
[] output
, int currentIndex
, List
<IBaseEventInfo
> events
) {
578 int index
= currentIndex
;
579 while (index
< output
.length
) {
580 String line
= output
[index
];
581 if (line
.matches(PROVIDER_EVENT_PATTERN
)) {
582 // sched_kthread_stop (loglevel: TRACE_EMERG0) (type: tracepoint)
583 Pattern pattern
= Pattern
.compile(PROVIDER_EVENT_PATTERN
);
585 Matcher matcher
= pattern
.matcher(line
);
587 if (matcher
.matches()) {
588 IBaseEventInfo eventInfo
= new BaseEventInfo(matcher
.group(1).trim());
589 eventInfo
.setLogLevel(matcher
.group(2).trim());
590 eventInfo
.setEventType(matcher
.group(3).trim());
591 events
.add(eventInfo
);
593 } else if (line
.matches(UST_PROVIDER_PATTERN
)) {