From: Alexandre Montplaisir Date: Tue, 30 Jun 2015 00:13:50 +0000 (-0400) Subject: Split Java agent library in 3 separate jars X-Git-Url: http://git.efficios.com/?p=deliverable%2Flttng-ust.git;a=commitdiff_plain;h=8e57e02f3ece925cdf37006a160187993c6f1cb1 Split Java agent library in 3 separate jars Instead of having one .jar whose content is dependent on the configure flags used for the build, we can produce 3 separate jars whose contents will always be the same: lttng-ust-agent-common lttng-ust-agent-jul lttng-ust-agent-log4j The configure flag will now determine if the jul/log4j packages are built or not. Signed-off-by: Alexandre Montplaisir Signed-off-by: Mathieu Desnoyers --- diff --git a/.gitignore b/.gitignore index 6b11c673..bcd0ecb9 100644 --- a/.gitignore +++ b/.gitignore @@ -54,14 +54,13 @@ tests/benchmark/bench2 # 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 diff --git a/configure.ac b/configure.ac index fe85e7be..0e9886ba 100644 --- a/configure.ac +++ b/configure.ac @@ -382,6 +382,9 @@ AC_CONFIG_FILES([ 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 diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am index 9404054d..3538ee6d 100644 --- a/doc/examples/Makefile.am +++ b/doc/examples/Makefile.am @@ -105,12 +105,12 @@ all-local: 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; diff --git a/doc/examples/java-jul/Makefile b/doc/examples/java-jul/Makefile index 1431b60b..154078bf 100644 --- a/doc/examples/java-jul/Makefile +++ b/doc/examples/java-jul/Makefile @@ -16,19 +16,22 @@ # 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 diff --git a/doc/examples/java-jul/run b/doc/examples/java-jul/run index 6deb6fd8..eb340da8 100755 --- a/doc/examples/java-jul/run +++ b/doc/examples/java-jul/run @@ -7,22 +7,25 @@ # 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 diff --git a/doc/examples/java-log4j/Makefile b/doc/examples/java-log4j/Makefile index 2c629c37..bf10fc52 100644 --- a/doc/examples/java-log4j/Makefile +++ b/doc/examples/java-log4j/Makefile @@ -16,28 +16,30 @@ # 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: diff --git a/doc/examples/java-log4j/run b/doc/examples/java-log4j/run index 91f8f5d6..997d0bdc 100755 --- a/doc/examples/java-log4j/run +++ b/doc/examples/java-log4j/run @@ -7,7 +7,8 @@ # 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 @@ -18,16 +19,18 @@ fi 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 diff --git a/liblttng-ust-java-agent/java/Makefile.am b/liblttng-ust-java-agent/java/Makefile.am index 1232d6e5..a10a393f 100644 --- a/liblttng-ust-java-agent/java/Makefile.am +++ b/liblttng-ust-java-agent/java/Makefile.am @@ -1,66 +1,9 @@ -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 diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am b/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am new file mode 100644 index 00000000..46ac7cde --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am @@ -0,0 +1,36 @@ +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 diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/Manifest.txt b/liblttng-ust-java-agent/java/lttng-ust-agent-common/Manifest.txt new file mode 100644 index 00000000..d3c7e264 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/Manifest.txt @@ -0,0 +1,7 @@ +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 diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngAgent.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngAgent.java new file mode 100644 index 00000000..ca7bc777 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngAgent.java @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2013 - David Goulet + * + * 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(); + } + } +} diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngSessiondCmd2_6.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngSessiondCmd2_6.java new file mode 100644 index 00000000..7a33e425 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngSessiondCmd2_6.java @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2013 - David Goulet + * + * + * 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 loggerList = new ArrayList(); + + /** 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 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; + } + } +} diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngTCPSessiondClient.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngTCPSessiondClient.java new file mode 100644 index 00000000..d376f672 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngTCPSessiondClient.java @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2013 - David Goulet + * + * 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(); + } +} diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LogFramework.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LogFramework.java new file mode 100644 index 00000000..0dd7c982 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LogFramework.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014 - Christian Babeux + * + * + * 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 listLoggers(); + Boolean isRoot(); + void reset(); +} diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LogFrameworkSkeleton.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LogFrameworkSkeleton.java new file mode 100644 index 00000000..6d1ea9f6 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LogFrameworkSkeleton.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014 - Christian Babeux + * + * + * 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 enabledLoggers; + + public LogFrameworkSkeleton() { + this.enabledLoggers = new HashMap(); + } + + @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 listLoggers(); + + @Override + public abstract Boolean isRoot(); + + @Override + public void reset() { + enabledLoggers.clear(); + } + + protected Integer getEventCount() { + return enabledLoggers.size(); + } +} diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile.am b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile.am new file mode 100644 index 00000000..b2aed8b4 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile.am @@ -0,0 +1,41 @@ +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 diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Manifest.txt b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Manifest.txt new file mode 100644 index 00000000..4aba3600 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Manifest.txt @@ -0,0 +1,8 @@ +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 diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LTTngJUL.java b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LTTngJUL.java new file mode 100644 index 00000000..6a3eac95 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LTTngJUL.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014 - Christian Babeux + * + * + * 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 listLoggers() { + Vector logs = new Vector(); + for (Enumeration 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; + } +} diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LTTngLogHandler.java b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LTTngLogHandler.java new file mode 100644 index 00000000..b844d2f6 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LTTngLogHandler.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2013 - David Goulet + * + * 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); +} diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile.am b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile.am new file mode 100644 index 00000000..9113f85e --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile.am @@ -0,0 +1,41 @@ +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 diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Manifest.txt b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Manifest.txt new file mode 100644 index 00000000..d7b98f42 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Manifest.txt @@ -0,0 +1,8 @@ +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 diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LTTngLog4j.java b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LTTngLog4j.java new file mode 100644 index 00000000..6e892bcc --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LTTngLog4j.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014 - Christian Babeux + * + * + * 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 listLoggers() { + Vector logs = new Vector(); + 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; + } +} diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LTTngLogAppender.java b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LTTngLogAppender.java new file mode 100644 index 00000000..30fac23f --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LTTngLogAppender.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014 - Christian Babeux + * + * 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); +} diff --git a/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngAgent.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngAgent.java deleted file mode 100644 index ca7bc777..00000000 --- a/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngAgent.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (C) 2013 - David Goulet - * - * 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(); - } - } -} diff --git a/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngSessiondCmd2_6.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngSessiondCmd2_6.java deleted file mode 100644 index 7a33e425..00000000 --- a/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngSessiondCmd2_6.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2013 - David Goulet - * - * - * 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 loggerList = new ArrayList(); - - /** 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 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; - } - } -} diff --git a/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngTCPSessiondClient.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngTCPSessiondClient.java deleted file mode 100644 index d376f672..00000000 --- a/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngTCPSessiondClient.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (C) 2013 - David Goulet - * - * 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(); - } -} diff --git a/liblttng-ust-java-agent/java/org/lttng/ust/agent/LogFramework.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/LogFramework.java deleted file mode 100644 index 0dd7c982..00000000 --- a/liblttng-ust-java-agent/java/org/lttng/ust/agent/LogFramework.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2014 - Christian Babeux - * - * - * 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 listLoggers(); - Boolean isRoot(); - void reset(); -} diff --git a/liblttng-ust-java-agent/java/org/lttng/ust/agent/LogFrameworkSkeleton.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/LogFrameworkSkeleton.java deleted file mode 100644 index 6d1ea9f6..00000000 --- a/liblttng-ust-java-agent/java/org/lttng/ust/agent/LogFrameworkSkeleton.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2014 - Christian Babeux - * - * - * 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 enabledLoggers; - - public LogFrameworkSkeleton() { - this.enabledLoggers = new HashMap(); - } - - @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 listLoggers(); - - @Override - public abstract Boolean isRoot(); - - @Override - public void reset() { - enabledLoggers.clear(); - } - - protected Integer getEventCount() { - return enabledLoggers.size(); - } -} diff --git a/liblttng-ust-java-agent/java/org/lttng/ust/agent/Manifest.txt b/liblttng-ust-java-agent/java/org/lttng/ust/agent/Manifest.txt deleted file mode 100644 index d3c7e264..00000000 --- a/liblttng-ust-java-agent/java/org/lttng/ust/agent/Manifest.txt +++ /dev/null @@ -1,7 +0,0 @@ -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 diff --git a/liblttng-ust-java-agent/java/org/lttng/ust/agent/jul/LTTngJUL.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/jul/LTTngJUL.java deleted file mode 100644 index 6a3eac95..00000000 --- a/liblttng-ust-java-agent/java/org/lttng/ust/agent/jul/LTTngJUL.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2014 - Christian Babeux - * - * - * 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 listLoggers() { - Vector logs = new Vector(); - for (Enumeration 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; - } -} diff --git a/liblttng-ust-java-agent/java/org/lttng/ust/agent/jul/LTTngLogHandler.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/jul/LTTngLogHandler.java deleted file mode 100644 index b844d2f6..00000000 --- a/liblttng-ust-java-agent/java/org/lttng/ust/agent/jul/LTTngLogHandler.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2013 - David Goulet - * - * 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); -} diff --git a/liblttng-ust-java-agent/java/org/lttng/ust/agent/log4j/LTTngLog4j.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/log4j/LTTngLog4j.java deleted file mode 100644 index 6e892bcc..00000000 --- a/liblttng-ust-java-agent/java/org/lttng/ust/agent/log4j/LTTngLog4j.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2014 - Christian Babeux - * - * - * 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 listLoggers() { - Vector logs = new Vector(); - 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; - } -} diff --git a/liblttng-ust-java-agent/java/org/lttng/ust/agent/log4j/LTTngLogAppender.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/log4j/LTTngLogAppender.java deleted file mode 100644 index 30fac23f..00000000 --- a/liblttng-ust-java-agent/java/org/lttng/ust/agent/log4j/LTTngLogAppender.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2014 - Christian Babeux - * - * 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); -}