9c77f59b8395ca8e7bdd41d58aa1afa8daaa9302
[lttng-ust-java-tests.git] / src / test / java / org / lttng / ust / agent / utils / LttngSession.java
1 /*
2 * Copyright (C) 2015, EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
3 *
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.
8 *
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.
13 *
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.
17 */
18
19 package org.lttng.ust.agent.utils;
20
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.UUID;
32 import java.util.stream.Collectors;
33
34 /**
35 * Java representation of a LTTng tracing session. It uses the command-line
36 * "lttng" tool to manipulate the session. Creating an instance will run
37 * "lttng create", close()'ing it will run "lttng destroy".
38 *
39 * @author Alexandre Montplaisir
40 */
41 public class LttngSession implements AutoCloseable {
42
43 /**
44 * Tracing domains as they are defined by lttng-tools
45 */
46 public enum Domain {
47 /** The JUL (java.util.logging) domain */
48 JUL("-j"), /** The log4j (org.apache.log4j) domain */
49 LOG4J("-l");
50
51 private final String flag;
52
53 private Domain(String flag) {
54 this.flag = flag;
55 }
56
57 /**
58 * @return The corresponding command-line flag to pass to options like
59 * "lttng enable-event"
60 */
61 public String flag() {
62 return flag;
63 }
64 }
65
66 private final String sessionName;
67 private final Domain domain;
68
69 private volatile boolean channelCreated = false;
70
71 /**
72 * Constructor to create a new LTTng tracing session.
73 *
74 * @param sessionName
75 * The name of the session to use. It can be null, in which case
76 * we will provide a unique random name.
77 * @param domain
78 * The tracing domain of this session
79 */
80 public LttngSession(String sessionName, Domain domain) {
81 if (sessionName != null) {
82 this.sessionName = sessionName;
83 } else {
84 this.sessionName = UUID.randomUUID().toString();
85 }
86 this.domain = domain;
87
88 /* Create the session in LTTng */
89 executeCommand(Arrays.asList("lttng", "create", this.sessionName));
90 }
91
92 @Override
93 public void close() {
94 /* Destroy the session */
95 executeCommand(Arrays.asList("lttng", "destroy", sessionName));
96 // FIXME also delete the trace we generated ?
97 }
98
99 // ------------------------------------------------------------------------
100 // Public methods
101 // ------------------------------------------------------------------------
102
103 /**
104 * Enable all events in the given session (enable-event -a)
105 *
106 * @return If the command executed successfully (return code = 0).
107 */
108 public boolean enableAllEvents() {
109 channelCreated = true;
110 return executeCommand(Arrays.asList(
111 "lttng", "enable-event", domain.flag(), "-a", "-s", sessionName));
112 }
113
114 /**
115 * Enable individual event(s).
116 *
117 * @param enabledEvents
118 * The list of events to enable. Should not be null or empty
119 * @return If the command executed successfully (return code = 0).
120 */
121 public boolean enableEvents(String... enabledEvents) {
122 if (enabledEvents == null || enabledEvents.length == 0) {
123 throw new IllegalArgumentException();
124 }
125 channelCreated = true;
126 return executeCommand(Arrays.asList(
127 "lttng", "enable-event", domain.flag(),
128 Arrays.stream(enabledEvents).collect(Collectors.joining(",")),
129 "-s", sessionName));
130 }
131
132 /**
133 * Send a disable-event command. Used to disable events that were previously
134 * enabled.
135 *
136 * @param disabledEvents
137 * The list of disabled events. Should not be null or empty
138 * @return If the command executed successfully (return code = 0).
139 */
140 public boolean disableEvents(String... disabledEvents) {
141 if (disabledEvents == null || disabledEvents.length == 0) {
142 throw new IllegalArgumentException();
143 }
144 return executeCommand(Arrays.asList(
145 "lttng", "disable-event", domain.flag(),
146 Arrays.stream(disabledEvents).collect(Collectors.joining(",")),
147 "-s", sessionName));
148 }
149
150 /**
151 * Start tracing
152 *
153 * @return If the command executed successfully (return code = 0).
154 */
155 public boolean start() {
156 /*
157 * We have to enable a channel for 'lttng start' to work. However, we
158 * cannot enable a channel directly, see
159 * https://bugs.lttng.org/issues/894 . Instead we will enable an event
160 * we know does not exist
161 */
162 if (!channelCreated) {
163 enableEvents("non-event");
164 }
165 return executeCommand(Arrays.asList("lttng", "start", sessionName));
166 }
167
168 /**
169 * Stop the tracing session
170 *
171 * @return If the command executed successfully (return code = 0).
172 */
173 public boolean stop() {
174 return executeCommand(Arrays.asList("lttng", "stop", sessionName));
175 }
176
177 /**
178 * Issue a "lttng view" command on the session, and returns its output. This
179 * effectively returns the current content of the trace in text form.
180 *
181 * @return The output of Babeltrace on the session's current trace
182 */
183 public List<String> view() {
184 return MiscTestUtils.getOutputFromCommand(Arrays.asList("lttng", "view", sessionName));
185 }
186
187 /**
188 * Utility method to destroy all existing sessions. Useful when first
189 * setting up a test to make sure no existing session interferes.
190 */
191 public static void destroyAllSessions() {
192 executeCommand(Arrays.asList("lttng", "destroy", "-a"));
193 }
194
195 /**
196 * Outside of the scope of lttng-tools, but this utility method can be used
197 * to delete all traces currently under ~/lttng-traces/. This can be used by
198 * tests to cleanup a trace they have created.
199 *
200 * @return True if the command completes successfully, false if there was an
201 * error.
202 */
203 public static boolean deleteAllTracee() {
204 String tracesDir = new String(System.getProperty("user.home") + "/lttng-traces/");
205 return deleteDirectory(Paths.get(tracesDir));
206 }
207
208 // ------------------------------------------------------------------------
209 // Private helper methods
210 // ------------------------------------------------------------------------
211
212 private static boolean deleteDirectory(Path directory) {
213 try {
214 Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
215 @Override
216 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
217 Files.delete(file);
218 return FileVisitResult.CONTINUE;
219 }
220
221 @Override
222 public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
223 Files.delete(dir);
224 return FileVisitResult.CONTINUE;
225 }
226 });
227 } catch (IOException e) {
228 /* At least we tried... */
229 return false;
230 }
231 return true;
232 }
233
234 /**
235 * Simple command to test that the environment / stdout are working
236 * correctly.
237 *
238 * @param args
239 * Command-line arguments
240 */
241 public static void main(String[] args) {
242 List<String> command = Arrays.asList("ls", "-l");
243 executeCommand(command);
244 }
245
246 private static boolean executeCommand(List<String> command) {
247 try {
248 ProcessBuilder builder = new ProcessBuilder(command);
249 builder.redirectErrorStream(true);
250 builder.redirectOutput(Redirect.INHERIT);
251
252 Process p = builder.start();
253 int ret = p.waitFor();
254 return (ret == 0);
255
256 } catch (IOException | InterruptedException e) {
257 return false;
258 }
259 }
260 }
This page took 0.033562 seconds and 3 git commands to generate.