Commit | Line | Data |
---|---|---|
8576633f AM |
1 | package org.lttng.ust.agent.utils; |
2 | ||
3 | import java.io.IOException; | |
4 | import java.lang.ProcessBuilder.Redirect; | |
5 | import java.nio.file.FileVisitResult; | |
6 | import java.nio.file.Files; | |
7 | import java.nio.file.Path; | |
8 | import java.nio.file.Paths; | |
9 | import java.nio.file.SimpleFileVisitor; | |
10 | import java.nio.file.attribute.BasicFileAttributes; | |
11 | import java.util.Arrays; | |
12 | import java.util.List; | |
13 | import java.util.UUID; | |
14 | import java.util.stream.Collectors; | |
15 | ||
16 | public class LttngSession implements AutoCloseable { | |
17 | ||
18 | public enum Domain { | |
19 | JUL("-j"), | |
20 | LOG4J("-l"); | |
21 | ||
22 | private final String flag; | |
23 | ||
24 | private Domain(String flag) { | |
25 | this.flag = flag; | |
26 | } | |
27 | ||
28 | public String flag() { | |
29 | return flag; | |
30 | } | |
31 | } | |
32 | ||
33 | private final String sessionName; | |
34 | private final Domain domain; | |
35 | ||
36 | private volatile boolean channelCreated = false; | |
37 | ||
38 | public LttngSession(String sessionName, Domain domain) { | |
39 | if (sessionName != null) { | |
40 | this.sessionName = sessionName; | |
41 | } else { | |
42 | this.sessionName = UUID.randomUUID().toString(); | |
43 | } | |
44 | this.domain = domain; | |
45 | ||
46 | /* Create the session in LTTng */ | |
47 | executeCommand(Arrays.asList("lttng", "create", this.sessionName)); | |
48 | } | |
49 | ||
50 | @Override | |
51 | public void close() { | |
52 | /* Destroy the session */ | |
53 | executeCommand(Arrays.asList("lttng", "destroy", sessionName)); | |
54 | // FIXME also delete the trace we generated ? | |
55 | } | |
56 | ||
57 | // ------------------------------------------------------------------------ | |
58 | // Public methods | |
59 | // ------------------------------------------------------------------------ | |
60 | ||
61 | /** | |
62 | * Enable all events in the given session (enable-event -a) | |
63 | * | |
64 | * @return If the command executed successfully (return code = 0). | |
65 | */ | |
66 | public boolean enableAllEvents() { | |
67 | channelCreated = true; | |
68 | return executeCommand(Arrays.asList( | |
69 | "lttng", "enable-event", domain.flag(), "-a", "-s", sessionName)); | |
70 | } | |
71 | ||
72 | /** | |
73 | * Enable individual event(s). | |
74 | * | |
75 | * @param enabledEvents | |
76 | * The list of events to enable. Should not be null or empty | |
77 | * @return If the command executed successfully (return code = 0). | |
78 | */ | |
79 | public boolean enableEvents(String... enabledEvents) { | |
80 | if (enabledEvents == null || enabledEvents.length == 0) { | |
81 | throw new IllegalArgumentException(); | |
82 | } | |
83 | channelCreated = true; | |
84 | return executeCommand(Arrays.asList( | |
85 | "lttng", "enable-event", domain.flag(), | |
86 | Arrays.stream(enabledEvents).collect(Collectors.joining(",")), | |
87 | "-s", sessionName)); | |
88 | } | |
89 | ||
90 | /** | |
91 | * Send a disable-event command. Used to disable events that were previously | |
92 | * enabled. | |
93 | * | |
94 | * @param disabledEvents | |
95 | * The list of disabled events. Should not be null or empty | |
96 | * @return If the command executed successfully (return code = 0). | |
97 | */ | |
98 | public boolean disableEvents(String... disabledEvents) { | |
99 | if (disabledEvents == null || disabledEvents.length == 0) { | |
100 | throw new IllegalArgumentException(); | |
101 | } | |
102 | return executeCommand(Arrays.asList( | |
103 | "lttng", "disable-event", domain.flag(), | |
104 | Arrays.stream(disabledEvents).collect(Collectors.joining(",")), | |
105 | "-s", sessionName)); | |
106 | } | |
107 | ||
108 | public boolean start() { | |
109 | /* | |
110 | * We have to enable a channel for 'lttng start' to work. However, we | |
111 | * cannot enable a channel directly, see | |
112 | * https://bugs.lttng.org/issues/894 . Instead we will enable an event | |
113 | * we know does not exist | |
114 | */ | |
115 | if (!channelCreated) { | |
116 | enableEvents("non-event"); | |
117 | } | |
118 | return executeCommand(Arrays.asList("lttng", "start", sessionName)); | |
119 | } | |
120 | ||
121 | /** | |
122 | * Stop the tracing session | |
123 | * | |
124 | * @return If the command executed successfully (return code = 0). | |
125 | */ | |
126 | public boolean stop() { | |
127 | return executeCommand(Arrays.asList("lttng", "stop", sessionName)); | |
128 | } | |
129 | ||
130 | /** | |
131 | * Issue a "lttng view" command on the session, and returns its output. This | |
132 | * effectively returns the current content of the trace in text form. | |
133 | * | |
134 | * @return The output of Babeltrace on the session's current trace | |
135 | */ | |
136 | public List<String> view() { | |
137 | return TestUtils.getOutputFromCommand(Arrays.asList("lttng", "view", sessionName)); | |
138 | } | |
139 | ||
e41ec02a AM |
140 | /** |
141 | * Utility method to destroy all existing sessions. Useful when first | |
142 | * setting up a test to make sure no existing session interferes. | |
143 | */ | |
144 | public static void destroyAllSessions() { | |
145 | executeCommand(Arrays.asList("lttng", "destroy", "-a")); | |
146 | } | |
147 | ||
8576633f AM |
148 | /** |
149 | * Outside of the scope of lttng-tools, but this utility method can be used | |
150 | * to delete all traces currently under ~/lttng-traces/. This can be used by | |
151 | * tests to cleanup a trace they have created. | |
152 | * | |
153 | * @return True if the command completes successfully, false if there was an | |
154 | * error. | |
155 | */ | |
156 | public static boolean deleteAllTracee() { | |
157 | String tracesDir = new String(System.getProperty("user.home") + "/lttng-traces/"); | |
158 | return deleteDirectory(Paths.get(tracesDir)); | |
159 | } | |
160 | ||
161 | // ------------------------------------------------------------------------ | |
162 | // Private helper methods | |
163 | // ------------------------------------------------------------------------ | |
164 | ||
165 | private static boolean deleteDirectory(Path directory) { | |
166 | try { | |
167 | Files.walkFileTree(directory, new SimpleFileVisitor<Path>() { | |
168 | @Override | |
169 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { | |
170 | Files.delete(file); | |
171 | return FileVisitResult.CONTINUE; | |
172 | } | |
173 | ||
174 | @Override | |
175 | public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { | |
176 | Files.delete(dir); | |
177 | return FileVisitResult.CONTINUE; | |
178 | } | |
179 | }); | |
180 | } catch (IOException e) { | |
181 | /* At least we tried... */ | |
182 | return false; | |
183 | } | |
184 | return true; | |
185 | } | |
186 | ||
187 | /** | |
188 | * Just to test the environment / stdout are working correctly | |
189 | */ | |
190 | public static void main(String[] args) { | |
191 | List<String> command = Arrays.asList("ls", "-l"); | |
192 | executeCommand(command); | |
193 | } | |
194 | ||
195 | private static boolean executeCommand(List<String> command) { | |
196 | try { | |
197 | ProcessBuilder builder = new ProcessBuilder(command); | |
198 | builder.redirectErrorStream(true); | |
199 | builder.redirectOutput(Redirect.INHERIT); | |
200 | ||
201 | Process p = builder.start(); | |
202 | int ret = p.waitFor(); | |
203 | return (ret == 0); | |
204 | ||
205 | } catch (IOException | InterruptedException e) { | |
206 | return false; | |
207 | } | |
208 | } | |
209 | } |