# Java agent library
*.class
-liblttng-ust-agent*.jar
+lttng-ust-agent*.jar
classnoinst.stamp
jni-header.stamp
jul-jni-header.stamp
log4j-jni-header.stamp
org_lttng_ust_agent_jul_LTTngLogHandler.h
org_lttng_ust_agent_log4j_LTTngLogAppender.h
-liblttng-ust-java-agent/java/liblttng-ust-jul.jar
# Python agent
liblttng-ust-python-agent/__init__.py
liblttng-ust-java/Makefile
liblttng-ust-java-agent/Makefile
liblttng-ust-java-agent/java/Makefile
+ liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile
+ liblttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile
+ liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile
liblttng-ust-java-agent/jni/Makefile
liblttng-ust-java-agent/jni/jul/Makefile
liblttng-ust-java-agent/jni/log4j/Makefile
done; \
if [ x"$(SUBDIRS_JUL)" != x"" ]; then \
for subdir in $(SUBDIRS_JUL); do \
- (cd $(SUBDIRS_JUL) && $(MAKE) JAVA_CLASSPATH_OVERRIDE="../../../liblttng-ust-java-agent/java" JAVA_JARFILE_OVERRIDE="liblttng-ust-agent.jar" $(AM_MAKEFLAGS) all && cd ..) || exit 1; \
+ (cd $(SUBDIRS_JUL) && $(MAKE) JAVA_CLASSPATH_OVERRIDE_JUL="../../../liblttng-ust-java-agent/java/lttng-ust-agent-jul" JAVA_CLASSPATH_OVERRIDE_COMMON="../../../liblttng-ust-java-agent/java/lttng-ust-agent-common" $(AM_MAKEFLAGS) all && cd ..) || exit 1; \
done; \
fi; \
if [ x"$(SUBDIRS_LOG4J)" != x"" ]; then \
for subdir in $(SUBDIRS_LOG4J); do \
- (cd $(SUBDIRS_LOG4J) && $(MAKE) JAVA_CLASSPATH_OVERRIDE="../../../liblttng-ust-java-agent/java" JAVA_JARFILE_OVERRIDE="liblttng-ust-agent.jar" $(AM_MAKEFLAGS) all && cd ..) || exit 1; \
+ (cd $(SUBDIRS_LOG4J) && $(MAKE) JAVA_CLASSPATH_OVERRIDE_LOG4J="../../../liblttng-ust-java-agent/java/lttng-ust-agent-log4j" JAVA_CLASSPATH_OVERRIDE_COMMON="../../../liblttng-ust-java-agent/java/lttng-ust-agent-common" $(AM_MAKEFLAGS) all && cd ..) || exit 1; \
done; \
fi;
# This makefile is purposefully kept simple to support GNU and BSD make.
#
-# Default JUL jar name.
-JARFILE=liblttng-ust-agent.jar
+# Required JAR files for JUL
+JARFILE_JUL=lttng-ust-agent-jul.jar
+JARFILE_COMMON=lttng-ust-agent-common.jar
-# Check if the top level makefile overrides the JUL Jar file name.
-ifneq "$(JAVA_JARFILE_OVERRIDE)" ""
- JARFILE=$(JAVA_JARFILE_OVERRIDE)
+# Check if the top level makefile overrides the JUL Jar file's path.
+ifeq "$(JAVA_CLASSPATH_OVERRIDE_JUL)" ""
+ CLASSPATH=/usr/local/share/java/$(JARFILE_JUL):/usr/share/java/$(JARFILE_JUL)
+else
+ CLASSPATH=$(JAVA_CLASSPATH_OVERRIDE_JUL)/$(JARFILE_JUL)
endif
-# Check if the top level makefile overrides the JUL classpath.
-ifeq "$(JAVA_CLASSPATH_OVERRIDE)" ""
- CLASSPATH=/usr/local/share/java/$(JARFILE):/usr/share/java/$(JARFILE)
+# Check if the top level makefile overrides the Common Jar file's path.
+ifeq "$(JAVA_CLASSPATH_OVERRIDE_COMMON)" ""
+ CLASSPATH:=$(CLASSPATH):/usr/local/share/java/$(JARFILE_COMMON):/usr/share/java/$(JARFILE_COMMON)
else
- CLASSPATH=$(JAVA_CLASSPATH_OVERRIDE)/$(JARFILE)
+ CLASSPATH:=$(CLASSPATH):$(JAVA_CLASSPATH_OVERRIDE_COMMON)/$(JARFILE_COMMON)
endif
JFLAGS = -g
#
DIR=`dirname $0`
-JARFILE="liblttng-ust-agent.jar"
+JARFILE_COMMON="lttng-ust-agent-common.jar"
+JARFILE_JUL="lttng-ust-agent-jul.jar"
JAVA_OPTIONS=""
cd $DIR
if [ -f "$DIR/.intree" ]; then
- CLASSPATH="../../../liblttng-ust-java-agent/java/$JARFILE"
+ CLASSPATH="../../../liblttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON"
+ CLASSPATH="$CLASSPATH:../../../liblttng-ust-java-agent/java/lttng-ust-agent-jul/$JARFILE_JUL"
LIBPATH="../../../liblttng-ust-java-agent/jni/jul/.libs"
else
- CLASSPATH="/usr/local/share/java/$JARFILE:/usr/share/java/$JARFILE"
+ CLASSPATH="/usr/local/share/java/$JARFILE_COMMON:/usr/share/java/$JARFILE_COMMON"
+ CLASSPATH="$CLASSPATH:/usr/local/share/java/$JARFILE_JUL:/usr/share/java/$JARFILE_JUL"
# Use system defined java.library.path
#LIBPATH="/usr/local/lib:/usr/lib"
fi
if [ "x$LIBPATH" != "x" ]; then
- JAVA_OPTIONS="$JAVA_OPTIONS -Djava.library.path=\"$LIBPATH\""
+ JAVA_OPTIONS="$JAVA_OPTIONS -Djava.library.path=$LIBPATH"
fi
java -classpath "$CLASSPATH:." $JAVA_OPTIONS Hello
# This makefile is purposefully kept simple to support GNU and BSD make.
#
-JFLAGS = -g
-
-# Default JUL jar name.
-JARFILE=liblttng-ust-agent.jar
+# Required JAR files for Log4j
+JARFILE_LOG4J=lttng-ust-agent-log4j.jar
+JARFILE_COMMON=lttng-ust-agent-common.jar
# If system classpath is empty, try to guess log4j location
ifeq "$(CLASSPATH)" ""
CLASSPATH="/usr/local/share/java/log4j.jar:/usr/share/java/log4j.jar"
endif
-# Check if the top level makefile overrides the JUL Jar file name.
-ifneq "$(JAVA_JARFILE_OVERRIDE)" ""
- JARFILE=$(JAVA_JARFILE_OVERRIDE)
+# Check if the top level makefile overrides the Log4j Jar file's path.
+ifeq "$(JAVA_CLASSPATH_OVERRIDE_LOG4J)" ""
+ CLASSPATH:=$(CLASSPATH):/usr/local/share/java/$(JARFILE_LOG4J):/usr/share/java/$(JARFILE_LOG4J)
+else
+ CLASSPATH:=$(CLASSPATH):$(JAVA_CLASSPATH_OVERRIDE_LOG4J)/$(JARFILE_LOG4J)
endif
-# Check if the top level makefile overrides the JUL classpath.
-ifeq "$(JAVA_CLASSPATH_OVERRIDE)" ""
- CLASSPATH:=/usr/local/share/java/$(JARFILE):/usr/share/java/$(JARFILE):$(CLASSPATH)
+# Check if the top level makefile overrides the Common Jar file's path.
+ifeq "$(JAVA_CLASSPATH_OVERRIDE_COMMON)" ""
+ CLASSPATH:=$(CLASSPATH):/usr/local/share/java/$(JARFILE_COMMON):/usr/share/java/$(JARFILE_COMMON)
else
- CLASSPATH:=$(JAVA_CLASSPATH_OVERRIDE)/$(JARFILE):$(CLASSPATH)
+ CLASSPATH:=$(CLASSPATH):$(JAVA_CLASSPATH_OVERRIDE_COMMON)/$(JARFILE_COMMON)
endif
+JFLAGS = -g
JC = javac -classpath "$(CLASSPATH):."
.SUFFIXES: .java .class
.java.class:
#
DIR=`dirname $0`
-JARFILE="liblttng-ust-agent.jar"
+JARFILE_COMMON="lttng-ust-agent-common.jar"
+JARFILE_LOG4J="lttng-ust-agent-log4j.jar"
JAVA_OPTIONS=""
# If system classpath is empty, try to guess log4j location
cd $DIR
if [ -f "$DIR/.intree" ]; then
- CLASSPATH="../../../liblttng-ust-java-agent/java/$JARFILE:$CLASSPATH"
+ CLASSPATH="$CLASSPATH:../../../liblttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON"
+ CLASSPATH="$CLASSPATH:../../../liblttng-ust-java-agent/java/lttng-ust-agent-log4j/$JARFILE_LOG4J"
LIBPATH="../../../liblttng-ust-java-agent/jni/log4j/.libs"
else
- CLASSPATH="/usr/local/share/java/$JARFILE:/usr/share/java/$JARFILE:$CLASSPATH"
+ CLASSPATH="$CLASSPATH:/usr/local/share/java/$JARFILE_COMMON:/usr/share/java/$JARFILE_COMMON"
+ CLASSPATH="$CLASSPATH:/usr/local/share/java/$JARFILE_LOG4J:/usr/share/java/$JARFILE_LOG4J"
# Use system defined java.library.path
#LIBPATH="/usr/local/lib:/usr/lib"
fi
if [ "x$LIBPATH" != "x" ]; then
- JAVA_OPTIONS="$JAVA_OPTIONS -Djava.library.path=\"$LIBPATH\""
+ JAVA_OPTIONS="$JAVA_OPTIONS -Djava.library.path=$LIBPATH"
fi
java -classpath "$CLASSPATH:." $JAVA_OPTIONS Hello
-JAVAROOT = .
-
-pkgpath = org/lttng/ust/agent
-
-jarfile_version = 1.0.0
-jarfile_manifest = $(srcdir)/$(pkgpath)/Manifest.txt
-jarfile_symlink = liblttng-ust-agent.jar
-jarfile = liblttng-ust-agent-$(jarfile_version).jar
-
-jardir = $(datadir)/java
-
-juljniout = ../jni/jul
-log4jjniout = ../jni/log4j
-
-dist_noinst_JAVA = $(pkgpath)/LTTngAgent.java \
- $(pkgpath)/LTTngSessiondCmd2_6.java \
- $(pkgpath)/LTTngTCPSessiondClient.java \
- $(pkgpath)/LogFramework.java \
- $(pkgpath)/LogFrameworkSkeleton.java \
- $(pkgpath)/jul/LTTngJUL.java \
- $(pkgpath)/jul/LTTngLogHandler.java
-
-dist_noinst_DATA = $(jarfile_manifest)
-
-jar_DATA = $(jarfile)
-
-stamp =
-classes = $(pkgpath)/*.class
+SUBDIRS = lttng-ust-agent-common
if BUILD_JAVA_AGENT_WITH_JUL
-dist_noinst_JAVA += $(pkgpath)/jul/LTTngJUL.java \
- $(pkgpath)/jul/LTTngLogHandler.java
-stamp += jul-jni-header.stamp
-classes += $(pkgpath)/jul/*.class
+SUBDIRS += lttng-ust-agent-jul
endif
if BUILD_JAVA_AGENT_WITH_LOG4J
-dist_noinst_JAVA += $(pkgpath)/log4j/LTTngLog4j.java \
- $(pkgpath)/log4j/LTTngLogAppender.java
-stamp += log4j-jni-header.stamp
-classes += $(pkgpath)/log4j/*.class
+SUBDIRS += lttng-ust-agent-log4j
endif
-
-$(jarfile): classnoinst.stamp
- $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink)
-
-jul-jni-header.stamp: $(dist_noinst_JAVA)
- $(JAVAH) -classpath $(CLASSPATH):$(srcdir) -d $(juljniout) $(JAVAHFLAGS) org.lttng.ust.agent.jul.LTTngLogHandler && \
- echo "JUL JNI header generated" > jul-jni-header.stamp
-
-log4j-jni-header.stamp: $(dist_noinst_JAVA)
- $(JAVAH) -classpath $(CLASSPATH):$(srcdir) -d $(log4jjniout) $(JAVAHFLAGS) org.lttng.ust.agent.log4j.LTTngLogAppender && \
- echo "Log4j JNI header generated" > log4j-jni-header.stamp
-
-all-local: $(stamp)
-
-install-data-hook:
- cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink)
-
-uninstall-hook:
- cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink)
-
-CLEANFILES = $(jarfile) $(pkgpath)/*.class $(pkgpath)/jul/*.class \
- $(pkgpath)/log4j/*.class jul-jni-header.stamp log4j-jni-header.stamp \
- $(juljniout)/org_lttng_ust_agent_jul_LTTngLogHandler.h \
- $(log4jjniout)/org_lttng_ust_agent_log4j_LTTngLogAppender.h
--- /dev/null
+JAVAROOT = .
+
+pkgpath = org/lttng/ust/agent
+
+jarfile_version = 1.0.0
+jarfile_manifest = $(srcdir)/Manifest.txt
+jarfile_symlink = lttng-ust-agent-common.jar
+jarfile = lttng-ust-agent-common-$(jarfile_version).jar
+
+
+jardir = $(datadir)/java
+
+dist_noinst_JAVA = $(pkgpath)/LTTngAgent.java \
+ $(pkgpath)/LTTngSessiondCmd2_6.java \
+ $(pkgpath)/LTTngTCPSessiondClient.java \
+ $(pkgpath)/LogFramework.java \
+ $(pkgpath)/LogFrameworkSkeleton.java
+
+dist_noinst_DATA = $(jarfile_manifest)
+
+jar_DATA = $(jarfile)
+
+classes = $(pkgpath)/*.class
+
+$(jarfile):
+ $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink)
+
+all-local:
+
+install-data-hook:
+ cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink)
+
+uninstall-hook:
+ cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink)
+
+CLEANFILES = $(jarfile) $(pkgpath)/*.class
--- /dev/null
+Name: org/lttng/ust/agent/
+Specification-Title: LTTng UST Java Agent
+Specification-Version: 1.0.0
+Specification-Vendor: LTTng Project
+Implementation-Title: org.lttng.ust.agent
+Implementation-Version: 1.0.0
+Implementation-Vendor: LTTng Project
--- /dev/null
+/*
+ * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.lttng.ust.agent;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+public class LTTngAgent {
+
+ /* Domains */
+ static enum Domain {
+ JUL(3), LOG4J(4);
+ private int value;
+
+ private Domain(int value) {
+ this.value = value;
+ }
+
+ public int value() {
+ return value;
+ }
+ }
+
+ private static final int SEM_TIMEOUT = 3; /* Seconds */
+
+ private static LogFramework julUser;
+ private static LogFramework julRoot;
+ private static LogFramework log4jUser;
+ private static LogFramework log4jRoot;
+
+ /* Sessiond clients */
+ private static LTTngTCPSessiondClient julUserClient;
+ private static LTTngTCPSessiondClient julRootClient;
+ private static LTTngTCPSessiondClient log4jUserClient;
+ private static LTTngTCPSessiondClient log4jRootClient;
+
+ private static Thread sessiondThreadJULUser;
+ private static Thread sessiondThreadJULRoot;
+ private static Thread sessiondThreadLog4jUser;
+ private static Thread sessiondThreadLog4jRoot;
+
+ private boolean useJUL = false;
+ private boolean useLog4j = false;
+
+ /* Singleton agent object */
+ private static LTTngAgent curAgent = null;
+
+ /* Indicate if this object has been initialized. */
+ private static boolean initialized = false;
+
+ private static Semaphore registerSem;
+
+ /*
+ * Constructor is private. This is a singleton and a reference should be
+ * acquired using getLTTngAgent().
+ */
+ private LTTngAgent() {
+ initAgentJULClasses();
+
+ /* Since Log4j is a 3rd party JAR, we need to check if we can load any of its classes */
+ Boolean log4jLoaded = loadLog4jClasses();
+ if (log4jLoaded) {
+ initAgentLog4jClasses();
+ }
+
+ registerSem = new Semaphore(0, true);
+ }
+
+ private static Boolean loadLog4jClasses() {
+ Class<?> logging;
+
+ try {
+ logging = loadClass("org.apache.log4j.spi.LoggingEvent");
+ } catch (ClassNotFoundException e) {
+ /* Log4j classes not found, no need to create the relevant objects */
+ return false;
+ }
+
+ /*
+ * Detect capabilities of the log4j library. We only
+ * support log4j >= 1.2.15. The getTimeStamp() method
+ * was introduced in log4j 1.2.15, so verify that it
+ * is available.
+ *
+ * We can't rely on the getPackage().getImplementationVersion()
+ * call that would retrieves information from the manifest file
+ * found in the JAR since the manifest file shipped
+ * from upstream is known to be broken in several
+ * versions of the library.
+ *
+ * More info:
+ * https://issues.apache.org/bugzilla/show_bug.cgi?id=44370
+ */
+
+ try {
+ logging.getDeclaredMethod("getTimeStamp");
+ } catch (NoSuchMethodException e) {
+ System.err.println("Warning: The loaded log4j library is too old. Log4j tracing with LTTng will be disabled.");
+ return false;
+ } catch (NullPointerException e) {
+ /* Should never happen */
+ return false;
+ } catch (SecurityException e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private static Class<?> loadClass(String className) throws ClassNotFoundException {
+ ClassLoader loader;
+ Class<?> loadedClass;
+
+ try {
+ /* Try to load class using the current thread's context class loader */
+ loader = Thread.currentThread().getContextClassLoader();
+ loadedClass = loader.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ /* Loading failed, try using the system class loader */
+ loader = ClassLoader.getSystemClassLoader();
+ loadedClass = loader.loadClass(className);
+ }
+
+ return loadedClass;
+ }
+
+ private void initAgentJULClasses() {
+ try {
+ Class<?> lttngJUL = loadClass("org.lttng.ust.agent.jul.LTTngJUL");
+ julUser = (LogFramework) lttngJUL.getDeclaredConstructor(new Class[] { Boolean.class }).newInstance(false);
+ julRoot = (LogFramework) lttngJUL.getDeclaredConstructor(new Class[] { Boolean.class }).newInstance(true);
+ this.useJUL = true;
+ } catch (ClassNotFoundException e) {
+ /* LTTng JUL classes not found, no need to create the relevant objects */
+ this.useJUL = false;
+ } catch (InstantiationException e) {
+ this.useJUL = false;
+ } catch (NoSuchMethodException e) {
+ this.useJUL = false;
+ } catch (IllegalAccessException e) {
+ this.useJUL = false;
+ } catch (InvocationTargetException e) {
+ this.useJUL = false;
+ }
+ }
+
+ private void initAgentLog4jClasses() {
+ try {
+ Class<?> lttngLog4j = loadClass("org.lttng.ust.agent.log4j.LTTngLog4j");
+ log4jUser = (LogFramework)lttngLog4j.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(false);
+ log4jRoot = (LogFramework)lttngLog4j.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(true);
+ this.useLog4j = true;
+ } catch (ClassNotFoundException e) {
+ /* LTTng Log4j classes not found, no need to create the relevant objects */
+ this.useLog4j = false;
+ } catch (InstantiationException e) {
+ this.useLog4j = false;
+ } catch (NoSuchMethodException e) {
+ this.useLog4j = false;
+ } catch (IllegalAccessException e) {
+ this.useLog4j = false;
+ } catch (InvocationTargetException e) {
+ this.useLog4j = false;
+ }
+ }
+
+ /*
+ * Public getter to acquire a reference to this singleton object.
+ */
+ public static synchronized LTTngAgent getLTTngAgent() throws IOException {
+ if (curAgent == null) {
+ curAgent = new LTTngAgent();
+ curAgent.init();
+ }
+
+ return curAgent;
+ }
+
+ private synchronized void init() throws SecurityException {
+ if (initialized) {
+ return;
+ }
+
+ Integer numJULThreads = 0;
+ Integer numLog4jThreads = 0;
+
+ if (this.useJUL) {
+ numJULThreads = initJULClientThreads();
+ }
+
+ if (this.useLog4j) {
+ numLog4jThreads = initLog4jClientThreads();
+ }
+
+ Integer numThreads = numJULThreads + numLog4jThreads;
+
+ /* Wait for each registration to end. */
+ try {
+ registerSem.tryAcquire(numThreads,
+ SEM_TIMEOUT,
+ TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ initialized = true;
+ }
+
+ private synchronized static Integer initJULClientThreads() {
+ Integer numThreads = 2;
+
+ /* Handle user session daemon if any. */
+ julUserClient = new LTTngTCPSessiondClient(Domain.JUL,
+ julUser,
+ registerSem);
+
+ String userThreadName = "LTTng UST agent JUL user thread";
+ sessiondThreadJULUser = new Thread(julUserClient, userThreadName);
+ sessiondThreadJULUser.setDaemon(true);
+ sessiondThreadJULUser.start();
+
+ /* Handle root session daemon. */
+ julRootClient = new LTTngTCPSessiondClient(Domain.JUL,
+ julRoot,
+ registerSem);
+
+ String rootThreadName = "LTTng UST agent JUL root thread";
+ sessiondThreadJULRoot = new Thread(julRootClient, rootThreadName);
+ sessiondThreadJULRoot.setDaemon(true);
+ sessiondThreadJULRoot.start();
+
+ return numThreads;
+ }
+
+ private synchronized static Integer initLog4jClientThreads() {
+ Integer numThreads = 2;
+
+ log4jUserClient = new LTTngTCPSessiondClient(Domain.LOG4J,
+ log4jUser,
+ registerSem);
+
+ String userThreadName = "LTTng UST agent Log4j user thread";
+ sessiondThreadLog4jUser = new Thread(log4jUserClient, userThreadName);
+ sessiondThreadLog4jUser.setDaemon(true);
+ sessiondThreadLog4jUser.start();
+
+ log4jRootClient = new LTTngTCPSessiondClient(Domain.LOG4J,
+ log4jRoot,
+ registerSem);
+
+ String rootThreadName = "LTTng UST agent Log4j root thread";
+ sessiondThreadLog4jRoot = new Thread(log4jRootClient,rootThreadName);
+ sessiondThreadLog4jRoot.setDaemon(true);
+ sessiondThreadLog4jRoot.start();
+
+ return numThreads;
+ }
+
+
+ public void dispose() throws IOException {
+ if (this.useJUL) {
+ julUserClient.destroy();
+ julRootClient.destroy();
+ julUser.reset();
+ julRoot.reset();
+ }
+
+ if (this.useLog4j) {
+ log4jUserClient.destroy();
+ log4jRootClient.destroy();
+ log4jUser.reset();
+ log4jRoot.reset();
+ }
+
+ try {
+ if (this.useJUL) {
+ sessiondThreadJULUser.join();
+ sessiondThreadJULRoot.join();
+ }
+
+ if (this.useLog4j) {
+ sessiondThreadLog4jUser.join();
+ sessiondThreadLog4jRoot.join();
+ }
+
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.lttng.ust.agent;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+interface LTTngSessiondCmd2_6 {
+
+ /**
+ * Maximum name length for a logger name to be send to sessiond.
+ */
+ int NAME_MAX = 255;
+
+ /*
+ * Size of a primitive type int in byte. Because you know, Java can't
+ * provide that since it does not makes sense...
+ *
+ *
+ */
+ int INT_SIZE = 4;
+
+ interface SessiondResponse {
+ /**
+ * Gets a byte array of the command so that it may be streamed
+ *
+ * @return the byte array of the command
+ */
+ public byte[] getBytes();
+ }
+
+ interface SessiondCommand {
+ /**
+ * Populate the class from a byte array
+ *
+ * @param data
+ * the byte array containing the streamed command
+ */
+ public void populate(byte[] data);
+ }
+
+ enum lttng_agent_command {
+ /** List logger(s). */
+ CMD_LIST(1),
+ /** Enable logger by name. */
+ CMD_ENABLE(2),
+ /** Disable logger by name. */
+ CMD_DISABLE(3),
+ /** Registration done */
+ CMD_REG_DONE(4);
+
+ private int code;
+
+ private lttng_agent_command(int c) {
+ code = c;
+ }
+
+ public int getCommand() {
+ return code;
+ }
+ }
+
+ enum lttng_agent_ret_code {
+ CODE_SUCCESS_CMD(1),
+ CODE_INVALID_CMD(2),
+ CODE_UNK_LOGGER_NAME(3);
+ private int code;
+
+ private lttng_agent_ret_code(int c) {
+ code = c;
+ }
+
+ public int getCode() {
+ return code;
+ }
+ }
+
+ class sessiond_hdr implements SessiondCommand {
+
+ /** ABI size of command header. */
+ public final static int SIZE = 16;
+ /** Payload size in bytes following this header. */
+ public long dataSize;
+ /** Command type. */
+ public lttng_agent_command cmd;
+ /** Command version. */
+ public int cmdVersion;
+
+ @Override
+ public void populate(byte[] data) {
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ buf.order(ByteOrder.BIG_ENDIAN);
+
+ dataSize = buf.getLong();
+ cmd = lttng_agent_command.values()[buf.getInt() - 1];
+ cmdVersion = buf.getInt();
+ }
+ }
+
+ class sessiond_enable_handler implements SessiondResponse, SessiondCommand {
+
+ private static final int SIZE = 4;
+ public String name;
+ public int lttngLogLevel;
+ public int lttngLogLevelType;
+
+ /** Return status code to the session daemon. */
+ public lttng_agent_ret_code code;
+
+ @Override
+ public void populate(byte[] data) {
+ int dataOffset = INT_SIZE * 2;
+
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ lttngLogLevel = buf.getInt();
+ lttngLogLevelType = buf.getInt();
+ name = new String(data, dataOffset, data.length - dataOffset).trim();
+ }
+
+ @Override
+ public byte[] getBytes() {
+ byte data[] = new byte[SIZE];
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ buf.order(ByteOrder.BIG_ENDIAN);
+ buf.putInt(code.getCode());
+ return data;
+ }
+
+ /**
+ * Execute enable handler action which is to enable the given handler
+ * to the received name.
+ */
+ public void execute(LogFramework log) {
+ if (log.enableLogger(this.name)) {
+ this.code = lttng_agent_ret_code.CODE_SUCCESS_CMD;
+ } else {
+ this.code = lttng_agent_ret_code.CODE_INVALID_CMD;
+ }
+ }
+ }
+
+ class sessiond_disable_handler implements SessiondResponse, SessiondCommand {
+
+ private final static int SIZE = 4;
+ public String name;
+
+
+ /** Return status code to the session daemon. */
+ public lttng_agent_ret_code code;
+
+ @Override
+ public void populate(byte[] data) {
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ name = new String(data).trim();
+ }
+
+ @Override
+ public byte[] getBytes() {
+ byte data[] = new byte[SIZE];
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ buf.order(ByteOrder.BIG_ENDIAN);
+ buf.putInt(code.getCode());
+ return data;
+ }
+
+ /**
+ * Execute disable handler action which is to disable the given handler
+ * to the received name.
+ */
+ public void execute(LogFramework log) {
+ if (log.disableLogger(this.name)) {
+ this.code = lttng_agent_ret_code.CODE_SUCCESS_CMD;
+ } else {
+ this.code = lttng_agent_ret_code.CODE_INVALID_CMD;
+ }
+ }
+ }
+
+ class sessiond_list_logger implements SessiondResponse {
+
+ private final static int SIZE = 12;
+
+ private int dataSize = 0;
+ private int nbLogger = 0;
+
+ List<String> loggerList = new ArrayList<String>();
+
+ /** Return status code to the session daemon. */
+ public lttng_agent_ret_code code;
+
+ @Override
+ public byte[] getBytes() {
+ byte data[] = new byte[SIZE + dataSize];
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ buf.order(ByteOrder.BIG_ENDIAN);
+
+ /* Returned code */
+ buf.putInt(code.getCode());
+ buf.putInt(dataSize);
+ buf.putInt(nbLogger);
+
+ for (String logger: loggerList) {
+ buf.put(logger.getBytes());
+ /* NULL terminated byte after the logger name. */
+ buf.put((byte) 0x0);
+ }
+ return data;
+ }
+
+ public void execute(LogFramework log) {
+ String loggerName;
+
+ Iterator<String> loggers = log.listLoggers();
+ while (loggers.hasNext()) {
+ loggerName = loggers.next();
+ this.loggerList.add(loggerName);
+ this.nbLogger++;
+ this.dataSize += loggerName.length() + 1;
+ }
+
+ this.code = lttng_agent_ret_code.CODE_SUCCESS_CMD;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.lttng.ust.agent;
+
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.concurrent.Semaphore;
+
+class LTTngTCPSessiondClient implements Runnable {
+
+ private static final String SESSION_HOST = "127.0.0.1";
+ private static final String ROOT_PORT_FILE = "/var/run/lttng/agent.port";
+ private static final String USER_PORT_FILE = "/.lttng/agent.port";
+
+ private static Integer protocolMajorVersion = 1;
+ private static Integer protocolMinorVersion = 0;
+
+ /* Command header from the session deamon. */
+ private LTTngSessiondCmd2_6.sessiond_hdr headerCmd =
+ new LTTngSessiondCmd2_6.sessiond_hdr();
+
+ private Socket sessiondSock;
+ private volatile boolean quit = false;
+
+ private DataInputStream inFromSessiond;
+ private DataOutputStream outToSessiond;
+
+ private LogFramework log;
+
+ private Semaphore registerSem;
+
+
+ private LTTngAgent.Domain agentDomain;
+
+ /* Indicate if we've already released the semaphore. */
+ private boolean semPosted = false;
+
+ public LTTngTCPSessiondClient(LTTngAgent.Domain domain, LogFramework log, Semaphore sem) {
+ this.agentDomain = domain;
+ this.log = log;
+ this.registerSem = sem;
+ }
+
+ /*
+ * Try to release the registerSem if it's not already done.
+ */
+ private void tryReleaseSem() {
+ /* Release semaphore so we unblock the agent. */
+ if (!this.semPosted) {
+ this.registerSem.release();
+ this.semPosted = true;
+ }
+ }
+
+ @Override
+ public void run() {
+ for (;;) {
+ if (this.quit) {
+ break;
+ }
+
+ /* Cleanup Agent state before trying to connect or reconnect. */
+ this.log.reset();
+
+ try {
+
+ /*
+ * Connect to the session daemon before anything else.
+ */
+ connectToSessiond();
+
+ /*
+ * Register to the session daemon as the Java component of the
+ * UST application.
+ */
+ registerToSessiond();
+
+ /*
+ * Block on socket receive and wait for command from the
+ * session daemon. This will return if and only if there is a
+ * fatal error or the socket closes.
+ */
+ handleSessiondCmd();
+ } catch (UnknownHostException uhe) {
+ tryReleaseSem();
+ System.out.println(uhe);
+ } catch (IOException ioe) {
+ tryReleaseSem();
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } catch (Exception e) {
+ tryReleaseSem();
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void destroy() {
+ this.quit = true;
+
+ try {
+ if (this.sessiondSock != null) {
+ this.sessiondSock.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /*
+ * Receive header data from the session daemon using the LTTng command
+ * static buffer of the right size.
+ */
+ private void recvHeader() throws Exception {
+ byte data[] = new byte[LTTngSessiondCmd2_6.sessiond_hdr.SIZE];
+
+ int readLen = this.inFromSessiond.read(data, 0, data.length);
+ if (readLen != data.length) {
+ throw new IOException();
+ }
+ this.headerCmd.populate(data);
+ }
+
+ /*
+ * Receive payload from the session daemon. This MUST be done after a
+ * recvHeader() so the header value of a command are known.
+ *
+ * The caller SHOULD use isPayload() before which returns true if a payload
+ * is expected after the header.
+ */
+ private byte[] recvPayload() throws Exception {
+ byte payload[] = new byte[(int) this.headerCmd.dataSize];
+
+ /* Failsafe check so we don't waste our time reading 0 bytes. */
+ if (payload.length == 0) {
+ return null;
+ }
+
+ this.inFromSessiond.read(payload, 0, payload.length);
+ return payload;
+ }
+
+ /*
+ * Handle session command from the session daemon.
+ */
+ private void handleSessiondCmd() throws Exception {
+ byte data[] = null;
+
+ while (true) {
+ /* Get header from session daemon. */
+ recvHeader();
+
+ if (headerCmd.dataSize > 0) {
+ data = recvPayload();
+ }
+
+ switch (headerCmd.cmd) {
+ case CMD_REG_DONE:
+ {
+ /*
+ * Release semaphore so meaning registration is done and we
+ * can proceed to continue tracing.
+ */
+ tryReleaseSem();
+ /*
+ * We don't send any reply to the registration done command.
+ * This just marks the end of the initial session setup.
+ */
+ continue;
+ }
+ case CMD_LIST:
+ {
+ LTTngSessiondCmd2_6.sessiond_list_logger listLoggerCmd =
+ new LTTngSessiondCmd2_6.sessiond_list_logger();
+ listLoggerCmd.execute(this.log);
+ data = listLoggerCmd.getBytes();
+ break;
+ }
+ case CMD_ENABLE:
+ {
+ LTTngSessiondCmd2_6.sessiond_enable_handler enableCmd =
+ new LTTngSessiondCmd2_6.sessiond_enable_handler();
+ if (data == null) {
+ enableCmd.code = LTTngSessiondCmd2_6.lttng_agent_ret_code.CODE_INVALID_CMD;
+ break;
+ }
+ enableCmd.populate(data);
+ enableCmd.execute(this.log);
+ data = enableCmd.getBytes();
+ break;
+ }
+ case CMD_DISABLE:
+ {
+ LTTngSessiondCmd2_6.sessiond_disable_handler disableCmd =
+ new LTTngSessiondCmd2_6.sessiond_disable_handler();
+ if (data == null) {
+ disableCmd.code = LTTngSessiondCmd2_6.lttng_agent_ret_code.CODE_INVALID_CMD;
+ break;
+ }
+ disableCmd.populate(data);
+ disableCmd.execute(this.log);
+ data = disableCmd.getBytes();
+ break;
+ }
+ default:
+ {
+ data = new byte[4];
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ buf.order(ByteOrder.BIG_ENDIAN);
+ break;
+ }
+ }
+
+ /* Send payload to session daemon. */
+ this.outToSessiond.write(data, 0, data.length);
+ this.outToSessiond.flush();
+ }
+ }
+
+ private static String getHomePath() {
+ return System.getProperty("user.home");
+ }
+
+ /**
+ * Read port number from file created by the session daemon.
+ *
+ * @return port value if found else 0.
+ */
+ private static int getPortFromFile(String path) throws IOException {
+ int port;
+ BufferedReader br;
+
+ try {
+ br = new BufferedReader(new FileReader(path));
+ String line = br.readLine();
+ port = Integer.parseInt(line, 10);
+ if (port < 0 || port > 65535) {
+ /* Invalid value. Ignore. */
+ port = 0;
+ }
+ br.close();
+ } catch (FileNotFoundException e) {
+ /* No port available. */
+ port = 0;
+ }
+
+ return port;
+ }
+
+ private void connectToSessiond() throws Exception {
+ int port;
+
+ if (this.log.isRoot()) {
+ port = getPortFromFile(ROOT_PORT_FILE);
+ if (port == 0) {
+ /* No session daemon available. Stop and retry later. */
+ throw new IOException();
+ }
+ } else {
+ port = getPortFromFile(getHomePath() + USER_PORT_FILE);
+ if (port == 0) {
+ /* No session daemon available. Stop and retry later. */
+ throw new IOException();
+ }
+ }
+
+ this.sessiondSock = new Socket(SESSION_HOST, port);
+ this.inFromSessiond = new DataInputStream(sessiondSock.getInputStream());
+ this.outToSessiond = new DataOutputStream(sessiondSock.getOutputStream());
+ }
+
+ private void registerToSessiond() throws Exception {
+ byte data[] = new byte[16];
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
+
+ buf.putInt(this.agentDomain.value());
+ buf.putInt(Integer.parseInt(pid));
+ buf.putInt(protocolMajorVersion);
+ buf.putInt(protocolMinorVersion);
+ this.outToSessiond.write(data, 0, data.length);
+ this.outToSessiond.flush();
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.lttng.ust.agent;
+
+import java.util.Iterator;
+
+interface LogFramework {
+ Boolean enableLogger(String name);
+ Boolean disableLogger(String name);
+ Iterator<String> listLoggers();
+ Boolean isRoot();
+ void reset();
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.lttng.ust.agent;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+public abstract class LogFrameworkSkeleton implements LogFramework {
+
+ /* A map of event name and reference count */
+ private final Map<String, Integer> enabledLoggers;
+
+ public LogFrameworkSkeleton() {
+ this.enabledLoggers = new HashMap<String, Integer>();
+ }
+
+ @Override
+ public Boolean enableLogger(String name) {
+ if (name == null) {
+ return false;
+ }
+
+ if (enabledLoggers.containsKey(name)) {
+ /* Event is already enabled, simply increment its refcount */
+ Integer refcount = enabledLoggers.get(name);
+ refcount++;
+ Integer oldval = enabledLoggers.put(name, refcount);
+ assert (oldval != null);
+ } else {
+ /* Event was not enabled, init refcount to 1 */
+ Integer oldval = enabledLoggers.put(name, 1);
+ assert (oldval == null);
+ }
+
+ return true;
+ }
+
+ @Override
+ public Boolean disableLogger(String name) {
+ if (name == null) {
+ return false;
+ }
+
+ if (!enabledLoggers.containsKey(name)) {
+ /* Event was never enabled, abort */
+ return false;
+ }
+
+ /* Event was previously enabled, simply decrement its refcount */
+ Integer refcount = enabledLoggers.get(name);
+ refcount--;
+ assert (refcount >= 0);
+
+ if (refcount == 0) {
+ /* Event is not used anymore, remove it from the map */
+ Integer oldval = enabledLoggers.remove(name);
+ assert (oldval != null);
+ }
+
+ return true;
+ }
+
+ @Override
+ public abstract Iterator<String> listLoggers();
+
+ @Override
+ public abstract Boolean isRoot();
+
+ @Override
+ public void reset() {
+ enabledLoggers.clear();
+ }
+
+ protected Integer getEventCount() {
+ return enabledLoggers.size();
+ }
+}
--- /dev/null
+JAVAROOT = .
+CLASSPATH_ENV = CLASSPATH=$(CLASSPATH):$(builddir)/../lttng-ust-agent-common/lttng-ust-agent-common.jar
+
+pkgpath = org/lttng/ust/agent/jul
+
+jarfile_version = 1.0.0
+jarfile_manifest = $(srcdir)/Manifest.txt
+jarfile_symlink = lttng-ust-agent-jul.jar
+jarfile = lttng-ust-agent-jul-$(jarfile_version).jar
+
+jardir = $(datadir)/java
+
+juljniout = ../../jni/jul
+
+dist_noinst_JAVA = $(pkgpath)/LTTngJUL.java \
+ $(pkgpath)/LTTngLogHandler.java
+
+dist_noinst_DATA = $(jarfile_manifest)
+
+jar_DATA = $(jarfile)
+
+stamp = jul-jni-header.stamp
+classes = $(pkgpath)/*.class
+
+$(jarfile): classnoinst.stamp
+ $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink)
+
+jul-jni-header.stamp: $(dist_noinst_JAVA)
+ $(JAVAH) -classpath $(CLASSPATH):$(srcdir) -d $(juljniout) $(JAVAHFLAGS) org.lttng.ust.agent.jul.LTTngLogHandler && \
+ echo "JUL JNI header generated" > jul-jni-header.stamp
+
+all-local: $(stamp)
+
+install-data-hook:
+ cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink)
+
+uninstall-hook:
+ cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink)
+
+CLEANFILES = $(jarfile) $(pkgpath)/*.class jul-jni-header.stamp \
+ $(juljniout)/org_lttng_ust_agent_jul_LTTngLogHandler.h
--- /dev/null
+Name: org/lttng/ust/agent/jul/
+Specification-Title: LTTng UST Java Agent JUL Integration
+Specification-Version: 1.0.0
+Specification-Vendor: LTTng Project
+Implementation-Title: org.lttng.ust.agent.jul
+Implementation-Version: 1.0.0
+Implementation-Vendor: LTTng Project
+Class-Path: lttng-ust-agent-common.jar
--- /dev/null
+/*
+ * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.lttng.ust.agent.jul;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Vector;
+
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+import org.lttng.ust.agent.LogFrameworkSkeleton;
+
+public class LTTngJUL extends LogFrameworkSkeleton {
+
+ private LTTngLogHandler handler;
+ private Boolean attached;
+
+ public LTTngJUL(Boolean isRoot) {
+ super();
+ this.handler = new LTTngLogHandler(isRoot);
+ this.attached = false;
+ }
+
+ @Override
+ public Boolean enableLogger(String name) {
+ if(!super.enableLogger(name)) {
+ return false;
+ }
+
+ /* The first enable of any event triggers the attachment to the root logger */
+ if (getEventCount() == 1 && !this.attached) {
+ attachToRootLogger();
+ }
+
+ return true;
+ }
+
+ @Override
+ public Boolean disableLogger(String name) {
+ if(!super.disableLogger(name)) {
+ return false;
+ }
+
+ /* Detach from the root logger when the event count reach zero */
+ if (getEventCount() == 0 && this.attached) {
+ detachFromRootLogger();
+ }
+
+ return true;
+ }
+
+ @Override
+ public Iterator<String> listLoggers() {
+ Vector<String> logs = new Vector<String>();
+ for (Enumeration<String> loggers = LogManager.getLogManager().getLoggerNames(); loggers.hasMoreElements(); ) {
+ String name = loggers.nextElement();
+ /* Skip the root logger */
+ if (name.equals("")) {
+ continue;
+ }
+
+ logs.add(name);
+ }
+
+ return logs.iterator();
+ }
+
+ @Override
+ public Boolean isRoot() {
+ return handler.isRoot();
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ detachFromRootLogger();
+ }
+
+ private void attachToRootLogger() {
+ if (this.attached) {
+ return;
+ }
+
+ Logger rootLogger = LogManager.getLogManager().getLogger("");
+ rootLogger.addHandler(this.handler);
+ this.attached = true;
+ }
+
+ private void detachFromRootLogger() {
+ if (!this.attached) {
+ return;
+ }
+
+ Logger rootLogger = LogManager.getLogManager().getLogger("");
+ rootLogger.removeHandler(this.handler);
+ this.attached = false;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.lttng.ust.agent.jul;
+
+import java.lang.String;
+
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+
+class LTTngLogHandler extends Handler {
+
+ private final Boolean isRoot;
+
+ public LTTngLogHandler(Boolean isRoot) {
+ super();
+ this.isRoot = isRoot;
+ /* Initialize LTTng UST tracer. */
+ try {
+ System.loadLibrary("lttng-ust-jul-jni"); //$NON-NLS-1$
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (UnsatisfiedLinkError e) {
+ e.printStackTrace();
+ } catch (NullPointerException e) {
+ /* Should never happen */
+ e.printStackTrace();
+ }
+ }
+
+ public Boolean isRoot() {
+ return this.isRoot;
+ }
+
+ @Override
+ public void close() throws SecurityException {}
+
+ @Override
+ public void flush() {}
+
+ @Override
+ public void publish(LogRecord record) {
+ /*
+ * Specific tracepoint designed for JUL events. The source class of the
+ * caller is used for the event name, the raw message is taken, the
+ * loglevel of the record and the thread ID.
+ */
+ if (this.isRoot) {
+ tracepointS(record.getMessage(),
+ record.getLoggerName(), record.getSourceClassName(),
+ record.getSourceMethodName(), record.getMillis(),
+ record.getLevel().intValue(), record.getThreadID());
+ } else {
+ tracepointU(record.getMessage(),
+ record.getLoggerName(), record.getSourceClassName(),
+ record.getSourceMethodName(), record.getMillis(),
+ record.getLevel().intValue(), record.getThreadID());
+ }
+ }
+
+ /* Use for a user session daemon. */
+ private native void tracepointU(String msg,
+ String logger_name,
+ String class_name,
+ String method_name,
+ long millis,
+ int log_level,
+ int thread_id);
+
+ /* Use for a root session daemon. */
+ private native void tracepointS(String msg,
+ String logger_name,
+ String class_name,
+ String method_name,
+ long millis,
+ int log_level,
+ int thread_id);
+}
--- /dev/null
+JAVAROOT = .
+CLASSPATH_ENV = CLASSPATH=$(CLASSPATH):$(builddir)/../lttng-ust-agent-common/lttng-ust-agent-common.jar
+
+pkgpath = org/lttng/ust/agent/log4j
+
+jarfile_version = 1.0.0
+jarfile_manifest = $(srcdir)/Manifest.txt
+jarfile_symlink = lttng-ust-agent-log4j.jar
+jarfile = lttng-ust-agent-log4j-$(jarfile_version).jar
+
+jardir = $(datadir)/java
+
+log4jjniout = ../../jni/log4j
+
+dist_noinst_JAVA = $(pkgpath)/LTTngLog4j.java \
+ $(pkgpath)/LTTngLogAppender.java
+
+dist_noinst_DATA = $(jarfile_manifest)
+
+jar_DATA = $(jarfile)
+
+stamp = log4j-jni-header.stamp
+classes = $(pkgpath)/*.class
+
+$(jarfile): classnoinst.stamp
+ $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink)
+
+log4j-jni-header.stamp: $(dist_noinst_JAVA)
+ $(JAVAH) -classpath $(CLASSPATH):$(srcdir) -d $(log4jjniout) $(JAVAHFLAGS) org.lttng.ust.agent.log4j.LTTngLogAppender && \
+ echo "Log4j JNI header generated" > log4j-jni-header.stamp
+
+all-local: $(stamp)
+
+install-data-hook:
+ cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink)
+
+uninstall-hook:
+ cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink)
+
+CLEANFILES = $(jarfile) $(pkgpath)/*.class log4j-jni-header.stamp \
+ $(log4jjniout)/org_lttng_ust_agent_log4j_LTTngLogAppender.h
--- /dev/null
+Name: org/lttng/ust/agent/log4j/
+Specification-Title: LTTng UST Java Agent Log4J 1.x Integration
+Specification-Version: 1.0.0
+Specification-Vendor: LTTng Project
+Implementation-Title: org.lttng.ust.agent.log4j
+Implementation-Version: 1.0.0
+Implementation-Vendor: LTTng Project
+Class-Path: lttng-ust-agent-common.jar
--- /dev/null
+/*
+ * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.lttng.ust.agent.log4j;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+
+import org.lttng.ust.agent.LogFrameworkSkeleton;
+
+public class LTTngLog4j extends LogFrameworkSkeleton {
+
+ private LTTngLogAppender appender;
+ private Boolean attached;
+
+ public LTTngLog4j(Boolean isRoot) {
+ super();
+ this.appender = new LTTngLogAppender(isRoot);
+ this.attached = false;
+ }
+
+ @Override
+ public Boolean enableLogger(String name) {
+ if(!super.enableLogger(name)) {
+ return false;
+ }
+
+ /* The first enable of any event triggers the attachment to the root logger */
+ if (getEventCount() == 1 && !this.attached) {
+ attachToRootLogger();
+ }
+
+ return true;
+ }
+
+ @Override
+ public Boolean disableLogger(String name) {
+ if(!super.disableLogger(name)) {
+ return false;
+ }
+
+ /* Detach from the root logger when the event counts reach zero */
+ if (getEventCount() == 0 && this.attached) {
+ detachFromRootLogger();
+ }
+
+ return true;
+ }
+
+ @Override
+ public Iterator<String> listLoggers() {
+ Vector<String> logs = new Vector<String>();
+ for (Enumeration<?> loggers = LogManager.getCurrentLoggers(); loggers.hasMoreElements(); ) {
+ Logger logger = (Logger) loggers.nextElement();
+ String name = logger.getName();
+ logs.add(name);
+ }
+
+ return logs.iterator();
+ }
+
+ @Override
+ public Boolean isRoot() {
+ return appender.isRoot();
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ detachFromRootLogger();
+ }
+
+ private void attachToRootLogger() {
+ if (this.attached) {
+ return;
+ }
+
+ Logger logger = Logger.getRootLogger();
+ logger.addAppender(this.appender);
+ this.attached = true;
+ }
+
+ private void detachFromRootLogger() {
+ if (!this.attached) {
+ return;
+ }
+
+ Logger logger = Logger.getRootLogger();
+ logger.removeAppender(this.appender);
+ this.attached = false;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.lttng.ust.agent.log4j;
+
+import java.lang.String;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.spi.LoggingEvent;
+
+class LTTngLogAppender extends AppenderSkeleton {
+
+ private Boolean isRoot;
+
+ public LTTngLogAppender(Boolean isRoot) {
+ super();
+ this.isRoot = isRoot;
+ try {
+ System.loadLibrary("lttng-ust-log4j-jni"); //$NON-NLS-1$
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (UnsatisfiedLinkError e) {
+ e.printStackTrace();
+ } catch (NullPointerException e) {
+ /* Should never happen */
+ e.printStackTrace();
+ }
+ }
+
+ public Boolean isRoot() {
+ return this.isRoot;
+ }
+
+ @Override
+ protected void append(LoggingEvent event) {
+ int line;
+
+ /*
+ * The line number returned from LocationInformation is a
+ * string. At least try to convert to a proper int.
+ */
+ try {
+ String lineString = event.getLocationInformation().getLineNumber();
+ line = Integer.parseInt(lineString);
+ } catch (NumberFormatException n) {
+ line = -1;
+ }
+
+ if (this.isRoot) {
+ tracepointS(event.getRenderedMessage(),
+ event.getLoggerName(),
+ event.getLocationInformation().getClassName(),
+ event.getLocationInformation().getMethodName(),
+ event.getLocationInformation().getFileName(),
+ line,
+ event.getTimeStamp(),
+ event.getLevel().toInt(),
+ event.getThreadName());
+ } else {
+ tracepointU(event.getRenderedMessage(),
+ event.getLoggerName(),
+ event.getLocationInformation().getClassName(),
+ event.getLocationInformation().getMethodName(),
+ event.getLocationInformation().getFileName(),
+ line,
+ event.getTimeStamp(),
+ event.getLevel().toInt(),
+ event.getThreadName());
+ }
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public boolean requiresLayout() {
+ return false;
+ }
+
+ /* Use for a user session daemon. */
+ private native void tracepointU(String msg,
+ String logger_name,
+ String class_name,
+ String method_name,
+ String file_name,
+ int line_number,
+ long timestamp,
+ int loglevel,
+ String thread_name);
+
+ /* Use for a root session daemon. */
+ private native void tracepointS(String msg,
+ String logger_name,
+ String class_name,
+ String method_name,
+ String file_name,
+ int line_number,
+ long timestamp,
+ int loglevel,
+ String thread_name);
+}
+++ /dev/null
-/*
- * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License, version 2.1 only,
- * as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.lttng.ust.agent;
-
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-public class LTTngAgent {
-
- /* Domains */
- static enum Domain {
- JUL(3), LOG4J(4);
- private int value;
-
- private Domain(int value) {
- this.value = value;
- }
-
- public int value() {
- return value;
- }
- }
-
- private static final int SEM_TIMEOUT = 3; /* Seconds */
-
- private static LogFramework julUser;
- private static LogFramework julRoot;
- private static LogFramework log4jUser;
- private static LogFramework log4jRoot;
-
- /* Sessiond clients */
- private static LTTngTCPSessiondClient julUserClient;
- private static LTTngTCPSessiondClient julRootClient;
- private static LTTngTCPSessiondClient log4jUserClient;
- private static LTTngTCPSessiondClient log4jRootClient;
-
- private static Thread sessiondThreadJULUser;
- private static Thread sessiondThreadJULRoot;
- private static Thread sessiondThreadLog4jUser;
- private static Thread sessiondThreadLog4jRoot;
-
- private boolean useJUL = false;
- private boolean useLog4j = false;
-
- /* Singleton agent object */
- private static LTTngAgent curAgent = null;
-
- /* Indicate if this object has been initialized. */
- private static boolean initialized = false;
-
- private static Semaphore registerSem;
-
- /*
- * Constructor is private. This is a singleton and a reference should be
- * acquired using getLTTngAgent().
- */
- private LTTngAgent() {
- initAgentJULClasses();
-
- /* Since Log4j is a 3rd party JAR, we need to check if we can load any of its classes */
- Boolean log4jLoaded = loadLog4jClasses();
- if (log4jLoaded) {
- initAgentLog4jClasses();
- }
-
- registerSem = new Semaphore(0, true);
- }
-
- private static Boolean loadLog4jClasses() {
- Class<?> logging;
-
- try {
- logging = loadClass("org.apache.log4j.spi.LoggingEvent");
- } catch (ClassNotFoundException e) {
- /* Log4j classes not found, no need to create the relevant objects */
- return false;
- }
-
- /*
- * Detect capabilities of the log4j library. We only
- * support log4j >= 1.2.15. The getTimeStamp() method
- * was introduced in log4j 1.2.15, so verify that it
- * is available.
- *
- * We can't rely on the getPackage().getImplementationVersion()
- * call that would retrieves information from the manifest file
- * found in the JAR since the manifest file shipped
- * from upstream is known to be broken in several
- * versions of the library.
- *
- * More info:
- * https://issues.apache.org/bugzilla/show_bug.cgi?id=44370
- */
-
- try {
- logging.getDeclaredMethod("getTimeStamp");
- } catch (NoSuchMethodException e) {
- System.err.println("Warning: The loaded log4j library is too old. Log4j tracing with LTTng will be disabled.");
- return false;
- } catch (NullPointerException e) {
- /* Should never happen */
- return false;
- } catch (SecurityException e) {
- return false;
- }
-
- return true;
- }
-
- private static Class<?> loadClass(String className) throws ClassNotFoundException {
- ClassLoader loader;
- Class<?> loadedClass;
-
- try {
- /* Try to load class using the current thread's context class loader */
- loader = Thread.currentThread().getContextClassLoader();
- loadedClass = loader.loadClass(className);
- } catch (ClassNotFoundException e) {
- /* Loading failed, try using the system class loader */
- loader = ClassLoader.getSystemClassLoader();
- loadedClass = loader.loadClass(className);
- }
-
- return loadedClass;
- }
-
- private void initAgentJULClasses() {
- try {
- Class<?> lttngJUL = loadClass("org.lttng.ust.agent.jul.LTTngJUL");
- julUser = (LogFramework) lttngJUL.getDeclaredConstructor(new Class[] { Boolean.class }).newInstance(false);
- julRoot = (LogFramework) lttngJUL.getDeclaredConstructor(new Class[] { Boolean.class }).newInstance(true);
- this.useJUL = true;
- } catch (ClassNotFoundException e) {
- /* LTTng JUL classes not found, no need to create the relevant objects */
- this.useJUL = false;
- } catch (InstantiationException e) {
- this.useJUL = false;
- } catch (NoSuchMethodException e) {
- this.useJUL = false;
- } catch (IllegalAccessException e) {
- this.useJUL = false;
- } catch (InvocationTargetException e) {
- this.useJUL = false;
- }
- }
-
- private void initAgentLog4jClasses() {
- try {
- Class<?> lttngLog4j = loadClass("org.lttng.ust.agent.log4j.LTTngLog4j");
- log4jUser = (LogFramework)lttngLog4j.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(false);
- log4jRoot = (LogFramework)lttngLog4j.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(true);
- this.useLog4j = true;
- } catch (ClassNotFoundException e) {
- /* LTTng Log4j classes not found, no need to create the relevant objects */
- this.useLog4j = false;
- } catch (InstantiationException e) {
- this.useLog4j = false;
- } catch (NoSuchMethodException e) {
- this.useLog4j = false;
- } catch (IllegalAccessException e) {
- this.useLog4j = false;
- } catch (InvocationTargetException e) {
- this.useLog4j = false;
- }
- }
-
- /*
- * Public getter to acquire a reference to this singleton object.
- */
- public static synchronized LTTngAgent getLTTngAgent() throws IOException {
- if (curAgent == null) {
- curAgent = new LTTngAgent();
- curAgent.init();
- }
-
- return curAgent;
- }
-
- private synchronized void init() throws SecurityException {
- if (initialized) {
- return;
- }
-
- Integer numJULThreads = 0;
- Integer numLog4jThreads = 0;
-
- if (this.useJUL) {
- numJULThreads = initJULClientThreads();
- }
-
- if (this.useLog4j) {
- numLog4jThreads = initLog4jClientThreads();
- }
-
- Integer numThreads = numJULThreads + numLog4jThreads;
-
- /* Wait for each registration to end. */
- try {
- registerSem.tryAcquire(numThreads,
- SEM_TIMEOUT,
- TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- initialized = true;
- }
-
- private synchronized static Integer initJULClientThreads() {
- Integer numThreads = 2;
-
- /* Handle user session daemon if any. */
- julUserClient = new LTTngTCPSessiondClient(Domain.JUL,
- julUser,
- registerSem);
-
- String userThreadName = "LTTng UST agent JUL user thread";
- sessiondThreadJULUser = new Thread(julUserClient, userThreadName);
- sessiondThreadJULUser.setDaemon(true);
- sessiondThreadJULUser.start();
-
- /* Handle root session daemon. */
- julRootClient = new LTTngTCPSessiondClient(Domain.JUL,
- julRoot,
- registerSem);
-
- String rootThreadName = "LTTng UST agent JUL root thread";
- sessiondThreadJULRoot = new Thread(julRootClient, rootThreadName);
- sessiondThreadJULRoot.setDaemon(true);
- sessiondThreadJULRoot.start();
-
- return numThreads;
- }
-
- private synchronized static Integer initLog4jClientThreads() {
- Integer numThreads = 2;
-
- log4jUserClient = new LTTngTCPSessiondClient(Domain.LOG4J,
- log4jUser,
- registerSem);
-
- String userThreadName = "LTTng UST agent Log4j user thread";
- sessiondThreadLog4jUser = new Thread(log4jUserClient, userThreadName);
- sessiondThreadLog4jUser.setDaemon(true);
- sessiondThreadLog4jUser.start();
-
- log4jRootClient = new LTTngTCPSessiondClient(Domain.LOG4J,
- log4jRoot,
- registerSem);
-
- String rootThreadName = "LTTng UST agent Log4j root thread";
- sessiondThreadLog4jRoot = new Thread(log4jRootClient,rootThreadName);
- sessiondThreadLog4jRoot.setDaemon(true);
- sessiondThreadLog4jRoot.start();
-
- return numThreads;
- }
-
-
- public void dispose() throws IOException {
- if (this.useJUL) {
- julUserClient.destroy();
- julRootClient.destroy();
- julUser.reset();
- julRoot.reset();
- }
-
- if (this.useLog4j) {
- log4jUserClient.destroy();
- log4jRootClient.destroy();
- log4jUser.reset();
- log4jRoot.reset();
- }
-
- try {
- if (this.useJUL) {
- sessiondThreadJULUser.join();
- sessiondThreadJULRoot.join();
- }
-
- if (this.useLog4j) {
- sessiondThreadLog4jUser.join();
- sessiondThreadLog4jRoot.join();
- }
-
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
- *
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License, version 2.1 only,
- * as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.lttng.ust.agent;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-interface LTTngSessiondCmd2_6 {
-
- /**
- * Maximum name length for a logger name to be send to sessiond.
- */
- int NAME_MAX = 255;
-
- /*
- * Size of a primitive type int in byte. Because you know, Java can't
- * provide that since it does not makes sense...
- *
- *
- */
- int INT_SIZE = 4;
-
- interface SessiondResponse {
- /**
- * Gets a byte array of the command so that it may be streamed
- *
- * @return the byte array of the command
- */
- public byte[] getBytes();
- }
-
- interface SessiondCommand {
- /**
- * Populate the class from a byte array
- *
- * @param data
- * the byte array containing the streamed command
- */
- public void populate(byte[] data);
- }
-
- enum lttng_agent_command {
- /** List logger(s). */
- CMD_LIST(1),
- /** Enable logger by name. */
- CMD_ENABLE(2),
- /** Disable logger by name. */
- CMD_DISABLE(3),
- /** Registration done */
- CMD_REG_DONE(4);
-
- private int code;
-
- private lttng_agent_command(int c) {
- code = c;
- }
-
- public int getCommand() {
- return code;
- }
- }
-
- enum lttng_agent_ret_code {
- CODE_SUCCESS_CMD(1),
- CODE_INVALID_CMD(2),
- CODE_UNK_LOGGER_NAME(3);
- private int code;
-
- private lttng_agent_ret_code(int c) {
- code = c;
- }
-
- public int getCode() {
- return code;
- }
- }
-
- class sessiond_hdr implements SessiondCommand {
-
- /** ABI size of command header. */
- public final static int SIZE = 16;
- /** Payload size in bytes following this header. */
- public long dataSize;
- /** Command type. */
- public lttng_agent_command cmd;
- /** Command version. */
- public int cmdVersion;
-
- @Override
- public void populate(byte[] data) {
- ByteBuffer buf = ByteBuffer.wrap(data);
- buf.order(ByteOrder.BIG_ENDIAN);
-
- dataSize = buf.getLong();
- cmd = lttng_agent_command.values()[buf.getInt() - 1];
- cmdVersion = buf.getInt();
- }
- }
-
- class sessiond_enable_handler implements SessiondResponse, SessiondCommand {
-
- private static final int SIZE = 4;
- public String name;
- public int lttngLogLevel;
- public int lttngLogLevelType;
-
- /** Return status code to the session daemon. */
- public lttng_agent_ret_code code;
-
- @Override
- public void populate(byte[] data) {
- int dataOffset = INT_SIZE * 2;
-
- ByteBuffer buf = ByteBuffer.wrap(data);
- buf.order(ByteOrder.LITTLE_ENDIAN);
- lttngLogLevel = buf.getInt();
- lttngLogLevelType = buf.getInt();
- name = new String(data, dataOffset, data.length - dataOffset).trim();
- }
-
- @Override
- public byte[] getBytes() {
- byte data[] = new byte[SIZE];
- ByteBuffer buf = ByteBuffer.wrap(data);
- buf.order(ByteOrder.BIG_ENDIAN);
- buf.putInt(code.getCode());
- return data;
- }
-
- /**
- * Execute enable handler action which is to enable the given handler
- * to the received name.
- */
- public void execute(LogFramework log) {
- if (log.enableLogger(this.name)) {
- this.code = lttng_agent_ret_code.CODE_SUCCESS_CMD;
- } else {
- this.code = lttng_agent_ret_code.CODE_INVALID_CMD;
- }
- }
- }
-
- class sessiond_disable_handler implements SessiondResponse, SessiondCommand {
-
- private final static int SIZE = 4;
- public String name;
-
-
- /** Return status code to the session daemon. */
- public lttng_agent_ret_code code;
-
- @Override
- public void populate(byte[] data) {
- ByteBuffer buf = ByteBuffer.wrap(data);
- buf.order(ByteOrder.LITTLE_ENDIAN);
- name = new String(data).trim();
- }
-
- @Override
- public byte[] getBytes() {
- byte data[] = new byte[SIZE];
- ByteBuffer buf = ByteBuffer.wrap(data);
- buf.order(ByteOrder.BIG_ENDIAN);
- buf.putInt(code.getCode());
- return data;
- }
-
- /**
- * Execute disable handler action which is to disable the given handler
- * to the received name.
- */
- public void execute(LogFramework log) {
- if (log.disableLogger(this.name)) {
- this.code = lttng_agent_ret_code.CODE_SUCCESS_CMD;
- } else {
- this.code = lttng_agent_ret_code.CODE_INVALID_CMD;
- }
- }
- }
-
- class sessiond_list_logger implements SessiondResponse {
-
- private final static int SIZE = 12;
-
- private int dataSize = 0;
- private int nbLogger = 0;
-
- List<String> loggerList = new ArrayList<String>();
-
- /** Return status code to the session daemon. */
- public lttng_agent_ret_code code;
-
- @Override
- public byte[] getBytes() {
- byte data[] = new byte[SIZE + dataSize];
- ByteBuffer buf = ByteBuffer.wrap(data);
- buf.order(ByteOrder.BIG_ENDIAN);
-
- /* Returned code */
- buf.putInt(code.getCode());
- buf.putInt(dataSize);
- buf.putInt(nbLogger);
-
- for (String logger: loggerList) {
- buf.put(logger.getBytes());
- /* NULL terminated byte after the logger name. */
- buf.put((byte) 0x0);
- }
- return data;
- }
-
- public void execute(LogFramework log) {
- String loggerName;
-
- Iterator<String> loggers = log.listLoggers();
- while (loggers.hasNext()) {
- loggerName = loggers.next();
- this.loggerList.add(loggerName);
- this.nbLogger++;
- this.dataSize += loggerName.length() + 1;
- }
-
- this.code = lttng_agent_ret_code.CODE_SUCCESS_CMD;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License, version 2.1 only,
- * as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.lttng.ust.agent;
-
-import java.io.BufferedReader;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.net.Socket;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.concurrent.Semaphore;
-
-class LTTngTCPSessiondClient implements Runnable {
-
- private static final String SESSION_HOST = "127.0.0.1";
- private static final String ROOT_PORT_FILE = "/var/run/lttng/agent.port";
- private static final String USER_PORT_FILE = "/.lttng/agent.port";
-
- private static Integer protocolMajorVersion = 1;
- private static Integer protocolMinorVersion = 0;
-
- /* Command header from the session deamon. */
- private LTTngSessiondCmd2_6.sessiond_hdr headerCmd =
- new LTTngSessiondCmd2_6.sessiond_hdr();
-
- private Socket sessiondSock;
- private volatile boolean quit = false;
-
- private DataInputStream inFromSessiond;
- private DataOutputStream outToSessiond;
-
- private LogFramework log;
-
- private Semaphore registerSem;
-
-
- private LTTngAgent.Domain agentDomain;
-
- /* Indicate if we've already released the semaphore. */
- private boolean semPosted = false;
-
- public LTTngTCPSessiondClient(LTTngAgent.Domain domain, LogFramework log, Semaphore sem) {
- this.agentDomain = domain;
- this.log = log;
- this.registerSem = sem;
- }
-
- /*
- * Try to release the registerSem if it's not already done.
- */
- private void tryReleaseSem() {
- /* Release semaphore so we unblock the agent. */
- if (!this.semPosted) {
- this.registerSem.release();
- this.semPosted = true;
- }
- }
-
- @Override
- public void run() {
- for (;;) {
- if (this.quit) {
- break;
- }
-
- /* Cleanup Agent state before trying to connect or reconnect. */
- this.log.reset();
-
- try {
-
- /*
- * Connect to the session daemon before anything else.
- */
- connectToSessiond();
-
- /*
- * Register to the session daemon as the Java component of the
- * UST application.
- */
- registerToSessiond();
-
- /*
- * Block on socket receive and wait for command from the
- * session daemon. This will return if and only if there is a
- * fatal error or the socket closes.
- */
- handleSessiondCmd();
- } catch (UnknownHostException uhe) {
- tryReleaseSem();
- System.out.println(uhe);
- } catch (IOException ioe) {
- tryReleaseSem();
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- } catch (Exception e) {
- tryReleaseSem();
- e.printStackTrace();
- }
- }
- }
-
- public void destroy() {
- this.quit = true;
-
- try {
- if (this.sessiondSock != null) {
- this.sessiondSock.close();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /*
- * Receive header data from the session daemon using the LTTng command
- * static buffer of the right size.
- */
- private void recvHeader() throws Exception {
- byte data[] = new byte[LTTngSessiondCmd2_6.sessiond_hdr.SIZE];
-
- int readLen = this.inFromSessiond.read(data, 0, data.length);
- if (readLen != data.length) {
- throw new IOException();
- }
- this.headerCmd.populate(data);
- }
-
- /*
- * Receive payload from the session daemon. This MUST be done after a
- * recvHeader() so the header value of a command are known.
- *
- * The caller SHOULD use isPayload() before which returns true if a payload
- * is expected after the header.
- */
- private byte[] recvPayload() throws Exception {
- byte payload[] = new byte[(int) this.headerCmd.dataSize];
-
- /* Failsafe check so we don't waste our time reading 0 bytes. */
- if (payload.length == 0) {
- return null;
- }
-
- this.inFromSessiond.read(payload, 0, payload.length);
- return payload;
- }
-
- /*
- * Handle session command from the session daemon.
- */
- private void handleSessiondCmd() throws Exception {
- byte data[] = null;
-
- while (true) {
- /* Get header from session daemon. */
- recvHeader();
-
- if (headerCmd.dataSize > 0) {
- data = recvPayload();
- }
-
- switch (headerCmd.cmd) {
- case CMD_REG_DONE:
- {
- /*
- * Release semaphore so meaning registration is done and we
- * can proceed to continue tracing.
- */
- tryReleaseSem();
- /*
- * We don't send any reply to the registration done command.
- * This just marks the end of the initial session setup.
- */
- continue;
- }
- case CMD_LIST:
- {
- LTTngSessiondCmd2_6.sessiond_list_logger listLoggerCmd =
- new LTTngSessiondCmd2_6.sessiond_list_logger();
- listLoggerCmd.execute(this.log);
- data = listLoggerCmd.getBytes();
- break;
- }
- case CMD_ENABLE:
- {
- LTTngSessiondCmd2_6.sessiond_enable_handler enableCmd =
- new LTTngSessiondCmd2_6.sessiond_enable_handler();
- if (data == null) {
- enableCmd.code = LTTngSessiondCmd2_6.lttng_agent_ret_code.CODE_INVALID_CMD;
- break;
- }
- enableCmd.populate(data);
- enableCmd.execute(this.log);
- data = enableCmd.getBytes();
- break;
- }
- case CMD_DISABLE:
- {
- LTTngSessiondCmd2_6.sessiond_disable_handler disableCmd =
- new LTTngSessiondCmd2_6.sessiond_disable_handler();
- if (data == null) {
- disableCmd.code = LTTngSessiondCmd2_6.lttng_agent_ret_code.CODE_INVALID_CMD;
- break;
- }
- disableCmd.populate(data);
- disableCmd.execute(this.log);
- data = disableCmd.getBytes();
- break;
- }
- default:
- {
- data = new byte[4];
- ByteBuffer buf = ByteBuffer.wrap(data);
- buf.order(ByteOrder.BIG_ENDIAN);
- break;
- }
- }
-
- /* Send payload to session daemon. */
- this.outToSessiond.write(data, 0, data.length);
- this.outToSessiond.flush();
- }
- }
-
- private static String getHomePath() {
- return System.getProperty("user.home");
- }
-
- /**
- * Read port number from file created by the session daemon.
- *
- * @return port value if found else 0.
- */
- private static int getPortFromFile(String path) throws IOException {
- int port;
- BufferedReader br;
-
- try {
- br = new BufferedReader(new FileReader(path));
- String line = br.readLine();
- port = Integer.parseInt(line, 10);
- if (port < 0 || port > 65535) {
- /* Invalid value. Ignore. */
- port = 0;
- }
- br.close();
- } catch (FileNotFoundException e) {
- /* No port available. */
- port = 0;
- }
-
- return port;
- }
-
- private void connectToSessiond() throws Exception {
- int port;
-
- if (this.log.isRoot()) {
- port = getPortFromFile(ROOT_PORT_FILE);
- if (port == 0) {
- /* No session daemon available. Stop and retry later. */
- throw new IOException();
- }
- } else {
- port = getPortFromFile(getHomePath() + USER_PORT_FILE);
- if (port == 0) {
- /* No session daemon available. Stop and retry later. */
- throw new IOException();
- }
- }
-
- this.sessiondSock = new Socket(SESSION_HOST, port);
- this.inFromSessiond = new DataInputStream(sessiondSock.getInputStream());
- this.outToSessiond = new DataOutputStream(sessiondSock.getOutputStream());
- }
-
- private void registerToSessiond() throws Exception {
- byte data[] = new byte[16];
- ByteBuffer buf = ByteBuffer.wrap(data);
- String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
-
- buf.putInt(this.agentDomain.value());
- buf.putInt(Integer.parseInt(pid));
- buf.putInt(protocolMajorVersion);
- buf.putInt(protocolMinorVersion);
- this.outToSessiond.write(data, 0, data.length);
- this.outToSessiond.flush();
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
- *
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License, version 2.1 only,
- * as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.lttng.ust.agent;
-
-import java.util.Iterator;
-
-interface LogFramework {
- Boolean enableLogger(String name);
- Boolean disableLogger(String name);
- Iterator<String> listLoggers();
- Boolean isRoot();
- void reset();
-}
+++ /dev/null
-/*
- * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
- *
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License, version 2.1 only,
- * as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.lttng.ust.agent;
-
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Iterator;
-
-public abstract class LogFrameworkSkeleton implements LogFramework {
-
- /* A map of event name and reference count */
- private final Map<String, Integer> enabledLoggers;
-
- public LogFrameworkSkeleton() {
- this.enabledLoggers = new HashMap<String, Integer>();
- }
-
- @Override
- public Boolean enableLogger(String name) {
- if (name == null) {
- return false;
- }
-
- if (enabledLoggers.containsKey(name)) {
- /* Event is already enabled, simply increment its refcount */
- Integer refcount = enabledLoggers.get(name);
- refcount++;
- Integer oldval = enabledLoggers.put(name, refcount);
- assert (oldval != null);
- } else {
- /* Event was not enabled, init refcount to 1 */
- Integer oldval = enabledLoggers.put(name, 1);
- assert (oldval == null);
- }
-
- return true;
- }
-
- @Override
- public Boolean disableLogger(String name) {
- if (name == null) {
- return false;
- }
-
- if (!enabledLoggers.containsKey(name)) {
- /* Event was never enabled, abort */
- return false;
- }
-
- /* Event was previously enabled, simply decrement its refcount */
- Integer refcount = enabledLoggers.get(name);
- refcount--;
- assert (refcount >= 0);
-
- if (refcount == 0) {
- /* Event is not used anymore, remove it from the map */
- Integer oldval = enabledLoggers.remove(name);
- assert (oldval != null);
- }
-
- return true;
- }
-
- @Override
- public abstract Iterator<String> listLoggers();
-
- @Override
- public abstract Boolean isRoot();
-
- @Override
- public void reset() {
- enabledLoggers.clear();
- }
-
- protected Integer getEventCount() {
- return enabledLoggers.size();
- }
-}
+++ /dev/null
-Name: org/lttng/ust/agent/
-Specification-Title: LTTng UST Java Agent
-Specification-Version: 1.0.0
-Specification-Vendor: LTTng Project
-Implementation-Title: org.lttng.ust.agent
-Implementation-Version: 1.0.0
-Implementation-Vendor: LTTng Project
+++ /dev/null
-/*
- * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
- *
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License, version 2.1 only,
- * as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.lttng.ust.agent.jul;
-
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.Vector;
-
-import java.util.logging.LogManager;
-import java.util.logging.Logger;
-
-import org.lttng.ust.agent.LogFrameworkSkeleton;
-
-public class LTTngJUL extends LogFrameworkSkeleton {
-
- private LTTngLogHandler handler;
- private Boolean attached;
-
- public LTTngJUL(Boolean isRoot) {
- super();
- this.handler = new LTTngLogHandler(isRoot);
- this.attached = false;
- }
-
- @Override
- public Boolean enableLogger(String name) {
- if(!super.enableLogger(name)) {
- return false;
- }
-
- /* The first enable of any event triggers the attachment to the root logger */
- if (getEventCount() == 1 && !this.attached) {
- attachToRootLogger();
- }
-
- return true;
- }
-
- @Override
- public Boolean disableLogger(String name) {
- if(!super.disableLogger(name)) {
- return false;
- }
-
- /* Detach from the root logger when the event count reach zero */
- if (getEventCount() == 0 && this.attached) {
- detachFromRootLogger();
- }
-
- return true;
- }
-
- @Override
- public Iterator<String> listLoggers() {
- Vector<String> logs = new Vector<String>();
- for (Enumeration<String> loggers = LogManager.getLogManager().getLoggerNames(); loggers.hasMoreElements(); ) {
- String name = loggers.nextElement();
- /* Skip the root logger */
- if (name.equals("")) {
- continue;
- }
-
- logs.add(name);
- }
-
- return logs.iterator();
- }
-
- @Override
- public Boolean isRoot() {
- return handler.isRoot();
- }
-
- @Override
- public void reset() {
- super.reset();
- detachFromRootLogger();
- }
-
- private void attachToRootLogger() {
- if (this.attached) {
- return;
- }
-
- Logger rootLogger = LogManager.getLogManager().getLogger("");
- rootLogger.addHandler(this.handler);
- this.attached = true;
- }
-
- private void detachFromRootLogger() {
- if (!this.attached) {
- return;
- }
-
- Logger rootLogger = LogManager.getLogManager().getLogger("");
- rootLogger.removeHandler(this.handler);
- this.attached = false;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License, version 2.1 only,
- * as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.lttng.ust.agent.jul;
-
-import java.lang.String;
-
-import java.util.logging.Handler;
-import java.util.logging.LogRecord;
-
-class LTTngLogHandler extends Handler {
-
- private final Boolean isRoot;
-
- public LTTngLogHandler(Boolean isRoot) {
- super();
- this.isRoot = isRoot;
- /* Initialize LTTng UST tracer. */
- try {
- System.loadLibrary("lttng-ust-jul-jni"); //$NON-NLS-1$
- } catch (SecurityException e) {
- e.printStackTrace();
- } catch (UnsatisfiedLinkError e) {
- e.printStackTrace();
- } catch (NullPointerException e) {
- /* Should never happen */
- e.printStackTrace();
- }
- }
-
- public Boolean isRoot() {
- return this.isRoot;
- }
-
- @Override
- public void close() throws SecurityException {}
-
- @Override
- public void flush() {}
-
- @Override
- public void publish(LogRecord record) {
- /*
- * Specific tracepoint designed for JUL events. The source class of the
- * caller is used for the event name, the raw message is taken, the
- * loglevel of the record and the thread ID.
- */
- if (this.isRoot) {
- tracepointS(record.getMessage(),
- record.getLoggerName(), record.getSourceClassName(),
- record.getSourceMethodName(), record.getMillis(),
- record.getLevel().intValue(), record.getThreadID());
- } else {
- tracepointU(record.getMessage(),
- record.getLoggerName(), record.getSourceClassName(),
- record.getSourceMethodName(), record.getMillis(),
- record.getLevel().intValue(), record.getThreadID());
- }
- }
-
- /* Use for a user session daemon. */
- private native void tracepointU(String msg,
- String logger_name,
- String class_name,
- String method_name,
- long millis,
- int log_level,
- int thread_id);
-
- /* Use for a root session daemon. */
- private native void tracepointS(String msg,
- String logger_name,
- String class_name,
- String method_name,
- long millis,
- int log_level,
- int thread_id);
-}
+++ /dev/null
-/*
- * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
- *
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License, version 2.1 only,
- * as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.lttng.ust.agent.log4j;
-
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.Vector;
-
-import org.apache.log4j.LogManager;
-import org.apache.log4j.Logger;
-
-import org.lttng.ust.agent.LogFrameworkSkeleton;
-
-public class LTTngLog4j extends LogFrameworkSkeleton {
-
- private LTTngLogAppender appender;
- private Boolean attached;
-
- public LTTngLog4j(Boolean isRoot) {
- super();
- this.appender = new LTTngLogAppender(isRoot);
- this.attached = false;
- }
-
- @Override
- public Boolean enableLogger(String name) {
- if(!super.enableLogger(name)) {
- return false;
- }
-
- /* The first enable of any event triggers the attachment to the root logger */
- if (getEventCount() == 1 && !this.attached) {
- attachToRootLogger();
- }
-
- return true;
- }
-
- @Override
- public Boolean disableLogger(String name) {
- if(!super.disableLogger(name)) {
- return false;
- }
-
- /* Detach from the root logger when the event counts reach zero */
- if (getEventCount() == 0 && this.attached) {
- detachFromRootLogger();
- }
-
- return true;
- }
-
- @Override
- public Iterator<String> listLoggers() {
- Vector<String> logs = new Vector<String>();
- for (Enumeration<?> loggers = LogManager.getCurrentLoggers(); loggers.hasMoreElements(); ) {
- Logger logger = (Logger) loggers.nextElement();
- String name = logger.getName();
- logs.add(name);
- }
-
- return logs.iterator();
- }
-
- @Override
- public Boolean isRoot() {
- return appender.isRoot();
- }
-
- @Override
- public void reset() {
- super.reset();
- detachFromRootLogger();
- }
-
- private void attachToRootLogger() {
- if (this.attached) {
- return;
- }
-
- Logger logger = Logger.getRootLogger();
- logger.addAppender(this.appender);
- this.attached = true;
- }
-
- private void detachFromRootLogger() {
- if (!this.attached) {
- return;
- }
-
- Logger logger = Logger.getRootLogger();
- logger.removeAppender(this.appender);
- this.attached = false;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License, version 2.1 only,
- * as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.lttng.ust.agent.log4j;
-
-import java.lang.String;
-
-import org.apache.log4j.AppenderSkeleton;
-import org.apache.log4j.spi.LoggingEvent;
-
-class LTTngLogAppender extends AppenderSkeleton {
-
- private Boolean isRoot;
-
- public LTTngLogAppender(Boolean isRoot) {
- super();
- this.isRoot = isRoot;
- try {
- System.loadLibrary("lttng-ust-log4j-jni"); //$NON-NLS-1$
- } catch (SecurityException e) {
- e.printStackTrace();
- } catch (UnsatisfiedLinkError e) {
- e.printStackTrace();
- } catch (NullPointerException e) {
- /* Should never happen */
- e.printStackTrace();
- }
- }
-
- public Boolean isRoot() {
- return this.isRoot;
- }
-
- @Override
- protected void append(LoggingEvent event) {
- int line;
-
- /*
- * The line number returned from LocationInformation is a
- * string. At least try to convert to a proper int.
- */
- try {
- String lineString = event.getLocationInformation().getLineNumber();
- line = Integer.parseInt(lineString);
- } catch (NumberFormatException n) {
- line = -1;
- }
-
- if (this.isRoot) {
- tracepointS(event.getRenderedMessage(),
- event.getLoggerName(),
- event.getLocationInformation().getClassName(),
- event.getLocationInformation().getMethodName(),
- event.getLocationInformation().getFileName(),
- line,
- event.getTimeStamp(),
- event.getLevel().toInt(),
- event.getThreadName());
- } else {
- tracepointU(event.getRenderedMessage(),
- event.getLoggerName(),
- event.getLocationInformation().getClassName(),
- event.getLocationInformation().getMethodName(),
- event.getLocationInformation().getFileName(),
- line,
- event.getTimeStamp(),
- event.getLevel().toInt(),
- event.getThreadName());
- }
- }
-
- @Override
- public void close() {}
-
- @Override
- public boolean requiresLayout() {
- return false;
- }
-
- /* Use for a user session daemon. */
- private native void tracepointU(String msg,
- String logger_name,
- String class_name,
- String method_name,
- String file_name,
- int line_number,
- long timestamp,
- int loglevel,
- String thread_name);
-
- /* Use for a root session daemon. */
- private native void tracepointS(String msg,
- String logger_name,
- String class_name,
- String method_name,
- String file_name,
- int line_number,
- long timestamp,
- int loglevel,
- String thread_name);
-}