2 * Copyright (C) 2015, EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 package org
.lttng
.ust
.agent
.utils
;
21 import java
.io
.IOException
;
22 import java
.lang
.ProcessBuilder
.Redirect
;
23 import java
.nio
.file
.FileVisitResult
;
24 import java
.nio
.file
.Files
;
25 import java
.nio
.file
.Path
;
26 import java
.nio
.file
.Paths
;
27 import java
.nio
.file
.SimpleFileVisitor
;
28 import java
.nio
.file
.attribute
.BasicFileAttributes
;
29 import java
.util
.Arrays
;
30 import java
.util
.List
;
31 import java
.util
.StringJoiner
;
32 import java
.util
.UUID
;
33 import java
.util
.stream
.Collectors
;
36 * Java representation of a LTTng tracing session. It uses the command-line
37 * "lttng" tool to manipulate the session. Creating an instance will run
38 * "lttng create", close()'ing it will run "lttng destroy".
40 * @author Alexandre Montplaisir
42 public class LttngSession
implements AutoCloseable
{
45 * Tracing domains as they are defined by lttng-tools
48 /** The JUL (java.util.logging) domain */
49 JUL("-j"), /** The log4j (org.apache.log4j) domain */
52 private final String flag
;
54 private Domain(String flag
) {
59 * @return The corresponding command-line flag to pass to options like
60 * "lttng enable-event"
62 public String
flag() {
67 private final String sessionName
;
68 private final Domain domain
;
70 private volatile boolean channelCreated
= false;
73 * Constructor to create a new LTTng tracing session.
76 * The name of the session to use. It can be null, in which case
77 * we will provide a unique random name.
79 * The tracing domain of this session
81 public LttngSession(String sessionName
, Domain domain
) {
82 if (sessionName
!= null) {
83 this.sessionName
= sessionName
;
85 this.sessionName
= UUID
.randomUUID().toString();
89 /* Create the session in LTTng */
90 executeCommand(Arrays
.asList("lttng", "create", this.sessionName
));
95 /* Destroy the session */
96 executeCommand(Arrays
.asList("lttng", "destroy", sessionName
));
97 // FIXME also delete the trace we generated ?
100 // ------------------------------------------------------------------------
102 // ------------------------------------------------------------------------
105 * Enable all events in the given session (enable-event -a)
107 * @return If the command executed successfully (return code = 0).
109 public boolean enableAllEvents() {
110 channelCreated
= true;
111 return executeCommand(Arrays
.asList(
112 "lttng", "enable-event", domain
.flag(), "-a", "-s", sessionName
));
116 * Enable individual event(s).
118 * @param enabledEvents
119 * The list of events to enable. Should not be null or empty
120 * @return If the command executed successfully (return code = 0).
122 public boolean enableEvents(String
... enabledEvents
) {
123 if (enabledEvents
== null || enabledEvents
.length
== 0) {
124 throw new IllegalArgumentException();
126 channelCreated
= true;
127 return executeCommand(Arrays
.asList(
128 "lttng", "enable-event", domain
.flag(),
129 Arrays
.stream(enabledEvents
).collect(Collectors
.joining(",")),
134 * Send a disable-event command. Used to disable events that were previously
137 * @param disabledEvents
138 * The list of disabled events. Should not be null or empty
139 * @return If the command executed successfully (return code = 0).
141 public boolean disableEvents(String
... disabledEvents
) {
142 if (disabledEvents
== null || disabledEvents
.length
== 0) {
143 throw new IllegalArgumentException();
145 return executeCommand(Arrays
.asList(
146 "lttng", "disable-event", domain
.flag(),
147 Arrays
.stream(disabledEvents
).collect(Collectors
.joining(",")),
154 * @return If the command executed successfully (return code = 0).
156 public boolean start() {
158 * We have to enable a channel for 'lttng start' to work. However, we
159 * cannot enable a channel directly, see
160 * https://bugs.lttng.org/issues/894 . Instead we will enable an event
161 * we know does not exist
163 if (!channelCreated
) {
164 enableEvents("non-event");
166 return executeCommand(Arrays
.asList("lttng", "start", sessionName
));
170 * Stop the tracing session
172 * @return If the command executed successfully (return code = 0).
174 public boolean stop() {
175 return executeCommand(Arrays
.asList("lttng", "stop", sessionName
));
179 * Issue a "lttng view" command on the session, and returns its output. This
180 * effectively returns the current content of the trace in text form.
182 * @return The output of Babeltrace on the session's current trace
184 public List
<String
> view() {
185 return MiscTestUtils
.getOutputFromCommand(Arrays
.asList("lttng", "view", sessionName
));
189 * Utility method to destroy all existing sessions. Useful when first
190 * setting up a test to make sure no existing session interferes.
192 public static void destroyAllSessions() {
193 executeCommand(Arrays
.asList("lttng", "destroy", "-a"));
197 * Outside of the scope of lttng-tools, but this utility method can be used
198 * to delete all traces currently under ~/lttng-traces/. This can be used by
199 * tests to cleanup a trace they have created.
201 * @return True if the command completes successfully, false if there was an
204 public static boolean deleteAllTracee() {
205 String tracesDir
= new String(System
.getProperty("user.home") + "/lttng-traces/");
206 return deleteDirectory(Paths
.get(tracesDir
));
209 // ------------------------------------------------------------------------
210 // Private helper methods
211 // ------------------------------------------------------------------------
213 private static boolean deleteDirectory(Path directory
) {
215 Files
.walkFileTree(directory
, new SimpleFileVisitor
<Path
>() {
217 public FileVisitResult
visitFile(Path file
, BasicFileAttributes attrs
) throws IOException
{
219 return FileVisitResult
.CONTINUE
;
223 public FileVisitResult
postVisitDirectory(Path dir
, IOException exc
) throws IOException
{
225 return FileVisitResult
.CONTINUE
;
228 } catch (IOException e
) {
229 /* At least we tried... */
236 * Simple command to test that the environment / stdout are working
240 * Command-line arguments
242 public static void main(String
[] args
) {
243 List
<String
> command
= Arrays
.asList("ls", "-l");
244 executeCommand(command
);
247 private static boolean executeCommand(List
<String
> command
) {
249 /* "echo" the command to stdout */
250 StringJoiner sj
= new StringJoiner(" ", "$ ", "");
251 command
.stream().forEach(sj
::add
);
252 System
.out
.println(sj
.toString());
254 ProcessBuilder builder
= new ProcessBuilder(command
);
255 builder
.redirectErrorStream(true);
256 builder
.redirectOutput(Redirect
.INHERIT
);
258 Process p
= builder
.start();
259 int ret
= p
.waitFor();
261 System
.out
.println("(returned from command)");
265 } catch (IOException
| InterruptedException e
) {