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
.TraceLogLevel
;
31 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.BaseEventInfo
;
32 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.ChannelInfo
;
33 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.DomainInfo
;
34 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.EventInfo
;
35 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.SessionInfo
;
36 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.control
.model
.impl
.UstProviderInfo
;
39 * <b><u>LTTngControlService</u></b>
41 * Service for sending LTTng trace control commands to remote host.
44 public class LTTngControlService
implements ILttngControlService
{
45 // ------------------------------------------------------------------------
47 // ------------------------------------------------------------------------
50 * The lttng tools command.
52 private final static String CONTROL_COMMAND
= "lttng"; //$NON-NLS-1$
54 * Command: lttng list.
56 private final static String COMMAND_LIST
= CONTROL_COMMAND
+ " list "; //$NON-NLS-1$
58 * Command to list kernel tracer information.
60 private final static String COMMAND_LIST_KERNEL
= COMMAND_LIST
+ "-k"; //$NON-NLS-1$
62 * Command to list user space trace information.
64 private final static String COMMAND_LIST_UST
= COMMAND_LIST
+ "-u"; //$NON-NLS-1$
68 * Pattern to match for error output
70 private final static Pattern ERROR_PATTERN
= Pattern
.compile("\\s*Error\\:.*"); //$NON-NLS-1$
72 * Pattern to match for session information (lttng list)
74 private final static Pattern SESSION_PATTERN
= Pattern
.compile("\\s+(\\d+)\\)\\s+(.*)\\s+\\((.*)\\)\\s+\\[(active|inactive)\\].*"); //$NON-NLS-1$
76 * Pattern to match for session information (lttng list <session>)
78 private final static Pattern TRACE_SESSION_PATTERN
= Pattern
.compile("\\s*Tracing\\s+session\\s+(.*)\\:\\s+\\[(active|inactive)\\].*"); //$NON-NLS-1$
80 * Pattern to match for session path information (lttng list <session>)
82 private final static Pattern TRACE_SESSION_PATH_PATTERN
= Pattern
.compile("\\s*Trace\\s+path\\:\\s+(.*)"); //$NON-NLS-1$
84 * Pattern to match for kernel domain information (lttng list <session>)
86 private final static Pattern DOMAIN_KERNEL_PATTERN
= Pattern
.compile("=== Domain: Kernel ==="); //$NON-NLS-1$
88 * Pattern to match for ust domain information (lttng list <session>)
90 private final static Pattern DOMAIN_UST_GLOBAL_PATTERN
= Pattern
.compile("=== Domain: UST global ==="); //$NON-NLS-1$
92 * Pattern to match for channels section (lttng list <session>)
94 private final static Pattern CHANNELS_SECTION_PATTERN
= Pattern
.compile("\\s*Channels\\:"); //$NON-NLS-1$
96 * Pattern to match for channel information (lttng list <session>)
98 private final static Pattern CHANNEL_PATTERN
= Pattern
.compile("\\s*-\\s+(.*)\\:\\s+\\[(enabled|disabled)\\]"); //$NON-NLS-1$
100 * Pattern to match for events section information (lttng list <session>)
102 private final static Pattern EVENT_SECTION_PATTERN
= Pattern
.compile("\\s*Events\\:"); //$NON-NLS-1$
104 * Pattern to match for event information (no enabled events) (lttng list
107 // private final static String EVENT_NONE_PATTERN = "\\s+None"; //$NON-NLS-1$
109 * Pattern to match for event information (lttng list <session>)
111 private final static Pattern EVENT_PATTERN
= Pattern
.compile("\\s+(.*)\\s+\\(loglevel:\\s+(.*)\\s+\\(\\d*\\)\\)\\s+\\(type:\\s+(.*)\\)\\s+\\[(enabled|disabled)\\].*"); //$NON-NLS-1$
113 * Pattern to match a wildcarded event information (lttng list <session>)
115 private final static Pattern WILDCARD_EVENT_PATTERN
= Pattern
.compile("\\s+(.*)\\s+\\(type:\\s+(.*)\\)\\s+\\[(enabled|disabled)\\].*"); //$NON-NLS-1$
117 * Pattern to match for channel (overwite mode) information (lttng list
120 private final static Pattern OVERWRITE_MODE_ATTRIBUTE
= Pattern
.compile("\\s+overwrite\\s+mode\\:.*"); //$NON-NLS-1$
122 * Pattern to match indicating false for overwrite mode
124 private final static String OVERWRITE_MODE_ATTRIBUTE_FALSE
= "0"; //$NON-NLS-1$
126 * Pattern to match for channel (sub-buffer size) information (lttng list
129 private final static Pattern SUBBUFFER_SIZE_ATTRIBUTE
= Pattern
.compile("\\s+subbufers\\s+size\\:.*"); //$NON-NLS-1$
131 * Pattern to match for channel (number of sub-buffers) information (lttng
134 private final static Pattern NUM_SUBBUFFERS_ATTRIBUTE
= Pattern
.compile("\\s+number\\s+of\\s+subbufers\\:.*"); //$NON-NLS-1$
136 * Pattern to match for channel (switch timer) information (lttng list
139 private final static Pattern SWITCH_TIMER_ATTRIBUTE
= Pattern
.compile("\\s+switch\\s+timer\\s+interval\\:.*"); //$NON-NLS-1$
141 * Pattern to match for channel (read timer) information (lttng list
144 private final static Pattern READ_TIMER_ATTRIBUTE
= Pattern
.compile("\\s+read\\s+timer\\s+interval\\:.*"); //$NON-NLS-1$
146 * Pattern to match for channel (output type) information (lttng list
149 private final static Pattern OUTPUT_ATTRIBUTE
= Pattern
.compile("\\s+output\\:.*"); //$NON-NLS-1$
151 * Pattern to match for provider information (lttng list -k/-u)
153 private final static Pattern PROVIDER_EVENT_PATTERN
= Pattern
.compile("\\s*(.*)\\s+\\(loglevel:\\s+(.*)\\s+\\(\\d*\\)\\)\\s+\\(type:\\s+(.*)\\)"); //$NON-NLS-1$
155 * Pattern to match for UST provider information (lttng list -u)
157 private final static Pattern UST_PROVIDER_PATTERN
= Pattern
.compile("\\s*PID\\:\\s+(\\d+)\\s+-\\s+Name\\:\\s+(.*)"); //$NON-NLS-1$
159 // ------------------------------------------------------------------------
161 // ------------------------------------------------------------------------
163 * The command shell implementation
165 private ICommandShell fCommandShell
= null;
167 // ------------------------------------------------------------------------
169 // ------------------------------------------------------------------------
175 * - the command shell implementation to use
177 public LTTngControlService(ICommandShell shell
) {
178 fCommandShell
= shell
;
181 // ------------------------------------------------------------------------
183 // ------------------------------------------------------------------------
189 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
193 public String
[] getSessionNames() throws ExecutionException
{
194 return getSessionNames(new NullProgressMonitor());
201 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
202 * #getSessionNames(org.eclipse.core.runtime.IProgressMonitor)
205 public String
[] getSessionNames(IProgressMonitor monitor
) throws ExecutionException
{
207 String command
= COMMAND_LIST
;
208 ICommandResult result
= fCommandShell
.executeCommand(command
, monitor
);
210 if (isError(result
)) {
211 // TODO: no session available shouldn't be an error!
212 if (result
.getOutput().length
> 0 && ERROR_PATTERN
.matcher(result
.getOutput()[0]).matches()) {
213 // no sessions available
214 return new String
[0];
216 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + formatOutput(result
.getOutput())); //$NON-NLS-1$ //$NON-NLS-2$
220 // Available tracing sessions:
221 // 1) mysession1 (/home/user/lttng-traces/mysession1-20120123-083928)
223 // 2) mysession (/home/user/lttng-traces/mysession-20120123-083318)
226 // Use lttng list <session_name> for more details
228 ArrayList
<String
> retArray
= new ArrayList
<String
>();
230 while (index
< result
.getOutput().length
) {
231 String line
= result
.getOutput()[index
];
232 Matcher matcher
= SESSION_PATTERN
.matcher(line
);
233 if (matcher
.matches()) {
234 retArray
.add(matcher
.group(2).trim());
238 return retArray
.toArray(new String
[retArray
.size()]);
245 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
246 * #getSession(java.lang.String)
249 public ISessionInfo
getSession(String sessionName
) throws ExecutionException
{
250 return getSession(sessionName
, new NullProgressMonitor());
257 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
258 * #getSession(java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
261 public ISessionInfo
getSession(String sessionName
, IProgressMonitor monitor
) throws ExecutionException
{
262 String command
= COMMAND_LIST
+ sessionName
;
263 ICommandResult result
= fCommandShell
.executeCommand(command
, monitor
);
265 if (isError(result
)) {
266 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + formatOutput(result
.getOutput())); //$NON-NLS-1$ //$NON-NLS-2$
272 // Tracing session mysession2: [inactive]
273 // Trace path: /home/eedbhu/lttng-traces/mysession2-20120123-110330
274 ISessionInfo sessionInfo
= new SessionInfo(sessionName
);
276 while (index
< result
.getOutput().length
) {
277 // Tracing session mysession2: [inactive]
278 // Trace path: /home/eedbhu/lttng-traces/mysession2-20120123-110330
280 // === Domain: Kernel ===
282 String line
= result
.getOutput()[index
];
283 Matcher matcher
= TRACE_SESSION_PATTERN
.matcher(line
);
284 if (matcher
.matches()) {
285 sessionInfo
.setSessionState(matcher
.group(2));
290 matcher
= TRACE_SESSION_PATH_PATTERN
.matcher(line
);
291 if (matcher
.matches()) {
292 sessionInfo
.setSessionPath(matcher
.group(1).trim());
297 matcher
= DOMAIN_KERNEL_PATTERN
.matcher(line
);
298 if (matcher
.matches()) {
300 IDomainInfo domainInfo
= new DomainInfo(Messages
.TraceControl_KernelDomainDisplayName
);
301 sessionInfo
.addDomain(domainInfo
);
304 ArrayList
<IChannelInfo
> channels
= new ArrayList
<IChannelInfo
>();
305 index
= parseDomain(result
.getOutput(), index
, channels
);
308 domainInfo
.setChannels(channels
);
312 matcher
= DOMAIN_UST_GLOBAL_PATTERN
.matcher(line
);
313 if (matcher
.matches()) {
314 IDomainInfo domainInfo
= new DomainInfo(Messages
.TraceControl_UstGlobalDomainDisplayName
);
315 sessionInfo
.addDomain(domainInfo
);
318 ArrayList
<IChannelInfo
> channels
= new ArrayList
<IChannelInfo
>();
319 index
= parseDomain(result
.getOutput(), index
, channels
);
322 domainInfo
.setChannels(channels
);
334 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
335 * #getKernelProvider()
338 public List
<IBaseEventInfo
> getKernelProvider() throws ExecutionException
{
339 return getKernelProvider(new NullProgressMonitor());
346 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
347 * #getKernelProvider(org.eclipse.core.runtime.IProgressMonitor)
350 public List
<IBaseEventInfo
> getKernelProvider(IProgressMonitor monitor
) throws ExecutionException
{
351 String command
= COMMAND_LIST_KERNEL
;
352 ICommandResult result
= fCommandShell
.executeCommand(command
, monitor
);
353 if (isError(result
)) {
354 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + formatOutput(result
.getOutput())); //$NON-NLS-1$ //$NON-NLS-2$
359 // sched_kthread_stop (type: tracepoint)
360 List
<IBaseEventInfo
> events
= new ArrayList
<IBaseEventInfo
>();
361 getProviderEventInfo(result
.getOutput(), 0, events
);
369 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
373 public List
<IUstProviderInfo
> getUstProvider() throws ExecutionException
{
374 return getUstProvider(new NullProgressMonitor());
381 * org.eclipse.linuxtools.lttng.ui.views.control.service.ILttngControlService
382 * #getUstProvider(org.eclipse.core.runtime.IProgressMonitor)
385 public List
<IUstProviderInfo
> getUstProvider(IProgressMonitor monitor
) throws ExecutionException
{
386 String command
= COMMAND_LIST_UST
;
387 ICommandResult result
= fCommandShell
.executeCommand(command
, monitor
);
389 if (isError(result
)) {
390 throw new ExecutionException(Messages
.TraceControl_CommandError
+ " " + command
+ "\n" + formatOutput(result
.getOutput())); //$NON-NLS-1$ //$NON-NLS-2$
397 // /home/user/git/lttng-ust/tests/hello.cxx/.libs/lt-hello
398 // ust_tests_hello:tptest_sighandler (loglevel: TRACE_EMERG0) (type:
400 // ust_tests_hello:tptest (loglevel: TRACE_EMERG0) (type: tracepoint)
403 // /home/user/git/lttng-ust/tests/hello.cxx/.libs/lt-hello
404 // ust_tests_hello:tptest_sighandler (loglevel: TRACE_EMERG0) (type:
406 // ust_tests_hello:tptest (loglevel: TRACE_EMERG0) (type: tracepoint)
408 List
<IUstProviderInfo
> allProviders
= new ArrayList
<IUstProviderInfo
>();
409 IUstProviderInfo provider
= null;
412 while (index
< result
.getOutput().length
) {
413 String line
= result
.getOutput()[index
];
414 Matcher matcher
= UST_PROVIDER_PATTERN
.matcher(line
);
415 if (matcher
.matches()) {
417 provider
= new UstProviderInfo(matcher
.group(2).trim());
418 provider
.setPid(Integer
.valueOf(matcher
.group(1).trim()));
419 List
<IBaseEventInfo
> events
= new ArrayList
<IBaseEventInfo
>();
420 index
= getProviderEventInfo(result
.getOutput(), ++index
, events
);
421 provider
.setEvents(events
);
422 allProviders
.add(provider
);
432 // ------------------------------------------------------------------------
434 // ------------------------------------------------------------------------
436 * Checks if command result is an error result.
439 * - the command result to check
440 * @return true if error else false
442 private boolean isError(ICommandResult result
) {
443 if ((result
.getResult()) != 0 || (result
.getOutput().length
< 1 || ERROR_PATTERN
.matcher(result
.getOutput()[0]).matches())) {
450 * Formats the output string as single string.
454 * @return - the formatted output
456 private String
formatOutput(String
[] output
) {
457 if (output
== null || output
.length
== 0) {
458 return ""; //$NON-NLS-1$
461 StringBuffer ret
= new StringBuffer();
462 for (int i
= 0; i
< output
.length
; i
++) {
463 ret
.append(output
[i
] + "\n"); //$NON-NLS-1$
465 return ret
.toString();
469 * Parses the domain information.
472 * - a command output array
473 * @param currentIndex
474 * - current index in command output array
476 * - list for returning channel information
477 * @return the new current index in command output array
478 * @throws PatternSyntaxException
480 private int parseDomain(String
[] output
, int currentIndex
, List
<IChannelInfo
> channels
) throws PatternSyntaxException
{
481 int index
= currentIndex
;
485 // - channnel1: [enabled]
489 // subbufers size: 262144
490 // number of subbufers: 4
491 // switch timer interval: 0
492 // read timer interval: 200
495 while (index
< output
.length
) {
496 String line
= output
[index
];
498 Matcher outerMatcher
= CHANNELS_SECTION_PATTERN
.matcher(line
);
499 if (outerMatcher
.matches()) {
500 IChannelInfo channelInfo
= null;
501 while (index
< output
.length
) {
502 String subLine
= output
[index
];
504 Matcher innerMatcher
= CHANNEL_PATTERN
.matcher(subLine
);
505 if (innerMatcher
.matches()) {
506 channelInfo
= new ChannelInfo(""); //$NON-NLS-1$
508 channelInfo
.setName(innerMatcher
.group(1));
510 // get channel enablement
511 channelInfo
.setState(innerMatcher
.group(2));
514 channels
.add(channelInfo
);
516 } else if (OVERWRITE_MODE_ATTRIBUTE
.matcher(subLine
).matches()) {
517 String value
= getAttributeValue(subLine
);
518 channelInfo
.setOverwriteMode(!OVERWRITE_MODE_ATTRIBUTE_FALSE
.equals(value
));
519 } else if (SUBBUFFER_SIZE_ATTRIBUTE
.matcher(subLine
).matches()) {
520 channelInfo
.setSubBufferSize(Long
.valueOf(getAttributeValue(subLine
)));
522 } else if (NUM_SUBBUFFERS_ATTRIBUTE
.matcher(subLine
).matches()) {
523 channelInfo
.setNumberOfSubBuffers(Integer
.valueOf(getAttributeValue(subLine
)));
525 } else if (SWITCH_TIMER_ATTRIBUTE
.matcher(subLine
).matches()) {
526 channelInfo
.setSwitchTimer(Long
.valueOf(getAttributeValue(subLine
)));
528 } else if (READ_TIMER_ATTRIBUTE
.matcher(subLine
).matches()) {
529 channelInfo
.setReadTimer(Long
.valueOf(getAttributeValue(subLine
)));
531 } else if (OUTPUT_ATTRIBUTE
.matcher(subLine
).matches()) {
532 channelInfo
.setOutputType(getAttributeValue(subLine
));
534 } else if (EVENT_SECTION_PATTERN
.matcher(subLine
).matches()) {
535 List
<IEventInfo
> events
= new ArrayList
<IEventInfo
>();
536 index
= parseEvents(output
, index
, events
);
537 channelInfo
.setEvents(events
);
538 // we want to stay at the current index to be able to
541 } else if (DOMAIN_KERNEL_PATTERN
.matcher(subLine
).matches()) {
544 } else if (DOMAIN_UST_GLOBAL_PATTERN
.matcher(subLine
).matches()) {
556 * Parses the event information within a domain.
559 * - a command output array
560 * @param currentIndex
561 * - current index in command output array
563 * - list for returning event information
564 * @return the new current index in command output array
565 * @throws PatternSyntaxException
567 private int parseEvents(String
[] output
, int currentIndex
, List
<IEventInfo
> events
) throws PatternSyntaxException
{
568 int index
= currentIndex
;
570 while (index
< output
.length
) {
571 String line
= output
[index
];
572 if (CHANNEL_PATTERN
.matcher(line
).matches()) {
575 } else if (DOMAIN_KERNEL_PATTERN
.matcher(line
).matches()) {
578 } else if (DOMAIN_UST_GLOBAL_PATTERN
.matcher(line
).matches()) {
583 Matcher matcher
= EVENT_PATTERN
.matcher(line
);
584 Matcher matcher2
= WILDCARD_EVENT_PATTERN
.matcher(line
);
586 if (matcher
.matches()) {
587 IEventInfo eventInfo
= new EventInfo(matcher
.group(1).trim());
588 eventInfo
.setLogLevel(matcher
.group(2).trim());
589 eventInfo
.setEventType(matcher
.group(3).trim());
590 eventInfo
.setState(matcher
.group(4));
591 events
.add(eventInfo
);
592 } else if (matcher2
.matches()) {
593 IEventInfo eventInfo
= new EventInfo(matcher2
.group(1).trim());
594 eventInfo
.setLogLevel(TraceLogLevel
.LEVEL_UNKNOWN
);
595 eventInfo
.setEventType(matcher2
.group(2).trim());
596 eventInfo
.setState(matcher2
.group(3));
597 events
.add(eventInfo
);
599 // else if (line.matches(EVENT_NONE_PATTERN)) {
609 * Parses a line with attributes: <attribute Name>: <attribute value>
612 * - attribute line to parse
613 * @return the attribute value as string
614 * @throws PatternSyntaxException
616 private String
getAttributeValue(String line
) {
617 String
[] temp
= line
.split("\\: "); //$NON-NLS-1$
622 * Parses the event information within a provider.
625 * - a command output array
626 * @param currentIndex
627 * - current index in command output array
629 * - list for returning event information
630 * @return the new current index in command output array
632 private int getProviderEventInfo(String
[] output
, int currentIndex
, List
<IBaseEventInfo
> events
) {
633 int index
= currentIndex
;
634 while (index
< output
.length
) {
635 String line
= output
[index
];
636 Matcher matcher
= PROVIDER_EVENT_PATTERN
.matcher(line
);
637 if (matcher
.matches()) {
638 // sched_kthread_stop (loglevel: TRACE_EMERG0) (type:
640 IBaseEventInfo eventInfo
= new BaseEventInfo(matcher
.group(1).trim());
641 eventInfo
.setLogLevel(matcher
.group(2).trim());
642 eventInfo
.setEventType(matcher
.group(3).trim());
643 events
.add(eventInfo
);
644 } else if (UST_PROVIDER_PATTERN
.matcher(line
).matches()) {