From: Christian Babeux Date: Mon, 15 Sep 2014 03:11:30 +0000 (-0400) Subject: Refactor liblttng-ust-jul in liblttng-ust-agent X-Git-Tag: v2.6.0-rc1~9 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=501f6777610d7f8d855453c0083a10912d5fac4b;p=lttng-ust.git Refactor liblttng-ust-jul in liblttng-ust-agent This is a major refactor of the initial implementation of the UST JUL agent. The agent now support the log4j logging backend. The agent can now be built in three different configurations: 1) Java agent with JUL support: $ ./configure --enable-java-agent-jul 2) Java agent with Log4j support: $ export CLASSPATH=$CLASSPATH:/path/to/log4j.jar $ ./configure --enable-java-agent-log4j 3) Java agent with JUL + Log4j support $ export CLASSPATH=$CLASSPATH:/path/to/log4j.jar $ ./configure --enable-java-agent-all To build the agent with log4j support, make sure that the log4j jar is in your Java classpath. The configure script will automatically detect the appropriate Java binaries to use in order to build the Java agent. The name of the agent jar file is now "liblttng-ust-agent.jar". It will be installed in the arch-agnostic "$prefix/share/java" path e.g: "/usr/share/java". In order to support older applications using the "org.lttng.ust.jul" package, a transitional package is built with the same name. All applications should move to use the "org.lttng.ust.agent" package. Signed-off-by: Christian Babeux Signed-off-by: Mathieu Desnoyers --- diff --git a/.gitignore b/.gitignore index 11f87b79..c5f606fe 100644 --- a/.gitignore +++ b/.gitignore @@ -51,7 +51,12 @@ tests/snprintf/prog tests/benchmark/bench1 tests/benchmark/bench2 -# Java JUL library +# Java agent library *.class -liblttng-ust-jul.jar -org_lttng_ust_jul_LTTngUst.h +liblttng-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 \ No newline at end of file diff --git a/Makefile.am b/Makefile.am index b9a1115c..9fb95565 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,7 +13,11 @@ SUBDIRS += liblttng-ust-dl endif if BUILD_JNI_INTERFACE -SUBDIRS += liblttng-ust-java liblttng-ust-jul +SUBDIRS += liblttng-ust-java +endif + +if BUILD_JAVA_AGENT +SUBDIRS += liblttng-ust-java-agent endif SUBDIRS += tests doc diff --git a/configure.ac b/configure.ac index bf626697..82db75bd 100644 --- a/configure.ac +++ b/configure.ac @@ -240,27 +240,6 @@ if test x$NO_UNALIGNED_ACCESS = x ; then AC_DEFINE([LTTNG_UST_HAVE_EFFICIENT_UNALIGNED_ACCESS], [1]) fi -# Set compile flags to java include files if given -AC_ARG_WITH([java-jdk], - [AS_HELP_STRING([--with-java-jdk=DIR],[use the Java JDK in DIR. Ex : $JAVA_HOME.])], - [JAVA_JDK=$withval], - [JAVA_JDK=""] -) -AM_CONDITIONAL([HAVE_JAVA_JDK], [test $JAVA_JDK], [Java JDK path]) -AC_SUBST([JAVA_JDK]) - -AS_IF([test $JAVA_JDK],[ - AS_IF([test -d $JAVA_JDK],[ - AC_MSG_RESULT([using Java includes in $JAVA_SDK]) - SUBDIRS=`find $JAVA_JDK/include -type d` - CPPFLAGS+=" " - CPPFLAGS+=`for x in $SUBDIRS; do echo -n "-I$x "; done` - CPPFLAGS+=" " - ],[ - AC_MSG_ERROR(Unable to find Java include files in $JAVA_JDK) - ]) -]) - # Check for JNI header files if requested AC_ARG_ENABLE([jni-interface], [AS_HELP_STRING([--enable-jni-interface],[build JNI interface between C and Java. Needs Java include files [default=no]])], @@ -270,6 +249,56 @@ AC_ARG_ENABLE([jni-interface], AM_CONDITIONAL([BUILD_JNI_INTERFACE], [test "x$jni_interface" = "xyes"]) + +AC_ARG_ENABLE([java-agent-jul], + [AS_HELP_STRING([--enable-java-agent-jul],[build the LTTng UST Java agent with JUL support [default=no]])], + [java_agent_jul=$enableval], + [java_agent_jul=no] +) + +AC_ARG_ENABLE([java-agent-log4j], + [AS_HELP_STRING([--enable-java-agent-log4j],[build the LTTng UST Java agent with Log4j support [default=no]])], + [java_agent_log4j=$enableval], + [java_agent_log4j=no] +) + +AC_ARG_ENABLE([java-agent-all], + [AS_HELP_STRING([--enable-java-agent-all],[build the LTTng UST Java agent with all supported backends [default=no]])], + [java_agent_jul=$enableval + java_agent_log4j=$enableval], + [:] +) + + +AM_CONDITIONAL([BUILD_JAVA_AGENT], [test "x$java_agent_jul" = "xyes" || test "x$java_agent_log4j" = "xyes"]) +AM_CONDITIONAL([BUILD_JAVA_AGENT_WITH_JUL], [test "x$java_agent_jul" = "xyes"]) +AM_CONDITIONAL([BUILD_JAVA_AGENT_WITH_LOG4J], [test "x$java_agent_log4j" = "xyes"]) + +if test "x$jni_interface" = "xyes" || test "x$java_agent_jul" = "xyes" || test "x$java_agent_log4j" = "xyes"; then + AX_JAVA_OPTIONS + AX_PROG_JAVAC + AX_PROG_JAVA + AX_PROG_JAR + + AX_JNI_INCLUDE_DIR + for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS + do + CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" + done + + AX_PROG_JAVAH +fi + +if test "x$java_agent_log4j" = "xyes"; then + AX_CHECK_CLASSPATH + + AX_CHECK_CLASS(org.apache.log4j.Logger) + + if test "x$ac_cv_class_org_apache_log4j_Logger" = "xno"; then + AC_MSG_ERROR([The UST Java agent support for log4j was requested but the Log4j classes were not found. Please specify the location of the Log4j jar via the Java CLASSPATH e.g: export CLASSPATH="/path/to/log4j.jar"]) + fi +fi + # sdt.h integration AC_ARG_WITH([sdt], [AS_HELP_STRING([--with-sdt],[provide SystemTap integration via sdt.h [default=no]])], @@ -313,9 +342,6 @@ AC_ARG_WITH([lttng-system-rundir], AC_DEFINE_UNQUOTED([LTTNG_SYSTEM_RUNDIR], ["$lttng_system_rundir"], [LTTng system runtime directory]) -lttnglibjavadir="${libdir}/lttng/java" -AC_SUBST(lttnglibjavadir) - AM_PATH_PYTHON([2.7],BUILD_GEN_TP_EXAMPLES=1,[:]) AM_CONDITIONAL([BUILD_GEN_TP_EXAMPLES], [test $BUILD_GEN_TP_EXAMPLES], [Build examples requiring lttng-gen-tp]) @@ -333,7 +359,11 @@ AC_CONFIG_FILES([ liblttng-ust-fork/Makefile liblttng-ust-dl/Makefile liblttng-ust-java/Makefile - liblttng-ust-jul/Makefile + liblttng-ust-java-agent/Makefile + liblttng-ust-java-agent/java/Makefile + liblttng-ust-java-agent/jni/Makefile + liblttng-ust-java-agent/jni/jul/Makefile + liblttng-ust-java-agent/jni/log4j/Makefile liblttng-ust-libc-wrapper/Makefile liblttng-ust-cyg-profile/Makefile tools/Makefile @@ -344,7 +374,6 @@ AC_CONFIG_FILES([ tests/snprintf/Makefile tests/benchmark/Makefile tests/utils/Makefile - tests/java-jul/Makefile lttng-ust.pc ]) @@ -359,7 +388,14 @@ AS_ECHO() AS_ECHO("LTTng-UST will be built with the following options:") AS_ECHO() -AS_ECHO_N("Java support (JNI): ") + +AS_ECHO_N("Java agent (JUL support): ") +AS_IF([test "x$java_agent_jul" = "xyes"], [AS_ECHO("Enabled")], [AS_ECHO("Disabled")]) + +AS_ECHO_N("Java agent (Log4j support): ") +AS_IF([test "x$java_agent_log4j" = "xyes"], [AS_ECHO("Enabled")], [AS_ECHO("Disabled")]) + +AS_ECHO_N("JNI interface (JNI): ") AS_IF([test "x$jni_interface" = "xyes"], [AS_ECHO("Enabled")], [AS_ECHO("Disabled")]) AS_ECHO_N("sdt.h integration: ") diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am index 06905972..fbabb8ec 100644 --- a/doc/examples/Makefile.am +++ b/doc/examples/Makefile.am @@ -5,11 +5,11 @@ doc_examples_demodir = ${docdir}/examples/demo doc_examples_hello_static_libdir = ${docdir}/examples/hello-static-lib doc_examples_demo_tracefdir = ${docdir}/examples/demo-tracef -if BUILD_JNI_INTERFACE +if BUILD_JAVA_AGENT doc_examples_java_juldir = ${docdir}/examples/java-jul dist_doc_examples_java_jul_DATA = java-jul/Makefile \ - java-jul/Hello.java \ - java-jul/run + java-jul/Hello.java \ + java-jul/run SUBDIRS_JUL = java-jul endif @@ -79,7 +79,7 @@ all-local: done; \ if [ x"$(SUBDIRS_JUL)" != x"" ]; then \ for subdir in $(SUBDIRS_JUL); do \ - (cd $(SUBDIRS_JUL) && $(MAKE) JAVA_CLASSPATH_OVERRIDE="../../../liblttng-ust-jul" JAVA_JARFILE_OVERRIDE="liblttng-ust-jul.jar" $(AM_MAKEFLAGS) all && cd ..) || exit 1; \ + (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; \ done; \ fi; diff --git a/doc/examples/java-jul/Hello.java b/doc/examples/java-jul/Hello.java index a4414723..87b4c160 100644 --- a/doc/examples/java-jul/Hello.java +++ b/doc/examples/java-jul/Hello.java @@ -27,7 +27,7 @@ import java.util.logging.Logger; /* * That's the import you need being the path in the liblttng-ust-jul Jar file. */ -import org.lttng.ust.jul.LTTngAgent; +import org.lttng.ust.agent.LTTngAgent; public class Hello { diff --git a/doc/examples/java-jul/Makefile b/doc/examples/java-jul/Makefile index 3af44d3e..a45719d1 100644 --- a/doc/examples/java-jul/Makefile +++ b/doc/examples/java-jul/Makefile @@ -17,7 +17,7 @@ # # Default JUL jar name. -JARFILE=liblttng-ust-jul.jar +JARFILE=liblttng-ust-agent.jar # Check if the top level makefile overrides the JUL Jar file name. ifneq "$(JAVA_JARFILE_OVERRIDE)" "" @@ -26,7 +26,7 @@ endif # Check if the top level makefile overrides the JUL classpath. ifeq "$(JAVA_CLASSPATH_OVERRIDE)" "" - CLASSPATH=/usr/local/lib/lttng/java/$(JARFILE):/usr/lib/lttng/java/$(JARFILE) + CLASSPATH=/usr/local/share/java/$(JARFILE):/usr/share/java/$(JARFILE) else CLASSPATH=$(JAVA_CLASSPATH_OVERRIDE)/$(JARFILE) endif diff --git a/doc/examples/java-jul/run b/doc/examples/java-jul/run index da8365b7..b8342f70 100755 --- a/doc/examples/java-jul/run +++ b/doc/examples/java-jul/run @@ -7,15 +7,15 @@ # DIR=`dirname $0` -JARFILE="liblttng-ust-jul.jar" +JARFILE="liblttng-ust-agent.jar" cd $DIR if [ -f "$DIR/.intree" ]; then - CLASSPATH="../../../liblttng-ust-jul/$JARFILE" - LIBPATH="../../../liblttng-ust-jul/.libs" + CLASSPATH="../../../liblttng-ust-java-agent/java/$JARFILE" + LIBPATH="../../../liblttng-ust-java-agent/jni/jul/.libs" else - CLASSPATH="/usr/local/lib/lttng/java/$JARFILE:/usr/lib/lttng/java/$JARFILE" + CLASSPATH="/usr/local/share/java/$JARFILE:/usr/share/java/$JARFILE" LIBPATH="/usr/local/lib:/usr/lib" fi diff --git a/doc/examples/java-log4j/Hello.java b/doc/examples/java-log4j/Hello.java new file mode 100644 index 00000000..a0105adf --- /dev/null +++ b/doc/examples/java-log4j/Hello.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 - Christian Babeux + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +import java.io.IOException; + +import org.apache.log4j.Logger; +import org.apache.log4j.BasicConfigurator; + +import org.lttng.ust.agent.LTTngAgent; + +public class Hello +{ + /* Of course :) */ + private static final int answer = 42; + + static Logger helloLog = Logger.getLogger(Hello.class); + + private static LTTngAgent lttngAgent; + + public static void main(String args[]) throws Exception + { + BasicConfigurator.configure(); + lttngAgent = LTTngAgent.getLTTngAgent(); + + /* + * Gives you time to do some lttng commands before any event is hit. + */ + Thread.sleep(5000); + + /* Trigger a tracing event using the JUL Logger created before. */ + helloLog.info("Hello World, the answer is " + answer); + + System.out.println("Firing hello delay in 10 seconds..."); + Thread.sleep(5000); + helloLog.info("Hello World delayed..."); + } +} diff --git a/doc/examples/java-log4j/Makefile b/doc/examples/java-log4j/Makefile new file mode 100644 index 00000000..e174e318 --- /dev/null +++ b/doc/examples/java-log4j/Makefile @@ -0,0 +1,50 @@ +# +# Copyright (C) 2014 - Christian Babeux +# +# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR +# IMPLIED. ANY USE IS AT YOUR OWN RISK. +# +# Permission is hereby granted to use or copy this program for any purpose, +# provided the above notices are retained on all copies. Permission to modify +# the code and to distribute modified code is granted, provided the above +# notices are retained, and a notice that the code was modified is included +# with the above copyright notice. +# +# This Makefile is not using automake so that users may see how to build a +# program with tracepoint provider probes as stand-alone shared objects. +# +# This makefile is purposefully kept simple to support GNU and BSD make. +# + +JFLAGS = -g + +# Default JUL jar name. +JARFILE=liblttng-ust-agent.jar +LOG4J=/usr/share/java/log4j.jar + +# Check if the top level makefile overrides the JUL Jar file name. +ifneq "$(JAVA_JARFILE_OVERRIDE)" "" + JARFILE=$(JAVA_JARFILE_OVERRIDE) +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):$(LOG4J) +else + CLASSPATH=$(JAVA_CLASSPATH_OVERRIDE)/$(JARFILE):$(LOG4J) +endif + +JC = javac -cp "$(CLASSPATH):." +.SUFFIXES: .java .class +.java.class: + $(JC) $(JFLAGS) $*.java + +CLASSES = Hello.java + +all: classes + +classes: $(CLASSES:.java=.class) + +.PHONY: clean +clean: + $(RM) *.class diff --git a/doc/examples/java-log4j/run b/doc/examples/java-log4j/run new file mode 100755 index 00000000..3a84f594 --- /dev/null +++ b/doc/examples/java-log4j/run @@ -0,0 +1,25 @@ +#!/bin/bash + +# +# The -cp path should be changed to the lttng ust agent jar file on your system +# or locally to the project. Same goes for the Java library path in order to +# find the JNI Log4j library. +# + +DIR=`dirname $0` +JARFILE="liblttng-ust-agent.jar" +LOG4J="/usr/local/share/java/log4j.jar:/usr/share/java/log4j.jar" + +cd $DIR + +if [ -f "$DIR/.intree" ]; then + CLASSPATH="../../../liblttng-ust-java-agent/java/$JARFILE:$LOG4J" + LIBPATH="../../../liblttng-ust-java-agent/jni/log4j/.libs" +else + CLASSPATH="/usr/local/share/java/$JARFILE:/usr/share/java/$JARFILE:$LOG4J" + LIBPATH="/usr/local/lib:/usr/lib" +fi + +java -cp "$CLASSPATH:." Hello + +cd - diff --git a/liblttng-ust-java-agent/Makefile.am b/liblttng-ust-java-agent/Makefile.am new file mode 100644 index 00000000..7ce122f1 --- /dev/null +++ b/liblttng-ust-java-agent/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = java jni diff --git a/liblttng-ust-java-agent/java/Makefile.am b/liblttng-ust-java-agent/java/Makefile.am new file mode 100644 index 00000000..c949bf89 --- /dev/null +++ b/liblttng-ust-java-agent/java/Makefile.am @@ -0,0 +1,58 @@ +JAVAROOT = . + +jarfile = liblttng-ust-agent.jar +jarfile_old = liblttng-ust-jul.jar +jardir = $(datadir)/java +juljniout = ../jni/jul +log4jjniout = ../jni/log4j +pkgpath = org/lttng/ust/agent +pkgpath_old = org/lttng/ust/jul +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 \ + $(pkgpath_old)/LTTngAgent.java + +jar_DATA = $(jarfile) $(jarfile_old) + +stamp = +classes = $(pkgpath)/*.class + +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 +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 +endif + +$(jarfile): classnoinst.stamp + $(JAR) cf $(JARFLAGS) $@ $(classes) + +$(jarfile_old): classnoinst.stamp + $(JAR) cf $(JARFLAGS) $@ $(pkgpath)/*.class \ + $(pkgpath)/jul/*.class $(pkgpath_old)/*.class + +jul-jni-header.stamp: $(dist_noinst_JAVA) + $(JAVAH) -cp $(CLASSPATH):. -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) -cp $(CLASSPATH):. -d $(log4jjniout) $(JAVAHFLAGS) org.lttng.ust.agent.log4j.LTTngLogAppender && \ + echo "Log4j JNI header generated" > log4j-jni-header.stamp + +all-local: $(stamp) + +CLEANFILES = $(jarfile) $(jarfile_old) $(pkgpath)/*.class $(pkgpath_old)/*.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/org/lttng/ust/agent/LTTngAgent.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngAgent.java new file mode 100644 index 00000000..342ccfae --- /dev/null +++ b/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngAgent.java @@ -0,0 +1,273 @@ +/* + * 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 org.lttng.ust.agent.jul.LTTngJUL; + +import java.io.IOException; +import java.io.InputStream; +import java.io.BufferedReader; +import java.io.FileReader; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.Enumeration; +import java.lang.reflect.InvocationTargetException; + +import java.util.logging.Logger; +import java.util.logging.FileHandler;; +import java.util.logging.SimpleFormatter; + +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 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; + private final static int semTimeout = 3; /* Seconds */ + + /* + * Constructor is private. This is a singleton and a reference should be + * acquired using getLTTngAgent(). + */ + private LTTngAgent() throws IOException { + 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(); + } + + this.registerSem = new Semaphore(0, true); + } + + private Boolean loadLog4jClasses() { + Boolean loaded = false; + try { + ClassLoader loader = ClassLoader.getSystemClassLoader(); + loader.loadClass("org.apache.log4j.Logger"); + loaded = true; + } catch (ClassNotFoundException e) { + /* Log4j classes not found, no need to create the relevant objects */ + loaded = false; + } + + return loaded; + } + + private void initAgentJULClasses() { + try { + ClassLoader loader = ClassLoader.getSystemClassLoader(); + Class lttngJUL = loader.loadClass("org.lttng.ust.agent.jul.LTTngJUL"); + this.julUser = (LogFramework)lttngJUL.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(false); + this.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 { + ClassLoader loader = ClassLoader.getSystemClassLoader(); + Class lttngLog4j = loader.loadClass("org.lttng.ust.agent.log4j.LTTngLog4j"); + this.log4jUser = (LogFramework)lttngLog4j.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(false); + this.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, IOException { + if (this.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 { + this.registerSem.tryAcquire(numThreads, + semTimeout, + TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + this.initialized = true; + } + + private synchronized Integer initJULClientThreads() { + Integer numThreads = 2; + + /* Handle user session daemon if any. */ + this.julUserClient = new LTTngTCPSessiondClient(Domain.JUL, + this.julUser, + this.registerSem); + + String userThreadName = "LTTng UST agent JUL user thread"; + this.sessiondThreadJULUser = new Thread(julUserClient, userThreadName); + this.sessiondThreadJULUser.setDaemon(true); + this.sessiondThreadJULUser.start(); + + /* Handle root session daemon. */ + this.julRootClient = new LTTngTCPSessiondClient(Domain.JUL, + this.julRoot, + this.registerSem); + + String rootThreadName = "LTTng UST agent JUL root thread"; + this.sessiondThreadJULRoot = new Thread(julRootClient, rootThreadName); + this.sessiondThreadJULRoot.setDaemon(true); + this.sessiondThreadJULRoot.start(); + + return numThreads; + } + + private synchronized Integer initLog4jClientThreads() { + Integer numThreads = 2; + + this.log4jUserClient = new LTTngTCPSessiondClient(Domain.LOG4J, + this.log4jUser, + this.registerSem); + + String userThreadName = "LTTng UST agent Log4j user thread"; + this.sessiondThreadLog4jUser = new Thread(log4jUserClient, userThreadName); + this.sessiondThreadLog4jUser.setDaemon(true); + this.sessiondThreadLog4jUser.start(); + + this.log4jRootClient = new LTTngTCPSessiondClient(Domain.LOG4J, + this.log4jRoot, + this.registerSem); + + String rootThreadName = "LTTng UST agent Log4j root thread"; + this.sessiondThreadLog4jRoot = new Thread(log4jRootClient,rootThreadName); + this.sessiondThreadLog4jRoot.setDaemon(true); + this.sessiondThreadLog4jRoot.start(); + + return numThreads; + } + + + public void dispose() throws IOException { + if (this.useJUL) { + this.julUserClient.destroy(); + this.julRootClient.destroy(); + this.julUser.reset(); + this.julRoot.reset(); + } + + if (this.useLog4j) { + this.log4jUserClient.destroy(); + this.log4jRootClient.destroy(); + this.log4jUser.reset(); + this.log4jRoot.reset(); + } + + try { + if (this.useJUL) { + this.sessiondThreadJULUser.join(); + this.sessiondThreadJULRoot.join(); + } + + if (this.useLog4j) { + this.sessiondThreadLog4jUser.join(); + this.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 new file mode 100644 index 00000000..c68308e7 --- /dev/null +++ b/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngSessiondCmd2_6.java @@ -0,0 +1,239 @@ +/* + * 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.lang.Object; +import java.util.ArrayList; +import java.util.List; +import java.util.Enumeration; +import java.util.Iterator; + +interface LTTngSessiondCmd2_6 { + /** + * Maximum name length for a logger name to be send to sessiond. + */ + final static 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... + */ + final static int INT_SIZE = 4; + + public 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(); + } + + public interface SessiondCommand { + /** + * Populate the class from a byte array + * + * @param data + * the byte array containing the streamed command + */ + public void populate(byte[] data); + } + + public 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; + } + } + + public 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 data_size; + /** Command type. */ + public lttng_agent_command cmd; + /** Command version. */ + public int cmd_version; + + public void populate(byte[] data) { + ByteBuffer buf = ByteBuffer.wrap(data); + buf.order(ByteOrder.BIG_ENDIAN); + + data_size = buf.getLong(); + cmd = lttng_agent_command.values()[buf.getInt() - 1]; + cmd_version = buf.getInt(); + } + } + + public class sessiond_enable_handler implements SessiondResponse, SessiondCommand { + private final static 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 data_offset = INT_SIZE * 2; + + ByteBuffer buf = ByteBuffer.wrap(data); + buf.order(ByteOrder.LITTLE_ENDIAN); + lttngLogLevel = buf.getInt(); + lttngLogLevelType = buf.getInt(); + name = new String(data, data_offset, data.length - data_offset).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; + } + } + } + + public 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; + } + } + } + + public class sessiond_list_logger implements SessiondResponse { + private final static int SIZE = 12; + + private int data_size = 0; + private int nb_logger = 0; + + List logger_list = new ArrayList(); + + /** Return status code to the session daemon. */ + public lttng_agent_ret_code code; + + @Override + public byte[] getBytes() { + byte data[] = new byte[SIZE + data_size]; + ByteBuffer buf = ByteBuffer.wrap(data); + buf.order(ByteOrder.BIG_ENDIAN); + + /* Returned code */ + buf.putInt(code.getCode()); + buf.putInt(data_size); + buf.putInt(nb_logger); + + for (String logger: logger_list) { + 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.logger_list.add(loggerName); + this.nb_logger++; + this.data_size += 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 new file mode 100644 index 00000000..ab800ede --- /dev/null +++ b/liblttng-ust-java-agent/java/org/lttng/ust/agent/LTTngTCPSessiondClient.java @@ -0,0 +1,319 @@ +/* + * 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.util.concurrent.Semaphore; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.lang.Integer; +import java.io.IOException; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.DataInputStream; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.net.*; +import java.lang.management.ManagementFactory; + +class LTTngTCPSessiondClient implements Runnable { + + /* 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 static final String sessiondHost = "127.0.0.1"; + private static final String rootPortFile = "/var/run/lttng/agent.port"; + private static final String userPortFile = "/.lttng/agent.port"; + + private static Integer protocolMajorVersion = 1; + private static Integer protocolMinorVersion = 0; + + private LTTngAgent.Domain agentDomain; + + /* Indicate if we've already release the semaphore. */ + private boolean sem_posted = 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.sem_posted) { + this.registerSem.release(); + this.sem_posted = 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 { + int read_len; + byte data[] = new byte[this.headerCmd.SIZE]; + + read_len = this.inFromSessiond.read(data, 0, data.length); + if (read_len != 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.data_size]; + + /* 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 { + int ret_code; + byte data[] = null; + + while (true) { + /* Get header from session daemon. */ + recvHeader(); + + if (headerCmd.data_size > 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); + LTTngSessiondCmd2_6.lttng_agent_ret_code code = + LTTngSessiondCmd2_6.lttng_agent_ret_code.CODE_INVALID_CMD; + break; + } + } + + /* Send payload to session daemon. */ + this.outToSessiond.write(data, 0, data.length); + this.outToSessiond.flush(); + } + } + + private 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 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(rootPortFile); + if (port == 0) { + /* No session daemon available. Stop and retry later. */ + throw new IOException(); + } + } else { + port = getPortFromFile(getHomePath() + userPortFile); + if (port == 0) { + /* No session daemon available. Stop and retry later. */ + throw new IOException(); + } + } + + this.sessiondSock = new Socket(this.sessiondHost, 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(this.protocolMajorVersion); + buf.putInt(this.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 new file mode 100644 index 00000000..0dd7c982 --- /dev/null +++ b/liblttng-ust-java-agent/java/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/org/lttng/ust/agent/LogFrameworkSkeleton.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/LogFrameworkSkeleton.java new file mode 100644 index 00000000..4ad981e9 --- /dev/null +++ b/liblttng-ust-java-agent/java/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 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/jul/LTTngJUL.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/jul/LTTngJUL.java new file mode 100644 index 00000000..6a3eac95 --- /dev/null +++ b/liblttng-ust-java-agent/java/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/org/lttng/ust/agent/jul/LTTngLogHandler.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/jul/LTTngLogHandler.java new file mode 100644 index 00000000..a20aed21 --- /dev/null +++ b/liblttng-ust-java-agent/java/org/lttng/ust/agent/jul/LTTngLogHandler.java @@ -0,0 +1,81 @@ +/* + * 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 Boolean is_root; + + public LTTngLogHandler(Boolean isRoot) { + super(); + this.is_root = 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.is_root; + } + + @Override + public void close() throws SecurityException {} + + @Override + public void flush() {} + + @Override + public void publish(LogRecord record) { + /* + * Specific tracepoing 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.is_root) { + 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 new file mode 100644 index 00000000..065b1630 --- /dev/null +++ b/liblttng-ust-java-agent/java/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/org/lttng/ust/agent/log4j/LTTngLogAppender.java b/liblttng-ust-java-agent/java/org/lttng/ust/agent/log4j/LTTngLogAppender.java new file mode 100644 index 00000000..0d4d6f32 --- /dev/null +++ b/liblttng-ust-java-agent/java/org/lttng/ust/agent/log4j/LTTngLogAppender.java @@ -0,0 +1,114 @@ +/* + * 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 is_root; + + public LTTngLogAppender(Boolean isRoot) { + super(); + this.is_root = 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.is_root; + } + + @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.is_root) { + 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/jul/LTTngAgent.java b/liblttng-ust-java-agent/java/org/lttng/ust/jul/LTTngAgent.java new file mode 100644 index 00000000..cd45ba13 --- /dev/null +++ b/liblttng-ust-java-agent/java/org/lttng/ust/jul/LTTngAgent.java @@ -0,0 +1,49 @@ +/* + * 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.jul; + +import java.io.IOException; + +public class LTTngAgent { + + /* + * !!! WARNING !!! + * Please use the LTTngAgent found in the org.lttng.ust.agent package. + * This class is DEPRECATED. + */ + + private static LTTngAgent curAgent = null; + private static org.lttng.ust.agent.LTTngAgent realAgent = null; + + + private LTTngAgent() throws IOException { + realAgent = org.lttng.ust.agent.LTTngAgent.getLTTngAgent(); + } + + public static synchronized LTTngAgent getLTTngAgent() throws IOException { + if (curAgent == null) { + curAgent = new LTTngAgent(); + } + + return curAgent; + } + + public void dispose() throws IOException { + realAgent.dispose(); + } +} diff --git a/liblttng-ust-java-agent/jni/Makefile.am b/liblttng-ust-java-agent/jni/Makefile.am new file mode 100644 index 00000000..5310c339 --- /dev/null +++ b/liblttng-ust-java-agent/jni/Makefile.am @@ -0,0 +1,8 @@ +SUBDIRS= +if BUILD_JAVA_AGENT_WITH_JUL +SUBDIRS += jul +endif + +if BUILD_JAVA_AGENT_WITH_LOG4J +SUBDIRS += log4j +endif diff --git a/liblttng-ust-java-agent/jni/jul/Makefile.am b/liblttng-ust-java-agent/jni/jul/Makefile.am new file mode 100644 index 00000000..6c9dc287 --- /dev/null +++ b/liblttng-ust-java-agent/jni/jul/Makefile.am @@ -0,0 +1,9 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include + +lib_LTLIBRARIES = liblttng-ust-jul-jni.la +liblttng_ust_jul_jni_la_SOURCES = lttng_ust_jul.c \ + lttng_ust_jul.h + +nodist_liblttng_ust_jul_jni_la_SOURCES = org_lttng_ust_agent_jul_LTTngLogHandler.h + +liblttng_ust_jul_jni_la_LIBADD = -lc -L$(top_builddir)/liblttng-ust/.libs -llttng-ust diff --git a/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.c b/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.c new file mode 100644 index 00000000..b089fe3b --- /dev/null +++ b/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011-2012 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * 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 + */ + +#include "org_lttng_ust_agent_jul_LTTngLogHandler.h" + +#define TRACEPOINT_DEFINE +#define TRACEPOINT_CREATE_PROBES +#include "lttng_ust_jul.h" + +/* + * System tracepoint meaning only root agent will fire this. + */ +JNIEXPORT void JNICALL Java_org_lttng_ust_agent_jul_LTTngLogHandler_tracepointS(JNIEnv *env, + jobject jobj, + jstring msg, + jstring logger_name, + jstring class_name, + jstring method_name, + jlong millis, + jint log_level, + jint thread_id) +{ + jboolean iscopy; + const char *msg_cstr = (*env)->GetStringUTFChars(env, msg, &iscopy); + const char *logger_name_cstr = (*env)->GetStringUTFChars(env, logger_name, &iscopy); + const char *class_name_cstr = (*env)->GetStringUTFChars(env, class_name, &iscopy); + const char *method_name_cstr = (*env)->GetStringUTFChars(env, method_name, &iscopy); + + tracepoint(lttng_jul, sys_event, msg_cstr, logger_name_cstr, + class_name_cstr, method_name_cstr, millis, log_level, thread_id); + + (*env)->ReleaseStringUTFChars(env, msg, msg_cstr); + (*env)->ReleaseStringUTFChars(env, logger_name, logger_name_cstr); + (*env)->ReleaseStringUTFChars(env, class_name, class_name_cstr); + (*env)->ReleaseStringUTFChars(env, method_name, method_name_cstr); +} + +/* + * User tracepoint meaning only a non root agent will fire this. + */ +JNIEXPORT void JNICALL Java_org_lttng_ust_agent_jul_LTTngLogHandler_tracepointU(JNIEnv *env, + jobject jobj, + jstring msg, + jstring logger_name, + jstring class_name, + jstring method_name, + jlong millis, + jint log_level, + jint thread_id) +{ + jboolean iscopy; + const char *msg_cstr = (*env)->GetStringUTFChars(env, msg, &iscopy); + const char *logger_name_cstr = (*env)->GetStringUTFChars(env, logger_name, &iscopy); + const char *class_name_cstr = (*env)->GetStringUTFChars(env, class_name, &iscopy); + const char *method_name_cstr = (*env)->GetStringUTFChars(env, method_name, &iscopy); + + tracepoint(lttng_jul, user_event, msg_cstr, logger_name_cstr, + class_name_cstr, method_name_cstr, millis, log_level, thread_id); + + (*env)->ReleaseStringUTFChars(env, msg, msg_cstr); + (*env)->ReleaseStringUTFChars(env, logger_name, logger_name_cstr); + (*env)->ReleaseStringUTFChars(env, class_name, class_name_cstr); + (*env)->ReleaseStringUTFChars(env, method_name, method_name_cstr); +} diff --git a/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.h b/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.h new file mode 100644 index 00000000..a45af396 --- /dev/null +++ b/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.h @@ -0,0 +1,81 @@ +#undef TRACEPOINT_PROVIDER +#define TRACEPOINT_PROVIDER lttng_jul + +#if !defined(_TRACEPOINT_LTTNG_UST_JUL_H) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define _TRACEPOINT_LTTNG_UST_JUL_H + +/* + * Copyright (C) 2011 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 of + * the License. + * + * 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 + */ + +#include + +/* + * Privileged tracepoint meaning that this is only enable and fired by the root + * session daemon. + */ +TRACEPOINT_EVENT(lttng_jul, sys_event, + TP_ARGS( + const char *, msg, + const char *, logger_name, + const char *, class_name, + const char *, method_name, + long, millis, + int, log_level, + int, thread_id), + TP_FIELDS( + ctf_string(msg, msg) + ctf_string(logger_name, logger_name) + ctf_string(class_name, class_name) + ctf_string(method_name, method_name) + ctf_integer(long, long_millis, millis) + ctf_integer(int, int_loglevel, log_level) + ctf_integer(int, int_threadid, thread_id) + ) +) + +/* + * User tracepoint meaning that this is only enable and fired by a non root + * session daemon. + */ +TRACEPOINT_EVENT(lttng_jul, user_event, + TP_ARGS( + const char *, msg, + const char *, logger_name, + const char *, class_name, + const char *, method_name, + long, millis, + int, log_level, + int, thread_id), + TP_FIELDS( + ctf_string(msg, msg) + ctf_string(logger_name, logger_name) + ctf_string(class_name, class_name) + ctf_string(method_name, method_name) + ctf_integer(long, long_millis, millis) + ctf_integer(int, int_loglevel, log_level) + ctf_integer(int, int_threadid, thread_id) + ) +) + +#endif /* _TRACEPOINT_LTTNG_UST_JUL_H */ + +#undef TRACEPOINT_INCLUDE +#define TRACEPOINT_INCLUDE "./lttng_ust_jul.h" + +/* This part must be outside protection */ +#include diff --git a/liblttng-ust-java-agent/jni/log4j/Makefile.am b/liblttng-ust-java-agent/jni/log4j/Makefile.am new file mode 100644 index 00000000..b734bf3d --- /dev/null +++ b/liblttng-ust-java-agent/jni/log4j/Makefile.am @@ -0,0 +1,8 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include +lib_LTLIBRARIES = liblttng-ust-log4j-jni.la +liblttng_ust_log4j_jni_la_SOURCES = lttng_ust_log4j.c \ + lttng_ust_log4j.h + +nodist_liblttng_ust_log4j_jni_la_SOURCES = org_lttng_ust_agent_log4j_LTTngLogAppender.h + +liblttng_ust_log4j_jni_la_LIBADD = -lc -L$(top_builddir)/liblttng-ust/.libs -llttng-ust diff --git a/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c b/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c new file mode 100644 index 00000000..c887f7f4 --- /dev/null +++ b/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2011-2012 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * 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 + */ + +#include "org_lttng_ust_agent_log4j_LTTngLogAppender.h" + +#define TRACEPOINT_DEFINE +#define TRACEPOINT_CREATE_PROBES +#include "lttng_ust_log4j.h" + +/* + * System tracepoint meaning only root agent will fire this. + */ +JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j_LTTngLogAppender_tracepointS(JNIEnv *env, + jobject jobj, + jstring msg, + jstring logger_name, + jstring class_name, + jstring method_name, + jstring file_name, + jint line_number, + jlong timestamp, + jint loglevel, + jstring thread_name) +{ + jboolean iscopy; + const char *msg_cstr = (*env)->GetStringUTFChars(env, msg, &iscopy); + const char *logger_name_cstr = (*env)->GetStringUTFChars(env, logger_name, &iscopy); + const char *class_name_cstr = (*env)->GetStringUTFChars(env, class_name, &iscopy); + const char *method_name_cstr = (*env)->GetStringUTFChars(env, method_name, &iscopy); + const char *file_name_cstr = (*env)->GetStringUTFChars(env, file_name, &iscopy); + const char *thread_name_cstr = (*env)->GetStringUTFChars(env, thread_name, &iscopy); + + tracepoint(lttng_log4j, sys_event, msg_cstr, logger_name_cstr, + class_name_cstr, method_name_cstr, file_name_cstr, + line_number, timestamp, loglevel, thread_name_cstr); + + (*env)->ReleaseStringUTFChars(env, msg, msg_cstr); + (*env)->ReleaseStringUTFChars(env, logger_name, logger_name_cstr); + (*env)->ReleaseStringUTFChars(env, class_name, class_name_cstr); + (*env)->ReleaseStringUTFChars(env, method_name, method_name_cstr); + (*env)->ReleaseStringUTFChars(env, file_name, file_name_cstr); + (*env)->ReleaseStringUTFChars(env, thread_name, thread_name_cstr); +} + +/* + * User tracepoint meaning only a non root agent will fire this. + */ +JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j_LTTngLogAppender_tracepointU(JNIEnv *env, + jobject jobj, + jstring msg, + jstring logger_name, + jstring class_name, + jstring method_name, + jstring file_name, + jint line_number, + jlong timestamp, + jint loglevel, + jstring thread_name) +{ + jboolean iscopy; + const char *msg_cstr = (*env)->GetStringUTFChars(env, msg, &iscopy); + const char *logger_name_cstr = (*env)->GetStringUTFChars(env, logger_name, &iscopy); + const char *class_name_cstr = (*env)->GetStringUTFChars(env, class_name, &iscopy); + const char *method_name_cstr = (*env)->GetStringUTFChars(env, method_name, &iscopy); + const char *file_name_cstr = (*env)->GetStringUTFChars(env, file_name, &iscopy); + const char *thread_name_cstr = (*env)->GetStringUTFChars(env, thread_name, &iscopy); + + tracepoint(lttng_log4j, user_event, msg_cstr, logger_name_cstr, + class_name_cstr, method_name_cstr, file_name_cstr, + line_number, timestamp, loglevel, thread_name_cstr); + + (*env)->ReleaseStringUTFChars(env, msg, msg_cstr); + (*env)->ReleaseStringUTFChars(env, logger_name, logger_name_cstr); + (*env)->ReleaseStringUTFChars(env, class_name, class_name_cstr); + (*env)->ReleaseStringUTFChars(env, method_name, method_name_cstr); + (*env)->ReleaseStringUTFChars(env, file_name, file_name_cstr); + (*env)->ReleaseStringUTFChars(env, thread_name, thread_name_cstr); +} diff --git a/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h b/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h new file mode 100644 index 00000000..cc403578 --- /dev/null +++ b/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h @@ -0,0 +1,89 @@ +#undef TRACEPOINT_PROVIDER +#define TRACEPOINT_PROVIDER lttng_log4j + +#if !defined(_TRACEPOINT_LTTNG_UST_LOG4J_H) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define _TRACEPOINT_LTTNG_UST_LOG4J_H + +/* + * Copyright (C) 2011 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 of + * the License. + * + * 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 + */ + +#include + +/* + * Privileged tracepoint meaning that this is only enable and fired by the root + * session daemon. + */ +TRACEPOINT_EVENT(lttng_log4j, sys_event, + TP_ARGS( + const char *, msg, + const char *, logger_name, + const char *, class_name, + const char *, method_name, + const char *, file_name, + int, line_number, + long, timestamp, + int, log_level, + const char *, thread_name), + TP_FIELDS( + ctf_string(msg, msg) + ctf_string(logger_name, logger_name) + ctf_string(class_name, class_name) + ctf_string(method_name, method_name) + ctf_string(filename, file_name) + ctf_integer(int, line_number, line_number) + ctf_integer(long, timestamp, timestamp) + ctf_integer(int, int_loglevel, log_level) + ctf_string(thread_name, thread_name) + ) +) + +/* + * User tracepoint meaning that this is only enable and fired by a non root + * session daemon. + */ +TRACEPOINT_EVENT(lttng_log4j, user_event, + TP_ARGS( + const char *, msg, + const char *, logger_name, + const char *, class_name, + const char *, method_name, + const char *, file_name, + int, line_number, + long, timestamp, + int, log_level, + const char *, thread_name), + TP_FIELDS( + ctf_string(msg, msg) + ctf_string(logger_name, logger_name) + ctf_string(class_name, class_name) + ctf_string(method_name, method_name) + ctf_string(filename, file_name) + ctf_integer(int, line_number, line_number) + ctf_integer(long, timestamp, timestamp) + ctf_integer(int, int_loglevel, log_level) + ctf_string(thread_name, thread_name) + ) +) + +#endif /* _TRACEPOINT_LTTNG_UST_LOG4J_H */ + +#undef TRACEPOINT_INCLUDE +#define TRACEPOINT_INCLUDE "./lttng_ust_log4j.h" + +/* This part must be outside protection */ +#include diff --git a/liblttng-ust-jul/LTTngUst.c b/liblttng-ust-jul/LTTngUst.c deleted file mode 100644 index e6837fbb..00000000 --- a/liblttng-ust-jul/LTTngUst.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2011-2012 Mathieu Desnoyers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; only - * version 2.1 of the License. - * - * 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 - */ - -#include "org_lttng_ust_jul_LTTngUst.h" - -#define TRACEPOINT_DEFINE -#define TRACEPOINT_CREATE_PROBES -#include "lttng_ust_jul.h" - -/* - * System tracepoint meaning only root agent will fire this. - */ -JNIEXPORT void JNICALL Java_org_lttng_ust_jul_LTTngUst_tracepointS(JNIEnv *env, - jobject jobj, - jstring msg, - jstring logger_name, - jstring class_name, - jstring method_name, - jlong millis, - jint log_level, - jint thread_id) -{ - jboolean iscopy; - const char *msg_cstr = (*env)->GetStringUTFChars(env, msg, &iscopy); - const char *logger_name_cstr = (*env)->GetStringUTFChars(env, logger_name, &iscopy); - const char *class_name_cstr = (*env)->GetStringUTFChars(env, class_name, &iscopy); - const char *method_name_cstr = (*env)->GetStringUTFChars(env, method_name, &iscopy); - - tracepoint(lttng_jul, sys_event, msg_cstr, logger_name_cstr, - class_name_cstr, method_name_cstr, millis, log_level, thread_id); - - (*env)->ReleaseStringUTFChars(env, msg, msg_cstr); - (*env)->ReleaseStringUTFChars(env, logger_name, logger_name_cstr); - (*env)->ReleaseStringUTFChars(env, class_name, class_name_cstr); - (*env)->ReleaseStringUTFChars(env, method_name, method_name_cstr); -} - -/* - * User tracepoint meaning only a non root agent will fire this. - */ -JNIEXPORT void JNICALL Java_org_lttng_ust_jul_LTTngUst_tracepointU(JNIEnv *env, - jobject jobj, - jstring msg, - jstring logger_name, - jstring class_name, - jstring method_name, - jlong millis, - jint log_level, - jint thread_id) -{ - jboolean iscopy; - const char *msg_cstr = (*env)->GetStringUTFChars(env, msg, &iscopy); - const char *logger_name_cstr = (*env)->GetStringUTFChars(env, logger_name, &iscopy); - const char *class_name_cstr = (*env)->GetStringUTFChars(env, class_name, &iscopy); - const char *method_name_cstr = (*env)->GetStringUTFChars(env, method_name, &iscopy); - - tracepoint(lttng_jul, user_event, msg_cstr, logger_name_cstr, - class_name_cstr, method_name_cstr, millis, log_level, thread_id); - - (*env)->ReleaseStringUTFChars(env, msg, msg_cstr); - (*env)->ReleaseStringUTFChars(env, logger_name, logger_name_cstr); - (*env)->ReleaseStringUTFChars(env, class_name, class_name_cstr); - (*env)->ReleaseStringUTFChars(env, method_name, method_name_cstr); -} diff --git a/liblttng-ust-jul/Makefile.am b/liblttng-ust-jul/Makefile.am deleted file mode 100644 index eb0a5f60..00000000 --- a/liblttng-ust-jul/Makefile.am +++ /dev/null @@ -1,60 +0,0 @@ -LTTNG_JUL_SRCDIR = $(srcdir)/org/lttng/ust/jul -LTTNG_JUL_DESTDIR = $(builddir)/org/lttng/ust/jul - -if BUILD_JNI_INTERFACE - -AM_CPPFLAGS = -I$(top_srcdir)/include -I$(builddir) -I$(top_builddir)/include - -BUILT_SOURCES = org_lttng_ust_jul_LTTngUst.h -lib_LTLIBRARIES = liblttng-ust-jul-jni.la -liblttng_ust_jul_jni_la_SOURCES = LTTngUst.c lttng_ust_jul.h -nodist_liblttng_ust_jul_jni_la_SOURCES = org_lttng_ust_jul_LTTngUst.h -dist_noinst_DATA = $(LTTNG_JUL_SRCDIR)/LTTngUst.java \ - $(LTTNG_JUL_SRCDIR)/LTTngAgent.java \ - $(LTTNG_JUL_SRCDIR)/LTTngEvent.java \ - $(LTTNG_JUL_SRCDIR)/LTTngLogHandler.java \ - $(LTTNG_JUL_SRCDIR)/LTTngSessiondCmd2_4.java \ - $(LTTNG_JUL_SRCDIR)/LTTngTCPSessiondClient.java \ - $(LTTNG_JUL_SRCDIR)/LTTngThread.java -liblttng_ust_jul_jni_la_LIBADD = -lc -L$(top_builddir)/liblttng-ust/.libs -llttng-ust - -lttnglibjava_DATA = liblttng-ust-jul.jar - -if HAVE_JAVA_JDK -JCC=$(JAVA_JDK)/bin -else -JCC=javac -endif - -all-local: $(LTTNG_JUL_DESTDIR)/LTTngAgent.class \ - $(LTTNG_JUL_DESTDIR)/LTTngUst.class \ - org_lttng_ust_jul_LTTngUst.h \ - liblttng-ust-jul.jar - -clean-local: - rm -f org_lttng_ust_jul_LTTngUst.h - rm -f liblttng-ust-jul.jar - rm -f org/lttng/ust/jul/*.class - -%.class: %.java - $(JCC)/javac -d "$(builddir)" $< - -LTTNG_AGENT_FILES = $(LTTNG_JUL_SRCDIR)/LTTngAgent.java \ - $(LTTNG_JUL_SRCDIR)/LTTngLogHandler.java \ - $(LTTNG_JUL_SRCDIR)/LTTngEvent.java \ - $(LTTNG_JUL_SRCDIR)/LTTngSessiondCmd2_4.java \ - $(LTTNG_JUL_SRCDIR)/LTTngTCPSessiondClient.java \ - $(LTTNG_JUL_SRCDIR)/LTTngThread.java - -$(LTTNG_JUL_DESTDIR)/LTTngAgent.class: $(LTTNG_AGENT_FILES) \ - $(LTTNG_JUL_DESTDIR)/LTTngUst.class - $(JCC)/javac -d "$(builddir)" $(LTTNG_AGENT_FILES) - -org_lttng_ust_jul_LTTngUst.h: $(LTTNG_JUL_DESTDIR)/LTTngUst.class - $(JCC)/javah org.lttng.ust.jul.LTTngUst - -liblttng-ust-jul.jar: $(LTTNG_JUL_DESTDIR)/LTTngAgent.class - $(JCC)/jar cf liblttng-ust-jul.jar \ - $(LTTNG_JUL_DESTDIR)/*.class - -endif diff --git a/liblttng-ust-jul/lttng_ust_jul.h b/liblttng-ust-jul/lttng_ust_jul.h deleted file mode 100644 index a45af396..00000000 --- a/liblttng-ust-jul/lttng_ust_jul.h +++ /dev/null @@ -1,81 +0,0 @@ -#undef TRACEPOINT_PROVIDER -#define TRACEPOINT_PROVIDER lttng_jul - -#if !defined(_TRACEPOINT_LTTNG_UST_JUL_H) || defined(TRACEPOINT_HEADER_MULTI_READ) -#define _TRACEPOINT_LTTNG_UST_JUL_H - -/* - * Copyright (C) 2011 Mathieu Desnoyers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; version 2.1 of - * the License. - * - * 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 - */ - -#include - -/* - * Privileged tracepoint meaning that this is only enable and fired by the root - * session daemon. - */ -TRACEPOINT_EVENT(lttng_jul, sys_event, - TP_ARGS( - const char *, msg, - const char *, logger_name, - const char *, class_name, - const char *, method_name, - long, millis, - int, log_level, - int, thread_id), - TP_FIELDS( - ctf_string(msg, msg) - ctf_string(logger_name, logger_name) - ctf_string(class_name, class_name) - ctf_string(method_name, method_name) - ctf_integer(long, long_millis, millis) - ctf_integer(int, int_loglevel, log_level) - ctf_integer(int, int_threadid, thread_id) - ) -) - -/* - * User tracepoint meaning that this is only enable and fired by a non root - * session daemon. - */ -TRACEPOINT_EVENT(lttng_jul, user_event, - TP_ARGS( - const char *, msg, - const char *, logger_name, - const char *, class_name, - const char *, method_name, - long, millis, - int, log_level, - int, thread_id), - TP_FIELDS( - ctf_string(msg, msg) - ctf_string(logger_name, logger_name) - ctf_string(class_name, class_name) - ctf_string(method_name, method_name) - ctf_integer(long, long_millis, millis) - ctf_integer(int, int_loglevel, log_level) - ctf_integer(int, int_threadid, thread_id) - ) -) - -#endif /* _TRACEPOINT_LTTNG_UST_JUL_H */ - -#undef TRACEPOINT_INCLUDE -#define TRACEPOINT_INCLUDE "./lttng_ust_jul.h" - -/* This part must be outside protection */ -#include diff --git a/liblttng-ust-jul/org/lttng/ust/jul/LTTngAgent.java b/liblttng-ust-jul/org/lttng/ust/jul/LTTngAgent.java index 6717cd1e..7c8e98e4 100644 --- a/liblttng-ust-jul/org/lttng/ust/jul/LTTngAgent.java +++ b/liblttng-ust-jul/org/lttng/ust/jul/LTTngAgent.java @@ -31,7 +31,6 @@ import java.util.logging.LogManager; import java.util.Enumeration; public class LTTngAgent { - private static LogManager logManager; /* Possible that we have to threads handling two sessiond. */ private static LTTngLogHandler lttngHandlerRoot; @@ -62,45 +61,12 @@ public class LTTngAgent { */ private LTTngAgent() throws IOException { this.logManager = LogManager.getLogManager(); - this.lttngHandlerUser = new LTTngLogHandler(this.logManager); - this.lttngHandlerRoot = new LTTngLogHandler(this.logManager); + this.lttngHandlerUser = new LTTngLogHandler(); + this.lttngHandlerRoot = new LTTngLogHandler(); this.lttngHandlerRoot.is_root = 1; this.registerSem = new Semaphore(0, true); } - private void removeHandlers() throws SecurityException, IOException { - String loggerName; - Logger logger; - - Enumeration list = this.logManager.getLoggerNames(); - while (list.hasMoreElements()) { - loggerName = list.nextElement().toString(); - /* Somehow there is always an empty string at the end. */ - if (loggerName == "") { - continue; - } - - logger = this.logManager.getLogger(loggerName); - logger.removeHandler(this.lttngHandlerUser); - logger.removeHandler(this.lttngHandlerRoot); - } - } - - private int getUID() throws IOException { - int uid; - byte b[] = new byte[4]; - String userName = System.getProperty("user.name"); - String command = "id -u " + userName; - Process child = Runtime.getRuntime().exec(command); - InputStream in = child.getInputStream(); - - in.read(b); - uid = Integer.parseInt(new String(b).trim(), 10); - in.close(); - - return uid; - } - /* * Public getter to acquire a reference to this singleton object. */ @@ -154,19 +120,17 @@ public class LTTngAgent { } public void dispose() throws IOException { - this.lttngThreadUser.dispose(); - if (this.lttngThreadRoot != null) { - this.lttngThreadRoot.dispose(); - } + this.lttngJULThreadUser.dispose(); + this.lttngJULThreadRoot.dispose(); - /* Make sure there is no more LTTng handler attach to logger(s). */ - this.removeHandlers(); + /* Remove handlers from the root logger */ + Logger rootLogger = LogManager.getLogManager().getLogger(""); + rootLogger.removeHandler(this.lttngHandlerUser); + rootLogger.removeHandler(this.lttngHandlerRoot); try { this.sessiondThUser.join(); - if (this.sessiondThRoot != null) { - this.sessiondThRoot.join(); - } + this.sessiondThRoot.join(); } catch (InterruptedException e) { e.printStackTrace(); } diff --git a/liblttng-ust-jul/org/lttng/ust/jul/LTTngEvent.java b/liblttng-ust-jul/org/lttng/ust/jul/LTTngEvent.java deleted file mode 100644 index 4eacb361..00000000 --- a/liblttng-ust-jul/org/lttng/ust/jul/LTTngEvent.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2014 - 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.jul; - -import java.lang.String; - -import org.lttng.ust.jul.LTTngUst; - -class LTTngLogLevel { - /* This level is a JUL int level value. */ - public int level; - public int type; - - public LTTngLogLevel(int level, int type) { - this.type = type; - this.level = level; - } -} - -public class LTTngEvent { - /* Name of the event. */ - public String name; - public LTTngLogLevel logLevel; - - public LTTngEvent(String name, int loglevel, int loglevel_type) { - this.name = name; - this.logLevel = new LTTngLogLevel(loglevel, loglevel_type); - } -} diff --git a/liblttng-ust-jul/org/lttng/ust/jul/LTTngLogHandler.java b/liblttng-ust-jul/org/lttng/ust/jul/LTTngLogHandler.java index 4c617fb9..008b105b 100644 --- a/liblttng-ust-jul/org/lttng/ust/jul/LTTngLogHandler.java +++ b/liblttng-ust-jul/org/lttng/ust/jul/LTTngLogHandler.java @@ -34,18 +34,13 @@ public class LTTngLogHandler extends Handler { public int is_root = 0; public int refcount = 0; - public LogManager logManager; - /* Logger object attached to this handler that can trigger a tracepoint. */ public Map enabledEvents = Collections.synchronizedMap(new HashMap()); /* Constructor */ - public LTTngLogHandler(LogManager logManager) { + public LTTngLogHandler() { super(); - - this.logManager = logManager; - /* Initialize LTTng UST tracer. */ LTTngUst.init(); } diff --git a/liblttng-ust-jul/org/lttng/ust/jul/LTTngSessiondCmd2_4.java b/liblttng-ust-jul/org/lttng/ust/jul/LTTngSessiondCmd2_4.java deleted file mode 100644 index 1a65f131..00000000 --- a/liblttng-ust-jul/org/lttng/ust/jul/LTTngSessiondCmd2_4.java +++ /dev/null @@ -1,300 +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.jul; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.lang.Object; -import java.util.logging.Logger; -import java.util.ArrayList; -import java.util.List; -import java.util.Enumeration; - -public interface LTTngSessiondCmd2_4 { - /** - * Maximum name length for a logger name to be send to sessiond. - */ - final static 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... - */ - final static int INT_SIZE = 4; - - public 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(); - } - - public interface SessiondCommand { - /** - * Populate the class from a byte array - * - * @param data - * the byte array containing the streamed command - */ - public void populate(byte[] data); - } - - public enum lttng_jul_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_jul_command(int c) { - code = c; - } - - public int getCommand() { - return code; - } - } - - enum lttng_jul_ret_code { - CODE_SUCCESS_CMD(1), - CODE_INVALID_CMD(2), - CODE_UNK_LOGGER_NAME(3); - private int code; - - private lttng_jul_ret_code(int c) { - code = c; - } - - public int getCode() { - return code; - } - } - - public 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 data_size; - /** Command type. */ - public lttng_jul_command cmd; - /** Command version. */ - public int cmd_version; - - public void populate(byte[] data) { - ByteBuffer buf = ByteBuffer.wrap(data); - buf.order(ByteOrder.BIG_ENDIAN); - - data_size = buf.getLong(); - cmd = lttng_jul_command.values()[buf.getInt() - 1]; - cmd_version = buf.getInt(); - } - } - - public class sessiond_enable_handler implements SessiondResponse, SessiondCommand { - private final static int SIZE = 4; - public String name; - public int lttngLogLevel; - public int lttngLogLevelType; - - /** Return status code to the session daemon. */ - public lttng_jul_ret_code code; - - @Override - public void populate(byte[] data) { - int data_offset = INT_SIZE * 2; - - ByteBuffer buf = ByteBuffer.wrap(data); - buf.order(ByteOrder.LITTLE_ENDIAN); - lttngLogLevel = buf.getInt(); - lttngLogLevelType = buf.getInt(); - name = new String(data, data_offset, data.length - data_offset).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. - * - * @return Event name as a string if the event is NOT found thus was - * not enabled. - */ - public void execute(LTTngLogHandler handler) { - LTTngEvent event; - - if (this.name == null) { - this.code = lttng_jul_ret_code.CODE_INVALID_CMD; - return; - } - - /* Add event to the enabled events hash map. */ - event = handler.enabledEvents.put(this.name, - new LTTngEvent(this.name, 0, 0)); - if (event != null) { - /* The event exists so skip updating the refcount. */ - this.code = lttng_jul_ret_code.CODE_SUCCESS_CMD; - return; - } - - /* - * Get the root logger and attach to it if it's the first enable - * seen by the handler. - */ - Logger rootLogger = handler.logManager.getLogger(""); - - handler.refcount++; - if (handler.refcount == 1) { - /* Add handler only if it's the first enable. */ - rootLogger.addHandler(handler); - } - - this.code = lttng_jul_ret_code.CODE_SUCCESS_CMD; - return; - } - } - - public class sessiond_disable_handler implements SessiondResponse, SessiondCommand { - private final static int SIZE = 4; - public String name; - public int lttngLogLevel; - public int lttngLogLevelType; - - /** Return status code to the session daemon. */ - public lttng_jul_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(LTTngLogHandler handler) { - LTTngEvent event; - - if (this.name == null) { - this.code = lttng_jul_ret_code.CODE_INVALID_CMD; - return; - } - - /* - * Try to remove the logger name from the events map and if we - * can't, just skip the refcount update since the event was never - * enabled. - */ - event = handler.enabledEvents.remove(this.name); - if (event == null) { - /* The event didn't exists so skip updating the refcount. */ - this.code = lttng_jul_ret_code.CODE_INVALID_CMD; - return; - } - - Logger rootLogger = handler.logManager.getLogger(""); - - handler.refcount--; - if (handler.refcount == 0) { - rootLogger.removeHandler(handler); - } - - this.code = lttng_jul_ret_code.CODE_SUCCESS_CMD; - return; - } - } - - public class sessiond_list_logger implements SessiondResponse { - private final static int SIZE = 12; - - private int data_size = 0; - private int nb_logger = 0; - - List logger_list = new ArrayList(); - - /** Return status code to the session daemon. */ - public lttng_jul_ret_code code; - - @Override - public byte[] getBytes() { - byte data[] = new byte[SIZE + data_size]; - ByteBuffer buf = ByteBuffer.wrap(data); - buf.order(ByteOrder.BIG_ENDIAN); - - /* Returned code */ - buf.putInt(code.getCode()); - buf.putInt(data_size); - buf.putInt(nb_logger); - - for (String logger: logger_list) { - buf.put(logger.getBytes()); - /* NULL terminated byte after the logger name. */ - buf.put((byte) 0x0); - } - return data; - } - - /** - * Execute enable handler action which is to enable the given handler - * to the received name. - */ - public void execute(LTTngLogHandler handler) { - String loggerName; - - Enumeration loggers = handler.logManager.getLoggerNames(); - while (loggers.hasMoreElements()) { - loggerName = loggers.nextElement().toString(); - /* Somehow there is always an empty string at the end. */ - if (loggerName == "") { - continue; - } - - this.logger_list.add(loggerName); - this.nb_logger++; - this.data_size += loggerName.length() + 1; - } - - this.code = lttng_jul_ret_code.CODE_SUCCESS_CMD; - } - } -} diff --git a/liblttng-ust-jul/org/lttng/ust/jul/LTTngTCPSessiondClient.java b/liblttng-ust-jul/org/lttng/ust/jul/LTTngTCPSessiondClient.java deleted file mode 100644 index cf3074b0..00000000 --- a/liblttng-ust-jul/org/lttng/ust/jul/LTTngTCPSessiondClient.java +++ /dev/null @@ -1,328 +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.jul; - -import java.util.concurrent.Semaphore; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.lang.Integer; -import java.io.IOException; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.DataInputStream; -import java.io.FileReader; -import java.io.FileNotFoundException; -import java.net.*; -import java.lang.management.ManagementFactory; -import java.util.logging.Logger; - -class USTRegisterMsg { - public static int pid; -} - -public class LTTngTCPSessiondClient { - /* Command header from the session deamon. */ - private LTTngSessiondCmd2_4.sessiond_hdr headerCmd = - new LTTngSessiondCmd2_4.sessiond_hdr(); - - private final String sessiondHost; - private Socket sessiondSock; - private boolean quit = false; - - private DataInputStream inFromSessiond; - private DataOutputStream outToSessiond; - - private LTTngLogHandler handler; - - private Semaphore registerSem; - - private static final String rootPortFile = "/var/run/lttng/agent.port"; - private static final String userPortFile = "/.lttng/agent.port"; - /* - * This is taken from the lttng/domain.h file which is mapped to - * LTTNG_DOMAIN_JUL value for this agent. - */ - private static final int agent_domain = 3; - - /* Indicate if we've already release the semaphore. */ - private boolean sem_posted = false; - - public LTTngTCPSessiondClient(String host, Semaphore sem) { - this.sessiondHost = host; - 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.sem_posted) { - this.registerSem.release(); - this.sem_posted = true; - } - } - - /* - * Cleanup Agent state. - */ - private void cleanupState() { - if (this.handler != null) { - this.handler.clear(); - } - } - - public void init(LTTngLogHandler handler) throws InterruptedException { - this.handler = handler; - - for (;;) { - if (this.quit) { - break; - } - - /* Cleanup Agent state before trying to connect or reconnect. */ - cleanupState(); - - 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(); - Thread.sleep(3000); - } 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 { - int read_len; - byte data[] = new byte[this.headerCmd.SIZE]; - - read_len = this.inFromSessiond.read(data, 0, data.length); - if (read_len != 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.data_size]; - - /* 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 { - int ret_code; - byte data[] = null; - - while (true) { - /* Get header from session daemon. */ - recvHeader(); - - if (headerCmd.data_size > 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_4.sessiond_list_logger listLoggerCmd = - new LTTngSessiondCmd2_4.sessiond_list_logger(); - listLoggerCmd.execute(this.handler); - data = listLoggerCmd.getBytes(); - break; - } - case CMD_ENABLE: - { - LTTngEvent event; - LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd = - new LTTngSessiondCmd2_4.sessiond_enable_handler(); - if (data == null) { - enableCmd.code = LTTngSessiondCmd2_4.lttng_jul_ret_code.CODE_INVALID_CMD; - break; - } - enableCmd.populate(data); - enableCmd.execute(this.handler); - data = enableCmd.getBytes(); - break; - } - case CMD_DISABLE: - { - LTTngSessiondCmd2_4.sessiond_disable_handler disableCmd = - new LTTngSessiondCmd2_4.sessiond_disable_handler(); - if (data == null) { - disableCmd.code = LTTngSessiondCmd2_4.lttng_jul_ret_code.CODE_INVALID_CMD; - break; - } - disableCmd.populate(data); - disableCmd.execute(this.handler); - data = disableCmd.getBytes(); - break; - } - default: - { - data = new byte[4]; - ByteBuffer buf = ByteBuffer.wrap(data); - buf.order(ByteOrder.BIG_ENDIAN); - LTTngSessiondCmd2_4.lttng_jul_ret_code code = - LTTngSessiondCmd2_4.lttng_jul_ret_code.CODE_INVALID_CMD; - buf.putInt(code.getCode()); - break; - } - } - - /* Send payload to session daemon. */ - this.outToSessiond.write(data, 0, data.length); - this.outToSessiond.flush(); - } - } - - private 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 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.handler.is_root == 1) { - port = getPortFromFile(rootPortFile); - if (port == 0) { - /* No session daemon available. Stop and retry later. */ - throw new IOException(); - } - } else { - port = getPortFromFile(getHomePath() + userPortFile); - if (port == 0) { - /* No session daemon available. Stop and retry later. */ - throw new IOException(); - } - } - - this.sessiondSock = new Socket(this.sessiondHost, port); - this.inFromSessiond = new DataInputStream( - sessiondSock.getInputStream()); - this.outToSessiond = new DataOutputStream( - sessiondSock.getOutputStream()); - } - - private void registerToSessiond() throws Exception { - byte data[] = new byte[8]; - ByteBuffer buf = ByteBuffer.wrap(data); - String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0]; - - buf.putInt(this.agent_domain); - buf.putInt(Integer.parseInt(pid)); - this.outToSessiond.write(data, 0, data.length); - this.outToSessiond.flush(); - } -} diff --git a/liblttng-ust-jul/org/lttng/ust/jul/LTTngThread.java b/liblttng-ust-jul/org/lttng/ust/jul/LTTngThread.java deleted file mode 100644 index b3aa0e6e..00000000 --- a/liblttng-ust-jul/org/lttng/ust/jul/LTTngThread.java +++ /dev/null @@ -1,44 +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.jul; - -import java.util.concurrent.Semaphore; - -public class LTTngThread implements Runnable { - private LTTngLogHandler handler; - private LTTngTCPSessiondClient sessiondClient; - - public LTTngThread(String host, LTTngLogHandler handler, - Semaphore registerSem) { - this.handler = handler; - this.sessiondClient = new LTTngTCPSessiondClient(host, registerSem); - } - - @Override - public void run() { - try { - this.sessiondClient.init(this.handler); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void dispose() { - this.sessiondClient.destroy(); - } -} diff --git a/liblttng-ust-jul/org/lttng/ust/jul/LTTngUst.java b/liblttng-ust-jul/org/lttng/ust/jul/LTTngUst.java deleted file mode 100644 index 10f2a8ca..00000000 --- a/liblttng-ust-jul/org/lttng/ust/jul/LTTngUst.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (C) 2011-2012 Mathieu Desnoyers - * Copyright (C) 2012 Alexandre Montplaisir - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; only - * version 2.1 of the License. - * - * 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.jul; - -/** - * This class implements the the Java side of the LTTng-UST Java interface. - * - * First, make sure you have installed "liblttng-ust-java.so" where the linker - * can find it. You can then call LTTngUst.init() from your Java program to - * connect the methods exposed here to the native library. - * - * Because of limitations in the probe declaration, all trace events generated - * by this library will have "lttng_ust_java" for domain, and "_event" for - * event name in the CTF trace files. The "name" parameter will instead appear - * as the first element of the event's payload. - * - * @author Mathieu Desnoyers - * @author Alexandre Montplaisir - * @author David Goulet - * - */ -public abstract class LTTngUst { - /** - * Initialize the UST tracer. This should always be called first, before any - * tracepoint* method. - */ - public static void init() { - System.loadLibrary("lttng-ust-jul-jni"); //$NON-NLS-1$ - } - - /** - * Insert a tracepoint for JUL event. - * - * @param msg - * Raw message provided by the JUL API. - * @param logger_name - * Logger name that trigger this event. - * @param class_name - * Name of the class that (allegedly) issued the logging request. - * @param method_name - * Name of the method that (allegedly) issued the logging request. - * @param millis - * Event time in milliseconds since 1970. - * @param log_level - * Log level of the event from JUL. - * @param thread_id - * Identifier for the thread where the message originated. - */ - - /* Use for a user session daemon. */ - public static 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. */ - public static 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/tests/Makefile.am b/tests/Makefile.am index b5166f98..30b0e9a0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,10 +4,6 @@ if CXX_WORKS SUBDIRS += hello.cxx endif -if BUILD_JNI_INTERFACE -SUBDIRS += java-jul -endif - SCRIPT_LIST = test_loop run.sh unit_tests dist_noinst_SCRIPTS = $(SCRIPT_LIST) diff --git a/tests/java-jul/JULTest.java b/tests/java-jul/JULTest.java index 1e002277..bc8f65a0 100644 --- a/tests/java-jul/JULTest.java +++ b/tests/java-jul/JULTest.java @@ -38,10 +38,6 @@ public class JULTest { } public static void go() throws IOException { - handler = new LTTngLogHandler(LogManager.getLogManager()); - assert handler.logManager == LogManager.getLogManager(); - ok("Log handler logManager is valid"); - client = new LTTngTCPSessiondClient("127.0.0.1", sem); assert client != null; ok("TCP client is valid"); diff --git a/tests/java-jul/Makefile.am b/tests/java-jul/Makefile.am deleted file mode 100644 index ba50fbf1..00000000 --- a/tests/java-jul/Makefile.am +++ /dev/null @@ -1,25 +0,0 @@ -EXTRA_DIST = test_jul JULTest.java - -if BUILD_JNI_INTERFACE - -if HAVE_JAVA_JDK -JCC=$(JAVA_JDK)/bin/javac -else -JCC=javac -endif - -AM_CPPFLAGS = -I$(top_srcdir)/include - -JUL_jar_file = "$(builddir)/../../liblttng-ust-jul/liblttng-ust-jul.jar" - -default: all - -all: JULTest.class - -clean-local: - rm -f *.class - -JULTest.class: JULTest.java - $(JCC) -cp $(JUL_jar_file) -d "$(builddir)" "$(srcdir)/JULTest.java" - -endif diff --git a/tests/java-jul/test_jul b/tests/java-jul/test_jul deleted file mode 100755 index 192dfdac..00000000 --- a/tests/java-jul/test_jul +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -CURDIR=$(dirname $0)/ -TESTDIR=$CURDIR/.. -TESTCLASS="JULTest" - -if [ ! -f "$CURDIR/$TESTCLASS.class" ]; then - echo "1..0 # Skipped: Java support not build" - exit 0 -fi - -java -ea -cp "$CURDIR:$TESTDIR/../liblttng-ust-jul/liblttng-ust-jul.jar" -Djava.library.path="$TESTDIR/../liblttng-ust-jul/.libs" $TESTCLASS diff --git a/tests/unit_tests b/tests/unit_tests index 2520c0d8..91101383 100644 --- a/tests/unit_tests +++ b/tests/unit_tests @@ -1,2 +1 @@ snprintf/test_snprintf -java-jul/test_jul