import java.io.IOException;
import java.util.List;
-import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
private static final Domain DOMAIN = Domain.JUL;
+ private static final String SESSION_NAME = JulEnabledEventsTest.class.getSimpleName();
+
private static final String EVENT_NAME_A = "EventA";
private static final String EVENT_NAME_B = "EventAB";
private static final String EVENT_NAME_C = "EventABC";
private Logger loggerC;
private Logger loggerD;
- private Handler handlerA;
- private Handler handlerB;
- private Handler handlerC;
+ private LttngLogHandler handlerA;
+ private LttngLogHandler handlerB;
+ private LttngLogHandler handlerC;
@BeforeClass
public static void classSetup() {
}
boolean ret1 = LttngSessionControl.setupSession(null, DOMAIN);
- boolean ret2 = LttngSessionControl.stopSession();
- boolean ret3 = LttngSessionControl.destroySession();
+ boolean ret2 = LttngSessionControl.stopSession(null);
+ /* "lttng view" also tests that Babeltrace is installed and working */
+ List<String> contents = LttngSessionControl.viewSession(null);
+ boolean ret3 = LttngSessionControl.destroySession(null);
assumeTrue(ret1 && ret2 && ret3);
+ assumeTrue(contents.isEmpty());
+ }
+
+ @AfterClass
+ public static void classCleanup() {
+ LttngSessionControl.deleteAllTracee();
}
@Before
public void setup() throws SecurityException, IOException {
+ // TODO Wipe all existing LTTng sessions?
+
loggerA = Logger.getLogger(EVENT_NAME_A);
loggerB = Logger.getLogger(EVENT_NAME_B);
loggerC = Logger.getLogger(EVENT_NAME_C);
loggerA.addHandler(handlerA);
loggerB.addHandler(handlerB);
- loggerC.addHandler(handlerB);
+ loggerC.addHandler(handlerC);
}
@After
public void teardown() {
+ /* Just in case the test failed */
+ LttngSessionControl.tryDestroySession(SESSION_NAME);
+
loggerA.removeHandler(handlerA);
loggerB.removeHandler(handlerB);
loggerC.removeHandler(handlerC);
/**
* Test sending events on the Java side, but no events enabled in the
- * tracing session. There should be nothing in the resulting trace.
+ * tracing session. There should be nothing in the resulting trace, and
+ * handlers should not have logged anything.
*/
@Test
public void testNoEvents() {
- assertTrue(LttngSessionControl.setupSession(null, DOMAIN));
+ assertTrue(LttngSessionControl.setupSession(SESSION_NAME, DOMAIN));
send10Events(loggerA);
send10Events(loggerB);
send10Events(loggerC);
send10Events(loggerD);
- assertTrue(LttngSessionControl.stopSession());
+ assertTrue(LttngSessionControl.stopSession(SESSION_NAME));
- List<String> output = LttngSessionControl.viewSession();
+ List<String> output = LttngSessionControl.viewSession(SESSION_NAME);
assertNotNull(output);
assertTrue(output.isEmpty());
- assertTrue(LttngSessionControl.destroySession());
+ assertTrue(LttngSessionControl.destroySession(SESSION_NAME));
+
+ assertEquals(0, handlerA.getEventCount());
+ assertEquals(0, handlerB.getEventCount());
+ assertEquals(0, handlerC.getEventCount());
}
/**
*/
@Test
public void testAllEvents() {
- assertTrue(LttngSessionControl.setupSessionAllEvents(null, DOMAIN));
+ assertTrue(LttngSessionControl.setupSessionAllEvents(SESSION_NAME, DOMAIN));
send10Events(loggerA);
send10Events(loggerB);
send10Events(loggerC);
send10Events(loggerD);
- assertTrue(LttngSessionControl.stopSession());
+ assertTrue(LttngSessionControl.stopSession(SESSION_NAME));
- List<String> output = LttngSessionControl.viewSession();
+ List<String> output = LttngSessionControl.viewSession(SESSION_NAME);
assertNotNull(output);
- assertEquals(20, output.size()); // loggerC has no handler attached
+ assertEquals(30, output.size()); // loggerD has no handler attached
- assertTrue(LttngSessionControl.destroySession());
+ assertTrue(LttngSessionControl.destroySession(SESSION_NAME));
+
+ assertEquals(10, handlerA.getEventCount());
+ assertEquals(10, handlerB.getEventCount());
+ assertEquals(10, handlerC.getEventCount());
}
/**
*/
@Test
public void testSomeEvents() {
- assertTrue(LttngSessionControl.setupSession(null, DOMAIN,
- EVENT_NAME_A, EVENT_NAME_D));
+ assertTrue(LttngSessionControl.setupSession(SESSION_NAME, DOMAIN,
+ EVENT_NAME_A, EVENT_NAME_C, EVENT_NAME_D));
+
+ send10Events(loggerA);
+ send10Events(loggerB);
+ send10Events(loggerC);
+ send10Events(loggerD);
+
+ assertTrue(LttngSessionControl.stopSession(SESSION_NAME));
+
+ List<String> output = LttngSessionControl.viewSession(SESSION_NAME);
+ assertNotNull(output);
+ assertEquals(20, output.size());
+
+ assertTrue(LttngSessionControl.destroySession(SESSION_NAME));
+
+ assertEquals(10, handlerA.getEventCount());
+ assertEquals(0, handlerB.getEventCount());
+ assertEquals(10, handlerC.getEventCount());
+ }
+
+ /**
+ * Test with all events enabled (-a), plus some other events added manually.
+ * Events should still be retained, but there should be no duplicates.
+ */
+ @Test
+ public void testAllEventsAndSome() {
+ assertTrue(LttngSessionControl.setupSessionAllEvents(SESSION_NAME, DOMAIN));
+ assertTrue(LttngSessionControl.enableEvents(SESSION_NAME, DOMAIN,
+ EVENT_NAME_A, EVENT_NAME_B));
+
+ send10Events(loggerA);
+ send10Events(loggerB);
+ send10Events(loggerC);
+ send10Events(loggerD);
+
+ assertTrue(LttngSessionControl.stopSession(SESSION_NAME));
+
+ List<String> output = LttngSessionControl.viewSession(SESSION_NAME);
+ assertNotNull(output);
+ assertEquals(30, output.size());
+
+ assertTrue(LttngSessionControl.destroySession(SESSION_NAME));
+
+ assertEquals(10, handlerA.getEventCount());
+ assertEquals(10, handlerB.getEventCount());
+ assertEquals(10, handlerC.getEventCount());
+ }
+
+ /**
+ * Same as {@link #testSomeEvents()}, but some events were enabled first,
+ * then disabled. Makes sure the enabled-event refcounting works properly.
+ */
+ @Test
+ public void testSomeEventsAfterDisabling() {
+ assertTrue(LttngSessionControl.setupSession(SESSION_NAME, DOMAIN,
+ EVENT_NAME_A, EVENT_NAME_C, EVENT_NAME_D));
+
+ assertTrue(LttngSessionControl.disableEvents(SESSION_NAME, DOMAIN,
+ EVENT_NAME_C));
+
+ send10Events(loggerA);
+ send10Events(loggerB);
+ send10Events(loggerC);
+ send10Events(loggerD);
+
+ assertTrue(LttngSessionControl.stopSession(SESSION_NAME));
+
+ List<String> output = LttngSessionControl.viewSession(SESSION_NAME);
+ assertNotNull(output);
+ assertEquals(10, output.size());
+
+ assertTrue(LttngSessionControl.destroySession(SESSION_NAME));
+
+ assertEquals(10, handlerA.getEventCount());
+ assertEquals(0, handlerB.getEventCount());
+ assertEquals(0, handlerC.getEventCount());
+ }
+
+ /**
+ * Test enabling an event prefix, which means an event name ending with a *,
+ * to match all events starting with this name.
+ */
+ @Test
+ public void testEventPrefix() {
+ assertTrue(LttngSessionControl.setupSession(SESSION_NAME, DOMAIN,
+ "EventAB*")); // should match event/loggers B and C, but not A.
+
+ send10Events(loggerA);
+ send10Events(loggerB);
+ send10Events(loggerC);
+ send10Events(loggerD);
+
+ assertTrue(LttngSessionControl.stopSession(SESSION_NAME));
+
+ List<String> output = LttngSessionControl.viewSession(SESSION_NAME);
+ assertNotNull(output);
+ assertEquals(20, output.size());
+
+ assertTrue(LttngSessionControl.destroySession(SESSION_NAME));
+
+ assertEquals(0, handlerA.getEventCount());
+ assertEquals(10, handlerB.getEventCount());
+ assertEquals(10, handlerC.getEventCount());
+ }
+
+ /**
+ * Same as {@link #testEventPrefix()}, but with multiple prefixes that
+ * overlap. There should not be any duplicate events in the trace or in the
+ * handlers.
+ */
+ @Test
+ public void testEventPrefixOverlapping() {
+ assertTrue(LttngSessionControl.setupSession(SESSION_NAME, DOMAIN,
+ "EventAB*", "EventABC*")); // should still match B and C
send10Events(loggerA);
send10Events(loggerB);
send10Events(loggerC);
send10Events(loggerD);
- assertTrue(LttngSessionControl.stopSession());
+ assertTrue(LttngSessionControl.stopSession(SESSION_NAME));
- List<String> output = LttngSessionControl.viewSession();
+ List<String> output = LttngSessionControl.viewSession(SESSION_NAME);
assertNotNull(output);
- assertEquals(10, output.size()); // loggerC has no handler attached
+ assertEquals(20, output.size());
+
+ assertTrue(LttngSessionControl.destroySession(SESSION_NAME));
+
+ assertEquals(0, handlerA.getEventCount());
+ assertEquals(10, handlerB.getEventCount());
+ assertEquals(10, handlerC.getEventCount());
+ }
+
+ /**
+ * Test with all events enabled (-a), plus an event prefix. Once again,
+ * there should be no duplicates.
+ */
+ @Test
+ public void testAllEventsAndPrefix() {
+ assertTrue(LttngSessionControl.setupSessionAllEvents(SESSION_NAME, DOMAIN));
+ assertTrue(LttngSessionControl.enableEvents(SESSION_NAME, DOMAIN,
+ "EventAB*")); // should match B and C
+
+ send10Events(loggerA);
+ send10Events(loggerB);
+ send10Events(loggerC);
+ send10Events(loggerD);
+
+ assertTrue(LttngSessionControl.stopSession(SESSION_NAME));
+
+ List<String> output = LttngSessionControl.viewSession(SESSION_NAME);
+ assertNotNull(output);
+ assertEquals(30, output.size());
+
+ assertTrue(LttngSessionControl.destroySession(SESSION_NAME));
- assertTrue(LttngSessionControl.destroySession());
+ assertEquals(10, handlerA.getEventCount());
+ assertEquals(10, handlerB.getEventCount());
+ assertEquals(10, handlerC.getEventCount());
}
private static void send10Events(Logger logger) {
String a = new String("a");
- Object[] params = {a, new String("b"), new Object()};
+ Object[] params = { a, new String("b"), new Object() };
- // Levels are FINE, FINER, FINEST, INFO, SEVERE, WARNING
+ // Levels are FINE, FINER, FINEST, INFO, SEVERE, WARNING
logger.fine("A fine level message");
logger.finer("A finer level message");
logger.finest("A finest level message");
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
+import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
});
}
+ /**
+ * Send a separate enable-event command.
+ *
+ * @param sessionName
+ * Name of the session in which to enable events. Use null for
+ * current session.
+ * @param domain
+ * The tracing domain
+ * @param enabledEvents
+ * The list of events to enable. Should not be null or empty
+ * @return If the command executed successfully (return code = 0).
+ */
+ public static boolean enableEvents(String sessionName, Domain domain, String... enabledEvents) {
+ if (enabledEvents == null || enabledEvents.length == 0) {
+ throw new IllegalArgumentException();
+ }
+ List<String> command = new ArrayList<String>();
+ command.add("lttng");
+ command.add("enable-event");
+ command.add(domain.flag());
+ command.add(Arrays.stream(enabledEvents).collect(Collectors.joining(",")));
+ if (sessionName != null) {
+ command.add("-s");
+ command.add(sessionName);
+ }
+ return executeCommand(command.toArray(new String[0]));
+ }
+
+ /**
+ * Send a disable-event command. Used to disable events that were previously
+ * enabled.
+ *
+ * @param sessionName
+ * Name of the session in which to disable events. Use null for
+ * current session.
+ * @param domain
+ * The tracing domain
+ * @param disabledEvents
+ * The list of disabled events. Should not be null or empty
+ * @return If the command executed successfully (return code = 0).
+ */
+ public static boolean disableEvents(String sessionName, Domain domain, String... disabledEvents) {
+ if (disabledEvents == null || disabledEvents.length == 0) {
+ throw new IllegalArgumentException();
+ }
+ List<String> command = new ArrayList<String>();
+ command.add("lttng");
+ command.add("disable-event");
+ command.add(domain.flag());
+ command.add(Arrays.stream(disabledEvents).collect(Collectors.joining(",")));
+ if (sessionName != null) {
+ command.add("-s");
+ command.add(sessionName);
+ }
+ return executeCommand(command.toArray(new String[0]));
+ }
+
/**
* Stop the current tracing session
*
+ * @param sessionName
+ * The name of the session to stop. Use null for the current
+ * session.
* @return If the command executed successfully (return code = 0).
*/
- public static boolean stopSession() {
- return executeCommand(new String[] { "lttng", "stop" });
+ public static boolean stopSession(String sessionName) {
+ List<String> command = new ArrayList<String>();
+ command.add("lttng");
+ command.add("stop");
+ if (sessionName != null) {
+ command.add(sessionName);
+ }
+ return executeCommand(command.toArray(new String[0]));
}
- public static List<String> viewSession() {
- return getOutputFromCommand(new String[] { "lttng", "view" });
+ /**
+ * Issue a "lttng view" command on the provided session, and returns its
+ * output. This effectively returns the current content of the trace in text
+ * form.
+ *
+ * @param sessionName
+ * The name of the session to print. Use null for the current
+ * session.
+ * @return The output of Babeltrace on the session's current trace
+ */
+ public static List<String> viewSession(String sessionName) {
+ List<String> command = new ArrayList<String>();
+ command.add("lttng");
+ command.add("view");
+ if (sessionName != null) {
+ command.add(sessionName);
+ }
+ return getOutputFromCommand(command.toArray(new String[0]));
}
/**
* Destroy the current tracing session
*
+ * @param sessionName
+ * The name of the session to destroy. Use null for the current
+ * session.
* @return If the command executed successfully (return code = 0).
*/
- public static boolean destroySession() {
- return executeCommand(new String[] { "lttng", "destroy" });
+ public static boolean destroySession(String sessionName) {
+ List<String> command = new ArrayList<String>();
+ command.add("lttng");
+ command.add("destroy");
+ if (sessionName != null) {
+ command.add(sessionName);
+ }
+ return executeCommand(command.toArray(new String[0]));
+ }
+
+ /**
+ * Try destroying the given tracing session, fail silently if there is no
+ * session.
+ *
+ * @param sessionName
+ * The name of the session to destroy. Use null for the current
+ * session.
+ */
+ public static void tryDestroySession(String sessionName) {
+ getOutputFromCommand(false, new String[] { "lttng", "destroy" });
+ }
+
+ /**
+ * Outside of the scope of lttng-tools, but this utility method can be used
+ * to delete all traces currently under ~/lttng-traces/. This can be used by
+ * tests to cleanup a trace they have created.
+ *
+ * @return True if the command completes successfully, false if there was an
+ * error.
+ */
+ public static boolean deleteAllTracee() {
+ String tracesDir = new String(System.getProperty("user.home") + "/lttng-traces/");
+ return deleteDirectory(Paths.get(tracesDir));
+ }
+
+ private static boolean deleteDirectory(Path directory) {
+ try {
+ Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Files.delete(file);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ Files.delete(dir);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ } catch (IOException e) {
+ /* At least we tried... */
+ return false;
+ }
+ return true;
}
// ------------------------------------------------------------------------
}
private static List<String> getOutputFromCommand(String[] command) {
+ return getOutputFromCommand(true, command);
+ }
+
+ private static List<String> getOutputFromCommand(boolean print, String[] command) {
try {
Path tempFile = Files.createTempFile("test-output", null);
List<String> lines = Files.readAllLines(tempFile);
Files.delete(tempFile);
- /* Also print the output to the console */
- lines.stream().forEach(s -> System.out.println(s));
+ if (print) {
+ /* Also print the output to the console */
+ lines.stream().forEach(s -> System.out.println(s));
+ }
return lines;