From: Michael Jeanson Date: Fri, 9 Apr 2021 18:30:00 +0000 (-0400) Subject: Move liblttng-ust-java* to 'src/lib/' X-Git-Tag: v2.13.0-rc1~135 X-Git-Url: https://git.lttng.org/?a=commitdiff_plain;h=3081c83f06d9a65cae1507a5db358df84ed7c192;p=lttng-ust.git Move liblttng-ust-java* to 'src/lib/' Move all public libraries under 'src/lib/'. This is part of an effort to standardize our autotools setup across projects to simplify maintenance. Change-Id: I98ed0e9da28c111e62b189f26b0a225b5aa500e1 Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- diff --git a/.gitignore b/.gitignore index 88f36282..0ad9442d 100644 --- a/.gitignore +++ b/.gitignore @@ -93,21 +93,21 @@ cscope.* /tests/unit/ust-utils/test_ust_utils_cxx # Java agent library -/src/liblttng-ust-java-agent/java/lttng-ust-agent-all/*.jar -/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/classnoinst.stamp -/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/context-jni-header.stamp -/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/*.jar -/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/classnoinst.stamp -/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/jul-jni-header.stamp -/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/*.jar -/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/classnoinst.stamp -/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/log4j-jni-header.stamp -/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/*.jar -/src/liblttng-ust-java-agent/jni/common/org_lttng_ust_agent_context_LttngContextApi.h -/src/liblttng-ust-java-agent/jni/jul/org_lttng_ust_agent_jul_LttngJulApi.h -/src/liblttng-ust-java-agent/jni/log4j/org_lttng_ust_agent_log4j_LttngLog4jApi.h -/src/liblttng-ust-java/classnoinst.stamp -/src/liblttng-ust-java/jni-header.stamp +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-all/*.jar +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/classnoinst.stamp +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/context-jni-header.stamp +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/*.jar +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/classnoinst.stamp +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/jul-jni-header.stamp +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/*.jar +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/classnoinst.stamp +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/log4j-jni-header.stamp +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/*.jar +/src/lib/lttng-ust-java-agent/jni/common/org_lttng_ust_agent_context_LttngContextApi.h +/src/lib/lttng-ust-java-agent/jni/jul/org_lttng_ust_agent_jul_LttngJulApi.h +/src/lib/lttng-ust-java-agent/jni/log4j/org_lttng_ust_agent_log4j_LttngLog4jApi.h +/src/lib/lttng-ust-java/classnoinst.stamp +/src/lib/lttng-ust-java/jni-header.stamp # Python agent /src/python-lttngust/lttngust/version.py @@ -132,17 +132,17 @@ cscope.* /src/lib/lttng-ust-dl/Makefile /src/lib/lttng-ust-fd/Makefile /src/lib/lttng-ust-fork/Makefile -/src/liblttng-ust-java-agent/Makefile -/src/liblttng-ust-java-agent/java/Makefile -/src/liblttng-ust-java-agent/java/lttng-ust-agent-all/Makefile -/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile -/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile -/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile -/src/liblttng-ust-java-agent/jni/Makefile -/src/liblttng-ust-java-agent/jni/common/Makefile -/src/liblttng-ust-java-agent/jni/jul/Makefile -/src/liblttng-ust-java-agent/jni/log4j/Makefile -/src/liblttng-ust-java/Makefile +/src/lib/lttng-ust-java-agent/Makefile +/src/lib/lttng-ust-java-agent/java/Makefile +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-all/Makefile +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/Makefile +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile +/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile +/src/lib/lttng-ust-java-agent/jni/Makefile +/src/lib/lttng-ust-java-agent/jni/common/Makefile +/src/lib/lttng-ust-java-agent/jni/jul/Makefile +/src/lib/lttng-ust-java-agent/jni/log4j/Makefile +/src/lib/lttng-ust-java/Makefile /src/lib/lttng-ust-libc-wrapper/Makefile /src/lib/lttng-ust-python-agent/Makefile /src/lib/Makefile diff --git a/configure.ac b/configure.ac index 8b6fb562..d705ecb6 100644 --- a/configure.ac +++ b/configure.ac @@ -526,17 +526,17 @@ AC_CONFIG_FILES([ src/lib/lttng-ust-dl/Makefile src/lib/lttng-ust-fd/Makefile src/lib/lttng-ust-fork/Makefile - src/liblttng-ust-java-agent/java/lttng-ust-agent-all/Makefile - src/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile - src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile - src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile - src/liblttng-ust-java-agent/java/Makefile - src/liblttng-ust-java-agent/jni/common/Makefile - src/liblttng-ust-java-agent/jni/jul/Makefile - src/liblttng-ust-java-agent/jni/log4j/Makefile - src/liblttng-ust-java-agent/jni/Makefile - src/liblttng-ust-java-agent/Makefile - src/liblttng-ust-java/Makefile + src/lib/lttng-ust-java-agent/java/lttng-ust-agent-all/Makefile + src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/Makefile + src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile + src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile + src/lib/lttng-ust-java-agent/java/Makefile + src/lib/lttng-ust-java-agent/jni/common/Makefile + src/lib/lttng-ust-java-agent/jni/jul/Makefile + src/lib/lttng-ust-java-agent/jni/log4j/Makefile + src/lib/lttng-ust-java-agent/jni/Makefile + src/lib/lttng-ust-java-agent/Makefile + src/lib/lttng-ust-java/Makefile src/lib/lttng-ust-libc-wrapper/Makefile src/liblttng-ust/Makefile src/lib/lttng-ust-python-agent/Makefile diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am index 06e40662..ce517922 100644 --- a/doc/examples/Makefile.am +++ b/doc/examples/Makefile.am @@ -155,8 +155,8 @@ all-local: cd $$subdir && \ $(MAKE) all \ CLASSPATH="$(CLASSPATH)" \ - JAVA_CLASSPATH_OVERRIDE_JUL="../../../src/liblttng-ust-java-agent/java/lttng-ust-agent-jul" \ - JAVA_CLASSPATH_OVERRIDE_COMMON="../../../src/liblttng-ust-java-agent/java/lttng-ust-agent-common" \ + JAVA_CLASSPATH_OVERRIDE_JUL="../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul" \ + JAVA_CLASSPATH_OVERRIDE_COMMON="../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common" \ $(AM_MAKEFLAGS) \ ) || exit 1; \ done; \ @@ -167,8 +167,8 @@ all-local: cd $$subdir && \ $(MAKE) all \ CLASSPATH="$(CLASSPATH)" \ - JAVA_CLASSPATH_OVERRIDE_LOG4J="../../../src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j" \ - JAVA_CLASSPATH_OVERRIDE_COMMON="../../../src/liblttng-ust-java-agent/java/lttng-ust-agent-common" \ + JAVA_CLASSPATH_OVERRIDE_LOG4J="../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j" \ + JAVA_CLASSPATH_OVERRIDE_COMMON="../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common" \ $(AM_MAKEFLAGS) \ ) || exit 1; \ done; \ diff --git a/doc/examples/java-jul/run b/doc/examples/java-jul/run index 03a5fd6f..911b04ca 100755 --- a/doc/examples/java-jul/run +++ b/doc/examples/java-jul/run @@ -15,9 +15,9 @@ JAVA_OPTIONS="" cd $DIR if [ -f "$DIR/.intree" ]; then - CLASSPATH="../../../liblttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON" - CLASSPATH="$CLASSPATH:../../../liblttng-ust-java-agent/java/lttng-ust-agent-jul/$JARFILE_JUL" - LIBPATH="../../../liblttng-ust-java-agent/jni/jul/.libs" + CLASSPATH="../../../lib/lttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON" + CLASSPATH="$CLASSPATH:../../../lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/$JARFILE_JUL" + LIBPATH="../../../lib/lttng-ust-java-agent/jni/jul/.libs" else CLASSPATH="/usr/local/share/java/$JARFILE_COMMON:/usr/share/java/$JARFILE_COMMON" CLASSPATH="$CLASSPATH:/usr/local/share/java/$JARFILE_JUL:/usr/share/java/$JARFILE_JUL" diff --git a/doc/examples/java-log4j/run b/doc/examples/java-log4j/run index 056ea67f..d6e5afa4 100755 --- a/doc/examples/java-log4j/run +++ b/doc/examples/java-log4j/run @@ -21,9 +21,9 @@ fi cd $DIR if [ -f "$DIR/.intree" ]; then - CLASSPATH="$CLASSPATH:../../../liblttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON" - CLASSPATH="$CLASSPATH:../../../liblttng-ust-java-agent/java/lttng-ust-agent-log4j/$JARFILE_LOG4J" - LIBPATH="../../../liblttng-ust-java-agent/jni/log4j/.libs" + CLASSPATH="$CLASSPATH:../../../lib/lttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON" + CLASSPATH="$CLASSPATH:../../../lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/$JARFILE_LOG4J" + LIBPATH="../../../lib/lttng-ust-java-agent/jni/log4j/.libs" else CLASSPATH="$CLASSPATH:/usr/local/share/java/$JARFILE_COMMON:/usr/share/java/$JARFILE_COMMON" CLASSPATH="$CLASSPATH:/usr/local/share/java/$JARFILE_LOG4J:/usr/share/java/$JARFILE_LOG4J" diff --git a/src/Makefile.am b/src/Makefile.am index f51694ec..7facaf2b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,14 +9,6 @@ SUBDIRS = \ liblttng-ust-ctl \ lib -if ENABLE_JNI_INTERFACE -SUBDIRS += liblttng-ust-java -endif - -if ENABLE_JAVA_AGENT -SUBDIRS += liblttng-ust-java-agent -endif - if ENABLE_PYTHON_AGENT SUBDIRS += python-lttngust endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 0b33906e..ec0b4538 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -10,6 +10,14 @@ if ENABLE_UST_DL SUBDIRS += lttng-ust-dl endif +if ENABLE_JNI_INTERFACE +SUBDIRS += lttng-ust-java +endif + +if ENABLE_JAVA_AGENT +SUBDIRS += lttng-ust-java-agent +endif + if ENABLE_PYTHON_AGENT SUBDIRS += lttng-ust-python-agent endif diff --git a/src/lib/lttng-ust-java-agent/Makefile.am b/src/lib/lttng-ust-java-agent/Makefile.am new file mode 100644 index 00000000..ad47256d --- /dev/null +++ b/src/lib/lttng-ust-java-agent/Makefile.am @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: LGPL-2.1-only + +SUBDIRS = java jni diff --git a/src/lib/lttng-ust-java-agent/java/Makefile.am b/src/lib/lttng-ust-java-agent/java/Makefile.am new file mode 100644 index 00000000..96d575aa --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/Makefile.am @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: LGPL-2.1-only + +SUBDIRS = lttng-ust-agent-common lttng-ust-agent-all + +if ENABLE_JAVA_AGENT_WITH_JUL +SUBDIRS += lttng-ust-agent-jul +endif + +if ENABLE_JAVA_AGENT_WITH_LOG4J +SUBDIRS += lttng-ust-agent-log4j +endif diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-all/Makefile.am b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-all/Makefile.am new file mode 100644 index 00000000..b6cf9aad --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-all/Makefile.am @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: LGPL-2.1-only + +JAVAROOT = . + +jarfile_version = 1.0.0 +jarfile_manifest = $(srcdir)/Manifest.txt +jarfile_symlink = lttng-ust-agent-all.jar +jarfile = lttng-ust-agent-all-$(jarfile_version).jar + +# Compatibility symlink provided for applications expecting the agent +# jar file installed by UST 2.7. +jarfile_compat_symlink = liblttng-ust-agent.jar + +jardir = $(datadir)/java + +dist_noinst_DATA = $(jarfile_manifest) + +jar_DATA = $(jarfile) + +$(jarfile): + $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) \ + && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink) \ + && rm -f $(jarfile_compat_symlink) && $(LN_S) $(jarfile_symlink) $(jarfile_compat_symlink) + +install-data-hook: + cd $(DESTDIR)/$(jardir) \ + && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink) \ + && rm -f $(jarfile_compat_symlink) && $(LN_S) $(jarfile_symlink) $(jarfile_compat_symlink) + +uninstall-hook: + cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && rm -f $(jarfile_compat_symlink) + +CLEANFILES = *.jar diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-all/Manifest.txt b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-all/Manifest.txt new file mode 100644 index 00000000..e09c85ec --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-all/Manifest.txt @@ -0,0 +1,8 @@ +Name: org/lttng/ust/agent/all/ +Specification-Title: LTTng UST All Java Agents +Specification-Version: 1.0.0 +Specification-Vendor: LTTng Project +Implementation-Title: org.lttng.ust.agent.all +Implementation-Version: 1.0.0 +Implementation-Vendor: LTTng Project +Class-Path: lttng-ust-agent-common.jar lttng-ust-agent-jul.jar lttng-ust-agent-log4j.jar diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am new file mode 100644 index 00000000..473e8729 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: LGPL-2.1-only + +JAVAROOT = . + +pkgpath = org/lttng/ust/agent + +jarfile_version = 1.0.0 +jarfile_manifest = $(srcdir)/Manifest.txt +jarfile_symlink = lttng-ust-agent-common.jar +jarfile = lttng-ust-agent-common-$(jarfile_version).jar + +jardir = $(datadir)/java +jnioutdir = ../../jni/common + +dist_noinst_JAVA = $(pkgpath)/AbstractLttngAgent.java \ + $(pkgpath)/EventNamePattern.java \ + $(pkgpath)/ILttngAgent.java \ + $(pkgpath)/ILttngHandler.java \ + $(pkgpath)/LTTngAgent.java \ + $(pkgpath)/client/ILttngTcpClientListener.java \ + $(pkgpath)/client/SessiondCommand.java \ + $(pkgpath)/client/LttngAgentResponse.java \ + $(pkgpath)/client/LttngTcpSessiondClient.java \ + $(pkgpath)/client/SessiondCommandHeader.java \ + $(pkgpath)/client/SessiondDisableAppContextCommand.java \ + $(pkgpath)/client/SessiondDisableEventCommand.java \ + $(pkgpath)/client/SessiondEnableAppContextCommand.java \ + $(pkgpath)/client/SessiondEnableEventCommand.java \ + $(pkgpath)/client/SessiondListLoggersCommand.java \ + $(pkgpath)/context/LttngContextApi.java \ + $(pkgpath)/context/ContextInfoManager.java \ + $(pkgpath)/context/ContextInfoSerializer.java \ + $(pkgpath)/context/IContextInfoRetriever.java \ + $(pkgpath)/filter/FilterChangeNotifier.java \ + $(pkgpath)/filter/IFilterChangeListener.java \ + $(pkgpath)/session/EventRule.java \ + $(pkgpath)/session/LogLevelSelector.java \ + $(pkgpath)/utils/LttngUstAgentLogger.java + + +dist_noinst_DATA = $(jarfile_manifest) + +jar_DATA = $(jarfile) + +classes = $(pkgpath)/*.class \ + $(pkgpath)/client/*.class \ + $(pkgpath)/context/*.class \ + $(pkgpath)/filter/*.class \ + $(pkgpath)/session/*.class \ + $(pkgpath)/utils/*.class + +$(jarfile): classnoinst.stamp + $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink) + +if !HAVE_JAVAH +# If we don't have javah, assume we are running openjdk >= 10 and use javac +# to generate the jni header file. +AM_JAVACFLAGS = -h $(jnioutdir) +else +context-jni-header.stamp: $(dist_noinst_JAVA) + $(JAVAH) -classpath $(CLASSPATH):$(srcdir) -d $(jnioutdir) $(JAVAHFLAGS) org.lttng.ust.agent.context.LttngContextApi && \ + echo "Context API JNI header generated" > context-jni-header.stamp + +all-local: context-jni-header.stamp +endif + +install-data-hook: + cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink) + +uninstall-hook: + cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) + +CLEANFILES = *.jar \ + $(pkgpath)/*.class \ + $(pkgpath)/client/*.class \ + $(pkgpath)/context/*.class \ + $(pkgpath)/filter/*.class \ + $(pkgpath)/session/*.class \ + $(pkgpath)/utils/*.class \ + context-jni-header.stamp \ + $(jnioutdir)/org_lttng_ust_agent_context_LttngContextApi.h diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/Manifest.txt b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/Manifest.txt new file mode 100644 index 00000000..d3c7e264 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/Manifest.txt @@ -0,0 +1,7 @@ +Name: org/lttng/ust/agent/ +Specification-Title: LTTng UST Java Agent +Specification-Version: 1.0.0 +Specification-Vendor: LTTng Project +Implementation-Title: org.lttng.ust.agent +Implementation-Version: 1.0.0 +Implementation-Vendor: LTTng Project diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java new file mode 100644 index 00000000..acbdc4f1 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java @@ -0,0 +1,386 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + * Copyright (C) 2013 David Goulet + */ + +package org.lttng.ust.agent; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.regex.Matcher; + +import org.lttng.ust.agent.client.ILttngTcpClientListener; +import org.lttng.ust.agent.client.LttngTcpSessiondClient; +import org.lttng.ust.agent.filter.FilterChangeNotifier; +import org.lttng.ust.agent.session.EventRule; +import org.lttng.ust.agent.utils.LttngUstAgentLogger; + +/** + * Base implementation of a {@link ILttngAgent}. + * + * @author Alexandre Montplaisir + * @param + * The type of logging handler that should register to this agent + */ +public abstract class AbstractLttngAgent + implements ILttngAgent, ILttngTcpClientListener { + + private static final int INIT_TIMEOUT = 3; /* Seconds */ + + /** The handlers registered to this agent */ + private final Set registeredHandlers = new HashSet(); + + /** + * The trace events currently enabled in the sessions. + * + * The key is the {@link EventNamePattern} that comes from the event name. + * The value is the ref count (how many different sessions currently have + * this event enabled). Once the ref count falls to 0, this means we can + * avoid sending log events through JNI because nobody wants them. + * + * Its accesses should be protected by the {@link #enabledEventNamesLock} + * below. + */ + private final Map enabledPatterns = new HashMap(); + + /** + * Cache of already-checked event names. As long as enabled/disabled events + * don't change in the session, we can avoid re-checking events that were + * previously checked against all known enabled patterns. + * + * Its accesses should be protected by the {@link #enabledEventNamesLock} + * below, with the exception of concurrent get operations. + */ + private final Map enabledEventNamesCache = new ConcurrentHashMap(); + + /** + * Lock protecting accesses to the {@link #enabledPatterns} and + * {@link #enabledEventNamesCache} maps. + */ + private final Lock enabledEventNamesLock = new ReentrantLock(); + + /** + * The application contexts currently enabled in the tracing sessions. + * + * It is first indexed by context retriever, then by context name. This + * allows to efficiently query all the contexts for a given retriever. + * + * Works similarly as {@link #enabledEvents}, but for app contexts (and with + * an extra degree of indexing). + * + * TODO Could be changed to a Guava Table once/if we start using it. + */ + private final Map> enabledAppContexts = new ConcurrentHashMap>(); + + /** Tracing domain. Defined by the sub-classes via the constructor. */ + private final Domain domain; + + /* Lazy-loaded sessiond clients and their thread objects */ + private LttngTcpSessiondClient rootSessiondClient = null; + private LttngTcpSessiondClient userSessiondClient = null; + private Thread rootSessiondClientThread = null; + private Thread userSessiondClientThread = null; + + /** Indicates if this agent has been initialized. */ + private boolean initialized = false; + + /** + * Constructor. Should only be called by sub-classes via super(...); + * + * @param domain + * The tracing domain of this agent. + */ + protected AbstractLttngAgent(Domain domain) { + this.domain = domain; + } + + @Override + public Domain getDomain() { + return domain; + } + + @Override + public void registerHandler(T handler) { + synchronized (registeredHandlers) { + if (registeredHandlers.isEmpty()) { + /* + * This is the first handler that registers, we will initialize + * the agent. + */ + init(); + } + registeredHandlers.add(handler); + } + } + + @Override + public void unregisterHandler(T handler) { + synchronized (registeredHandlers) { + registeredHandlers.remove(handler); + if (registeredHandlers.isEmpty()) { + /* There are no more registered handlers, close the connection. */ + dispose(); + } + } + } + + private void init() { + /* + * Only called from a synchronized (registeredHandlers) block, should + * not need additional synchronization. + */ + if (initialized) { + return; + } + + LttngUstAgentLogger.log(AbstractLttngAgent.class, "Initializing Agent for domain: " + domain.name()); + + String rootClientThreadName = "Root sessiond client started by agent: " + this.getClass().getSimpleName(); + + rootSessiondClient = new LttngTcpSessiondClient(this, getDomain().value(), true); + rootSessiondClientThread = new Thread(rootSessiondClient, rootClientThreadName); + rootSessiondClientThread.setDaemon(true); + rootSessiondClientThread.start(); + + String userClientThreadName = "User sessiond client started by agent: " + this.getClass().getSimpleName(); + + userSessiondClient = new LttngTcpSessiondClient(this, getDomain().value(), false); + userSessiondClientThread = new Thread(userSessiondClient, userClientThreadName); + userSessiondClientThread.setDaemon(true); + userSessiondClientThread.start(); + + /* Give the threads' registration a chance to end. */ + if (!rootSessiondClient.waitForConnection(INIT_TIMEOUT)) { + userSessiondClient.waitForConnection(INIT_TIMEOUT); + } + + initialized = true; + } + + /** + * Dispose the agent + */ + private void dispose() { + LttngUstAgentLogger.log(AbstractLttngAgent.class, "Disposing Agent for domain: " + domain.name()); + + /* + * Only called from a synchronized (registeredHandlers) block, should + * not need additional synchronization. + */ + rootSessiondClient.close(); + userSessiondClient.close(); + + try { + rootSessiondClientThread.join(); + userSessiondClientThread.join(); + + } catch (InterruptedException e) { + e.printStackTrace(); + } + rootSessiondClient = null; + rootSessiondClientThread = null; + userSessiondClient = null; + userSessiondClientThread = null; + + /* + * Send filter change notifications for all event rules currently + * active, then clear them. + */ + FilterChangeNotifier fcn = FilterChangeNotifier.getInstance(); + + enabledEventNamesLock.lock(); + try { + for (Map.Entry entry : enabledPatterns.entrySet()) { + String eventName = entry.getKey().getEventName(); + Integer nb = entry.getValue(); + for (int i = 0; i < nb.intValue(); i++) { + fcn.removeEventRules(eventName); + } + } + enabledPatterns.clear(); + enabledEventNamesCache.clear(); + } finally { + enabledEventNamesLock.unlock(); + } + + /* + * Also clear tracked app contexts (no filter notifications sent for + * those currently). + */ + enabledAppContexts.clear(); + + initialized = false; + } + + @Override + public boolean eventEnabled(EventRule eventRule) { + /* Notify the filter change manager of the command */ + FilterChangeNotifier.getInstance().addEventRule(eventRule); + + String eventName = eventRule.getEventName(); + EventNamePattern pattern = new EventNamePattern(eventName); + + enabledEventNamesLock.lock(); + try { + boolean ret = incrementRefCount(pattern, enabledPatterns); + enabledEventNamesCache.clear(); + return ret; + } finally { + enabledEventNamesLock.unlock(); + } + } + + @Override + public boolean eventDisabled(String eventName) { + /* Notify the filter change manager of the command */ + FilterChangeNotifier.getInstance().removeEventRules(eventName); + + EventNamePattern pattern = new EventNamePattern(eventName); + + enabledEventNamesLock.lock(); + try { + boolean ret = decrementRefCount(pattern, enabledPatterns); + enabledEventNamesCache.clear(); + return ret; + } finally { + enabledEventNamesLock.unlock(); + } + } + + @Override + public boolean appContextEnabled(String contextRetrieverName, String contextName) { + synchronized (enabledAppContexts) { + Map retrieverMap = enabledAppContexts.get(contextRetrieverName); + if (retrieverMap == null) { + /* There is no submap for this retriever, let's create one. */ + retrieverMap = new ConcurrentHashMap(); + enabledAppContexts.put(contextRetrieverName, retrieverMap); + } + + return incrementRefCount(contextName, retrieverMap); + } + } + + @Override + public boolean appContextDisabled(String contextRetrieverName, String contextName) { + synchronized (enabledAppContexts) { + Map retrieverMap = enabledAppContexts.get(contextRetrieverName); + if (retrieverMap == null) { + /* There was no submap for this retriever, invalid command? */ + return false; + } + + boolean ret = decrementRefCount(contextName, retrieverMap); + + /* If the submap is now empty we can remove it from the main map. */ + if (retrieverMap.isEmpty()) { + enabledAppContexts.remove(contextRetrieverName); + } + + return ret; + } + } + + /* + * Implementation of this method is domain-specific. + */ + @Override + public abstract Collection listAvailableEvents(); + + @Override + public boolean isEventEnabled(String eventName) { + Boolean cachedEnabled = enabledEventNamesCache.get(eventName); + if (cachedEnabled != null) { + /* We have seen this event previously */ + /* + * Careful! enabled == null could also mean that the null value is + * associated with the key. But we should have never inserted null + * values in the map. + */ + return cachedEnabled.booleanValue(); + } + + /* + * We have not previously checked this event. Run it against all known + * enabled event patterns to determine if it should pass or not. + */ + enabledEventNamesLock.lock(); + try { + boolean enabled = false; + for (EventNamePattern enabledPattern : enabledPatterns.keySet()) { + Matcher matcher = enabledPattern.getPattern().matcher(eventName); + if (matcher.matches()) { + enabled = true; + break; + } + } + + /* Add the result to the cache */ + enabledEventNamesCache.put(eventName, Boolean.valueOf(enabled)); + return enabled; + + } finally { + enabledEventNamesLock.unlock(); + } + } + + @Override + public Collection>> getEnabledAppContexts() { + return enabledAppContexts.entrySet(); + } + + private static boolean incrementRefCount(T key, Map refCountMap) { + synchronized (refCountMap) { + Integer count = refCountMap.get(key); + if (count == null) { + /* This is the first instance of this event being enabled */ + refCountMap.put(key, Integer.valueOf(1)); + return true; + } + if (count.intValue() <= 0) { + /* It should not have been in the map in the first place! */ + throw new IllegalStateException(); + } + /* The event was already enabled, increment its refcount */ + refCountMap.put(key, Integer.valueOf(count.intValue() + 1)); + return true; + } + } + + private static boolean decrementRefCount(T key, Map refCountMap) { + synchronized (refCountMap) { + Integer count = refCountMap.get(key); + if (count == null || count.intValue() <= 0) { + /* + * The sessiond asked us to disable an event that was not + * enabled previously. Command error? + */ + return false; + } + if (count.intValue() == 1) { + /* + * This is the last instance of this event being disabled, + * remove it from the map so that we stop sending it. + */ + refCountMap.remove(key); + return true; + } + /* + * Other sessions are still looking for this event, simply decrement + * its refcount. + */ + refCountMap.put(key, Integer.valueOf(count.intValue() - 1)); + return true; + } + } +} + diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/EventNamePattern.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/EventNamePattern.java new file mode 100644 index 00000000..ada5c95f --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/EventNamePattern.java @@ -0,0 +1,132 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2017 EfficiOS Inc. + * Copyright (C) 2017 Philippe Proulx + */ + +package org.lttng.ust.agent; + +import java.util.regex.Pattern; + +/** + * Class encapsulating an event name from the session daemon, and its + * corresponding {@link Pattern}. This allows referring back to the original + * event name, for example when we receive a disable command. + * + * @author Philippe Proulx + * @author Alexandre Montplaisir + */ +class EventNamePattern { + + private final String originalEventName; + + /* + * Note that two Patterns coming from the exact same String will not be + * equals()! As such, it would be confusing to make the pattern part of this + * class's equals/hashCode + */ + private final transient Pattern pattern; + + public EventNamePattern(String eventName) { + if (eventName == null) { + throw new IllegalArgumentException(); + } + + originalEventName = eventName; + pattern = patternFromEventName(eventName); + } + + public String getEventName() { + return originalEventName; + } + + public Pattern getPattern() { + return pattern; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + originalEventName.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + EventNamePattern other = (EventNamePattern) obj; + if (!originalEventName.equals(other.originalEventName)) { + return false; + } + return true; + } + + private static Pattern patternFromEventName(String eventName) { + /* + * The situation here is that `\*` means a literal `*` in the event + * name, and `*` is a wildcard star. We check the event name one + * character at a time and create a list of tokens to be converter to + * partial patterns. + */ + StringBuilder bigBuilder = new StringBuilder("^"); + StringBuilder smallBuilder = new StringBuilder(); + + for (int i = 0; i < eventName.length(); i++) { + char c = eventName.charAt(i); + + switch (c) { + case '*': + /* Add current quoted builder's string if not empty. */ + if (smallBuilder.length() > 0) { + bigBuilder.append(Pattern.quote(smallBuilder.toString())); + smallBuilder.setLength(0); + } + + /* Append the equivalent regex which is `.*`. */ + bigBuilder.append(".*"); + continue; + + case '\\': + /* We only escape `*` and `\` here. */ + if (i < (eventName.length() - 1)) { + char nextChar = eventName.charAt(i + 1); + + if (nextChar == '*' || nextChar == '\\') { + smallBuilder.append(nextChar); + } else { + smallBuilder.append(c); + smallBuilder.append(nextChar); + } + + i++; + continue; + } + break; + + default: + break; + } + + smallBuilder.append(c); + } + + /* Add current quoted builder's string if not empty. */ + if (smallBuilder.length() > 0) { + bigBuilder.append(Pattern.quote(smallBuilder.toString())); + } + + bigBuilder.append("$"); + + return Pattern.compile(bigBuilder.toString()); + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngAgent.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngAgent.java new file mode 100644 index 00000000..ca2358a5 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngAgent.java @@ -0,0 +1,97 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + */ + +package org.lttng.ust.agent; + +import java.util.Collection; +import java.util.Map; + +/** + * Interface to define LTTng Java agents. + * + * An "agent" is a representative of an LTTng session daemon in the Java world. + * It tracks the settings of a tracing session as they defined in the session + * daemon. + * + * It also track the current logging handlers that are sending events to UST. + * + * @author Alexandre Montplaisir + * + * @param + * The type of logging handler that should register to this agent + */ +public interface ILttngAgent { + + // ------------------------------------------------------------------------ + // Agent configuration elements + // ------------------------------------------------------------------------ + + /** + * Tracing domains. Corresponds to domains defined by LTTng Tools. + */ + enum Domain { + JUL(3), LOG4J(4); + private int value; + + private Domain(int value) { + this.value = value; + } + + public int value() { + return value; + } + } + + /** + * The tracing domain of this agent. + * + * @return The tracing domain. + */ + Domain getDomain(); + + // ------------------------------------------------------------------------ + // Log handler registering + // ------------------------------------------------------------------------ + + /** + * Register a handler to this agent. + * + * @param handler + * The handler to register + */ + void registerHandler(T handler); + + /** + * Deregister a handler from this agent. + * + * @param handler + * The handler to deregister. + */ + void unregisterHandler(T handler); + + // ------------------------------------------------------------------------ + // Tracing session parameters + // ------------------------------------------------------------------------ + + /** + * Query if a given event is currently enabled in a current tracing session, + * meaning it should be sent to UST. + * + * @param eventName + * The name of the event to check. + * @return True if the event is currently enabled, false if it is not. + */ + boolean isEventEnabled(String eventName); + + /** + * Return the list of application contexts enabled in the tracing sessions. + * + * @return The application contexts, first indexed by retriever name, then + * by context name + */ + Collection>> getEnabledAppContexts(); +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngHandler.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngHandler.java new file mode 100644 index 00000000..0d1bd799 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngHandler.java @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + */ + +package org.lttng.ust.agent; + +/** + * Simple interface to organize all LTTng log handlers under one type. + * + * @author Alexandre Montplaisir + */ +public interface ILttngHandler { + + /** + * Get the number of events logged by this handler since its inception. + * + * @return The number of logged events + */ + long getEventCount(); + + /** + * Close the log handler. Should be called once the application is done + * logging through it. + */ + void close(); +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngAgent.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngAgent.java new file mode 100644 index 00000000..f6aae351 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngAgent.java @@ -0,0 +1,280 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2013 David Goulet + */ + +package org.lttng.ust.agent; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Handler; +import java.util.logging.Logger; + +/** + * The central agent managing the JUL and Log4j handlers. + * + * @author David Goulet + * @deprecated Applications are now expected to manage their Logger and Handler + * objects. + */ +@Deprecated +public class LTTngAgent { + + private static LTTngAgent instance = null; + + /** + * Public getter to acquire a reference to this singleton object. + * + * @return The agent instance + */ + public static synchronized LTTngAgent getLTTngAgent() { + if (instance == null) { + instance = new LTTngAgent(); + } + return instance; + } + + /** + * Dispose the agent. Applications should call this once they are done + * logging. This dispose function is non-static for backwards + * compatibility purposes. + */ + @SuppressWarnings("static-method") + public void dispose() { + synchronized (LTTngAgent.class) { + if (instance != null) { + instance.disposeInstance(); + instance = null; + } + } + return; + } + + private ILttngHandler julHandler = null; + private ILttngHandler log4jAppender = null; + + /** + * Private constructor. This is a singleton and a reference should be + * acquired using {@link #getLTTngAgent()}. + */ + private LTTngAgent() { + initJulHandler(); + initLog4jAppender(); + } + + /** + * "Destructor" method. + */ + private void disposeInstance() { + disposeJulHandler(); + disposeLog4jAppender(); + } + + /** + * Create a LTTng-JUL handler, and attach it to the JUL root logger. + */ + private void initJulHandler() { + try { + Class julHandlerClass = Class.forName("org.lttng.ust.agent.jul.LttngLogHandler"); + /* + * It is safer to use Constructor.newInstance() rather than + * Class.newInstance(), because it will catch the exceptions thrown + * by the constructor below (which happens if the Java library is + * present, but the matching JNI one is not). + */ + Constructor julHandlerCtor = julHandlerClass.getConstructor(); + julHandler = (ILttngHandler) julHandlerCtor.newInstance(); + + /* Attach the handler to the root JUL logger */ + Logger.getLogger("").addHandler((Handler) julHandler); + + /* + * If any of the following exceptions happen, it means we could not + * find or initialize LTTng JUL classes. We will not setup LTTng JUL + * tracing in this case. + */ + } catch (SecurityException e) { + } catch (IllegalAccessException e) { + } catch (IllegalArgumentException e) { + } catch (ClassNotFoundException e) { + } catch (NoSuchMethodException e) { + } catch (InstantiationException e) { + } catch (InvocationTargetException e) { + } + } + + /** + * Create a LTTng-logj4 appender, and attach it to the log4j root logger. + */ + private void initLog4jAppender() { + /* + * Since Log4j is a 3rd party library, we first need to check if we can + * load any of its classes. + */ + if (!testLog4jClasses()) { + return; + } + + try { + Class log4jAppenderClass = Class.forName("org.lttng.ust.agent.log4j.LttngLogAppender"); + Constructor log4jAppendCtor = log4jAppenderClass.getConstructor(); + log4jAppender = (ILttngHandler) log4jAppendCtor.newInstance(); + + /* + * If any of the following exceptions happen, it means we could not + * find or initialize LTTng log4j classes. We will not setup LTTng + * log4j tracing in this case. + */ + } catch (SecurityException e) { + return; + } catch (ClassNotFoundException e) { + return; + } catch (NoSuchMethodException e) { + return; + } catch (IllegalArgumentException e) { + return; + } catch (InstantiationException e) { + return; + } catch (IllegalAccessException e) { + return; + } catch (InvocationTargetException e) { + return; + } + + /* + * Attach the appender to the root Log4j logger. Slightly more tricky + * here, as log4j.Logger is not in the base Java library, and we do not + * want the "common" package to depend on log4j. So we have to obtain it + * through reflection too. + */ + try { + Class loggerClass = Class.forName("org.apache.log4j.Logger"); + Class appenderClass = Class.forName("org.apache.log4j.Appender"); + + Method getRootLoggerMethod = loggerClass.getMethod("getRootLogger", (Class[]) null); + Method addAppenderMethod = loggerClass.getMethod("addAppender", appenderClass); + + Object rootLogger = getRootLoggerMethod.invoke(null, (Object[]) null); + addAppenderMethod.invoke(rootLogger, log4jAppender); + + /* + * We have checked for the log4j library version previously, none of + * the following exceptions should happen. + */ + } catch (SecurityException e) { + throw new IllegalStateException(e); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e); + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } catch (IllegalArgumentException e) { + throw new IllegalStateException(e); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + throw new IllegalStateException(e); + } + } + + /** + * Check if log4j >= 1.2.15 library is present. + */ + private static boolean testLog4jClasses() { + Class loggingEventClass; + + try { + loggingEventClass = Class.forName("org.apache.log4j.spi.LoggingEvent"); + } catch (ClassNotFoundException e) { + /* + * Log4j classes not found, no need to create the relevant objects + */ + return false; + } + + /* + * Detect capabilities of the log4j library. We only support log4j >= + * 1.2.15. The getTimeStamp() method was introduced in log4j 1.2.15, so + * verify that it is available. + * + * We can't rely on the getPackage().getImplementationVersion() call + * that would retrieves information from the manifest file found in the + * JAR since the manifest file shipped from upstream is known to be + * broken in several versions of the library. + * + * More info: https://issues.apache.org/bugzilla/show_bug.cgi?id=44370 + */ + try { + loggingEventClass.getDeclaredMethod("getTimeStamp"); + } catch (NoSuchMethodException e) { + System.err.println( + "Warning: The loaded log4j library is too old. Log4j tracing with LTTng will be disabled."); + return false; + } catch (SecurityException e) { + return false; + } + + return true; + } + + /** + * Detach the JUL handler from its logger and close it. + */ + private void disposeJulHandler() { + if (julHandler == null) { + /* The JUL handler was not activated, we have nothing to do */ + return; + } + Logger.getLogger("").removeHandler((Handler) julHandler); + julHandler.close(); + julHandler = null; + } + + /** + * Detach the log4j appender from its logger and close it. + */ + private void disposeLog4jAppender() { + if (log4jAppender == null) { + /* The log4j appender was not active, we have nothing to do */ + return; + } + + /* + * Detach the appender from the log4j root logger. Again, we have to do + * this via reflection. + */ + try { + Class loggerClass = Class.forName("org.apache.log4j.Logger"); + Class appenderClass = Class.forName("org.apache.log4j.Appender"); + + Method getRootLoggerMethod = loggerClass.getMethod("getRootLogger", (Class[]) null); + Method removeAppenderMethod = loggerClass.getMethod("removeAppender", appenderClass); + + Object rootLogger = getRootLoggerMethod.invoke(null, (Object[]) null); + removeAppenderMethod.invoke(rootLogger, log4jAppender); + + /* + * We were able to attach the appender previously, we should not + * have problems here either! + */ + } catch (SecurityException e) { + throw new IllegalStateException(e); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e); + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } catch (IllegalArgumentException e) { + throw new IllegalStateException(e); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + throw new IllegalStateException(e); + } + + /* Close the appender */ + log4jAppender.close(); + log4jAppender = null; + } + +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/ILttngTcpClientListener.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/ILttngTcpClientListener.java new file mode 100644 index 00000000..e6edb567 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/ILttngTcpClientListener.java @@ -0,0 +1,86 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.client; + +import java.util.Collection; + +import org.lttng.ust.agent.session.EventRule; + +/** + * TCP client listener interface. + * + * This interface contains callbacks that are called when the TCP client + * receives commands from the session daemon. These callbacks will define what + * do to with each command. + * + * @author Alexandre Montplaisir + */ +public interface ILttngTcpClientListener { + + /** + * Callback for the TCP client to notify the listener agent that a request + * for enabling an event rule was sent from the session daemon. + * + * @param eventRule + * The event rule that was requested to be enabled + * @return Since we do not track individual sessions, right now this command + * cannot fail. It will always return true. + */ + boolean eventEnabled(EventRule eventRule); + + /** + * Callback for the TCP client to notify the listener agent that a request + * for disabling an event was sent from the session daemon. + * + * @param eventName + * The name of the event that was requested to be disabled. + * @return True if the command completed successfully, false if we should + * report an error (event was not enabled, etc.) + */ + boolean eventDisabled(String eventName); + + /** + * Callback for the TCP client to notify the listener agent that a request + * for enabling an application-specific context was sent from the session + * daemon. + * + * @param contextRetrieverName + * The name of the retriever in which the context is present. + * This is used to namespace the contexts. + * @param contextName + * The name of the context that was requested to be enabled + * @return Since we do not track individual sessions, right now this command + * cannot fail. It will always return true. + */ + boolean appContextEnabled(String contextRetrieverName, String contextName); + + /** + * Callback for the TCP client to notify the listener agent that a request + * for disabling an application-specific context was sent from the session + * daemon. + * + * @param contextRetrieverName + * The name of the retriever in which the context is present. + * This is used to namespace the contexts. + * @param contextName + * The name of the context that was requested to be disabled. + * @return True if the command completed successfully, false if we should + * report an error (context was not previously enabled for example) + */ + boolean appContextDisabled(String contextRetrieverName, String contextName); + + /** + * List the events that are available in the agent's tracing domain. + * + * In Java terms, this means loggers that have at least one LTTng log + * handler of their corresponding domain attached. + * + * @return The list of available events + */ + Collection listAvailableEvents(); +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngAgentResponse.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngAgentResponse.java new file mode 100644 index 00000000..4ffeccd9 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngAgentResponse.java @@ -0,0 +1,100 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + * Copyright (C) 2013 David Goulet + */ + +package org.lttng.ust.agent.client; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Interface for all response messages sent from the Java agent to the sessiond + * daemon. Normally sent after a command coming from the session daemon was + * executed. + * + * @author Alexandre Montplaisir + */ +abstract class LttngAgentResponse { + + private static final int INT_SIZE = 4; + + public static final LttngAgentResponse SUCESS_RESPONSE = new LttngAgentResponse() { + @Override + public ReturnCode getReturnCode() { + return ReturnCode.CODE_SUCCESS_CMD; + } + }; + + public static final LttngAgentResponse FAILURE_RESPONSE = new LttngAgentResponse() { + @Override + public ReturnCode getReturnCode() { + return ReturnCode.CODE_INVALID_CMD; + } + }; + + /** + * Return codes used in agent responses, to indicate success or different + * types of failures of the commands. + */ + protected enum ReturnCode { + + CODE_SUCCESS_CMD(1, "sucess"), + CODE_INVALID_CMD(2, "invalid"), + CODE_UNKNOWN_LOGGER_NAME(3, "unknown logger name"); + + private final int code; + private final String toString; + + private ReturnCode(int c, String str) { + code = c; + toString = str; + } + + public int getCode() { + return code; + } + + /** + * Mainly used for debugging. The strings are not sent through the + * socket. + */ + @Override + public String toString() { + return toString; + } + } + + /** + * Get the {@link ReturnCode} that goes with this response. It is expected + * by the session daemon, but some commands may require more than this + * in their response. + * + * @return The return code + */ + public abstract ReturnCode getReturnCode(); + + /** + * Gets a byte array of the response so that it may be streamed. + * + * @return The byte array of the response + */ + public byte[] getBytes() { + byte data[] = new byte[INT_SIZE]; + ByteBuffer buf = ByteBuffer.wrap(data); + buf.order(ByteOrder.BIG_ENDIAN); + buf.putInt(getReturnCode().getCode()); + return data; + } + + @Override + public String toString() { + return "LttngAgentResponse[" + + "code=" + getReturnCode().getCode() + + ", " + getReturnCode().toString() + + "]"; + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngTcpSessiondClient.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngTcpSessiondClient.java new file mode 100644 index 00000000..9fa8c3ac --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngTcpSessiondClient.java @@ -0,0 +1,429 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015-2016 EfficiOS Inc. + * Copyright (C) 2015-2016 Alexandre Montplaisir + * Copyright (C) 2013 David Goulet + */ + +package org.lttng.ust.agent.client; + +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.management.ManagementFactory; +import java.net.Socket; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.Charset; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.lttng.ust.agent.utils.LttngUstAgentLogger; + +/** + * Client for agents to connect to a local session daemon, using a TCP socket. + * + * @author David Goulet + */ +public class LttngTcpSessiondClient implements Runnable { + + private static final String SESSION_HOST = "127.0.0.1"; + private static final String ROOT_PORT_FILE = "/var/run/lttng/agent.port"; + private static final String USER_PORT_FILE = "/.lttng/agent.port"; + private static final Charset PORT_FILE_ENCODING = Charset.forName("UTF-8"); + + private static final int PROTOCOL_MAJOR_VERSION = 2; + private static final int PROTOCOL_MINOR_VERSION = 0; + + /** Command header from the session deamon. */ + private final CountDownLatch registrationLatch = new CountDownLatch(1); + + private Socket sessiondSock; + private volatile boolean quit = false; + + private DataInputStream inFromSessiond; + private DataOutputStream outToSessiond; + + private final ILttngTcpClientListener logAgent; + private final int domainValue; + private final boolean isRoot; + + /** + * Constructor + * + * @param logAgent + * The listener this client will operate on, typically an LTTng + * agent. + * @param domainValue + * The integer to send to the session daemon representing the + * tracing domain to handle. + * @param isRoot + * True if this client should connect to the root session daemon, + * false if it should connect to the user one. + */ + public LttngTcpSessiondClient(ILttngTcpClientListener logAgent, int domainValue, boolean isRoot) { + this.logAgent = logAgent; + this.domainValue = domainValue; + this.isRoot = isRoot; + } + + /** + * Wait until this client has successfully established a connection to its + * target session daemon. + * + * @param seconds + * A timeout in seconds after which this method will return + * anyway. + * @return True if the the client actually established the connection, false + * if we returned because the timeout has elapsed or the thread was + * interrupted. + */ + public boolean waitForConnection(int seconds) { + try { + return registrationLatch.await(seconds, TimeUnit.SECONDS); + } catch (InterruptedException e) { + return false; + } + } + + @Override + public void run() { + for (;;) { + if (this.quit) { + break; + } + + try { + + /* + * Connect to the session daemon before anything else. + */ + log("Connecting to sessiond"); + connectToSessiond(); + + /* + * Register to the session daemon as the Java component of the + * UST application. + */ + log("Registering to sessiond"); + 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. + */ + log("Waiting on sessiond commands..."); + handleSessiondCmd(); + } catch (UnknownHostException uhe) { + uhe.printStackTrace(); + /* + * Terminate agent thread. + */ + close(); + } catch (IOException ioe) { + /* + * I/O exception may have been triggered by a session daemon + * closing the socket. Close our own socket and + * retry connecting after a delay. + */ + try { + if (this.sessiondSock != null) { + this.sessiondSock.close(); + } + Thread.sleep(3000); + } catch (InterruptedException e) { + /* + * Retry immediately if sleep is interrupted. + */ + } catch (IOException closeioe) { + closeioe.printStackTrace(); + /* + * Terminate agent thread. + */ + close(); + } + } + } + } + + /** + * Dispose this client and close any socket connection it may hold. + */ + public void close() { + log("Closing client"); + this.quit = true; + + try { + if (this.sessiondSock != null) { + this.sessiondSock.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void connectToSessiond() throws IOException { + int rootPort = getPortFromFile(ROOT_PORT_FILE); + int userPort = getPortFromFile(getHomePath() + USER_PORT_FILE); + + /* + * Check for the edge case of both files existing but pointing to the + * same port. In this case, let the root client handle it. + */ + if ((rootPort != 0) && (rootPort == userPort) && (!isRoot)) { + log("User and root config files both point to port " + rootPort + + ". Letting the root client handle it."); + throw new IOException(); + } + + int portToUse = (isRoot ? rootPort : userPort); + + if (portToUse == 0) { + /* No session daemon available. Stop and retry later. */ + throw new IOException(); + } + + this.sessiondSock = new Socket(SESSION_HOST, portToUse); + this.inFromSessiond = new DataInputStream(sessiondSock.getInputStream()); + this.outToSessiond = new DataOutputStream(sessiondSock.getOutputStream()); + } + + private static String getHomePath() { + /* + * The environment variable LTTNG_HOME overrides HOME if + * defined. + */ + String homePath = System.getenv("LTTNG_HOME"); + + if (homePath == null) { + homePath = System.getProperty("user.home"); + } + return homePath; + } + + /** + * Read port number from file created by the session daemon. + * + * @return port value if found else 0. + */ + private static int getPortFromFile(String path) throws IOException { + BufferedReader br = null; + + try { + br = new BufferedReader(new InputStreamReader(new FileInputStream(path), PORT_FILE_ENCODING)); + String line = br.readLine(); + if (line == null) { + /* File exists but is empty. */ + return 0; + } + + int port = Integer.parseInt(line, 10); + if (port < 0 || port > 65535) { + /* Invalid value. Ignore. */ + port = 0; + } + return port; + + } catch (NumberFormatException e) { + /* File contained something that was not a number. */ + return 0; + } catch (FileNotFoundException e) { + /* No port available. */ + return 0; + } finally { + if (br != null) { + br.close(); + } + } + } + + private void registerToSessiond() throws IOException { + byte data[] = new byte[16]; + ByteBuffer buf = ByteBuffer.wrap(data); + String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0]; + + buf.putInt(domainValue); + buf.putInt(Integer.parseInt(pid)); + buf.putInt(PROTOCOL_MAJOR_VERSION); + buf.putInt(PROTOCOL_MINOR_VERSION); + this.outToSessiond.write(data, 0, data.length); + this.outToSessiond.flush(); + } + + /** + * Handle session command from the session daemon. + */ + private void handleSessiondCmd() throws IOException { + /* Data read from the socket */ + byte inputData[] = null; + /* Reply data written to the socket, sent to the sessiond */ + LttngAgentResponse response; + + while (true) { + /* Get header from session daemon. */ + SessiondCommandHeader cmdHeader = recvHeader(); + + if (cmdHeader.getDataSize() > 0) { + inputData = recvPayload(cmdHeader); + } + + switch (cmdHeader.getCommandType()) { + case CMD_REG_DONE: + { + /* + * Countdown the registration latch, meaning registration is + * done and we can proceed to continue tracing. + */ + registrationLatch.countDown(); + /* + * We don't send any reply to the registration done command. + * This just marks the end of the initial session setup. + */ + log("Registration done"); + continue; + } + case CMD_LIST: + { + SessiondCommand listLoggerCmd = new SessiondListLoggersCommand(); + response = listLoggerCmd.execute(logAgent); + log("Received list loggers command"); + break; + } + case CMD_EVENT_ENABLE: + { + if (inputData == null) { + /* Invalid command */ + response = LttngAgentResponse.FAILURE_RESPONSE; + break; + } + SessiondCommand enableEventCmd = new SessiondEnableEventCommand(inputData); + response = enableEventCmd.execute(logAgent); + log("Received enable event command: " + enableEventCmd.toString()); + break; + } + case CMD_EVENT_DISABLE: + { + if (inputData == null) { + /* Invalid command */ + response = LttngAgentResponse.FAILURE_RESPONSE; + break; + } + SessiondCommand disableEventCmd = new SessiondDisableEventCommand(inputData); + response = disableEventCmd.execute(logAgent); + log("Received disable event command: " + disableEventCmd.toString()); + break; + } + case CMD_APP_CTX_ENABLE: + { + if (inputData == null) { + /* This commands expects a payload, invalid command */ + response = LttngAgentResponse.FAILURE_RESPONSE; + break; + } + SessiondCommand enableAppCtxCmd = new SessiondEnableAppContextCommand(inputData); + response = enableAppCtxCmd.execute(logAgent); + log("Received enable app-context command"); + break; + } + case CMD_APP_CTX_DISABLE: + { + if (inputData == null) { + /* This commands expects a payload, invalid command */ + response = LttngAgentResponse.FAILURE_RESPONSE; + break; + } + SessiondCommand disableAppCtxCmd = new SessiondDisableAppContextCommand(inputData); + response = disableAppCtxCmd.execute(logAgent); + log("Received disable app-context command"); + break; + } + default: + { + /* Unknown command, send empty reply */ + response = null; + log("Received unknown command, ignoring"); + break; + } + } + + /* Send response to the session daemon. */ + byte[] responseData; + if (response == null) { + responseData = new byte[4]; + ByteBuffer buf = ByteBuffer.wrap(responseData); + buf.order(ByteOrder.BIG_ENDIAN); + } else { + log("Sending response: " + response.toString()); + responseData = response.getBytes(); + } + this.outToSessiond.write(responseData, 0, responseData.length); + this.outToSessiond.flush(); + } + } + + /** + * Receive header data from the session daemon using the LTTng command + * static buffer of the right size. + */ + private SessiondCommandHeader recvHeader() throws IOException { + byte data[] = new byte[SessiondCommandHeader.HEADER_SIZE]; + int bytesLeft = data.length; + int bytesOffset = 0; + + while (bytesLeft > 0) { + int bytesRead = this.inFromSessiond.read(data, bytesOffset, bytesLeft); + + if (bytesRead < 0) { + throw new IOException(); + } + bytesLeft -= bytesRead; + bytesOffset += bytesRead; + } + return new SessiondCommandHeader(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(SessiondCommandHeader headerCmd) throws IOException { + byte payload[] = new byte[(int) headerCmd.getDataSize()]; + int bytesLeft = payload.length; + int bytesOffset = 0; + + /* Failsafe check so we don't waste our time reading 0 bytes. */ + if (bytesLeft == 0) { + return null; + } + + while (bytesLeft > 0) { + int bytesRead = inFromSessiond.read(payload, bytesOffset, bytesLeft); + + if (bytesRead < 0) { + throw new IOException(); + } + bytesLeft -= bytesRead; + bytesOffset += bytesRead; + } + return payload; + } + + /** + * Wrapper for this class's logging, adds the connection's characteristics + * to help differentiate between multiple TCP clients. + */ + private void log(String message) { + LttngUstAgentLogger.log(getClass(), + "(root=" + isRoot + ", domain=" + domainValue + ") " + message); + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommand.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommand.java new file mode 100644 index 00000000..27aba232 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommand.java @@ -0,0 +1,89 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015-2016 EfficiOS Inc. + * Copyright (C) 2015-2016 Alexandre Montplaisir + * Copyright (C) 2013 David Goulet + */ + +package org.lttng.ust.agent.client; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +/** + * Base class to represent all commands sent from the session daemon to the Java + * agent. The agent is then expected to execute the command and provide a + * response. + * + * @author Alexandre Montplaisir + */ +abstract class SessiondCommand { + + /** + * Encoding that should be used for the strings in the sessiond agent + * protocol on the socket. + */ + protected static final Charset SESSIOND_PROTOCOL_CHARSET = Charset.forName("UTF-8"); + + enum CommandType { + /** List logger(s). */ + CMD_LIST(1), + /** Enable logger by name. */ + CMD_EVENT_ENABLE(2), + /** Disable logger by name. */ + CMD_EVENT_DISABLE(3), + /** Registration done */ + CMD_REG_DONE(4), + /** Enable application context */ + CMD_APP_CTX_ENABLE(5), + /** Disable application context */ + CMD_APP_CTX_DISABLE(6); + + private int code; + + private CommandType(int c) { + code = c; + } + + public int getCommandType() { + return code; + } + } + + /** + * Execute the command handler's action on the specified tracing agent. + * + * @param agent + * The agent on which to execute the command + * @return If the command completed successfully or not + */ + public abstract LttngAgentResponse execute(ILttngTcpClientListener agent); + + /** + * Utility method to read agent-protocol strings passed on the socket. The + * buffer will contain a 32-bit integer representing the length, immediately + * followed by the string itself. + * + * @param buffer + * The ByteBuffer from which to read. It should already be setup + * and positioned where the read should begin. + * @return The string that was read, or null if it was badly + * formatted. + */ + protected static String readNextString(ByteBuffer buffer) { + int nbBytes = buffer.getInt(); + if (nbBytes < 0) { + /* The string length should be positive */ + return null; + } + if (nbBytes == 0) { + /* The string is explicitly an empty string */ + return ""; + } + + byte[] stringBytes = new byte[nbBytes]; + buffer.get(stringBytes); + return new String(stringBytes, SESSIOND_PROTOCOL_CHARSET).trim(); + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommandHeader.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommandHeader.java new file mode 100644 index 00000000..845109d7 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommandHeader.java @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + * Copyright (C) 2013 David Goulet + */ + +package org.lttng.ust.agent.client; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import org.lttng.ust.agent.client.SessiondCommand.CommandType; + +/** + * Header of session daemon commands. + * + * @author Alexandre Montplaisir + * @author David Goulet + */ +class SessiondCommandHeader { + + /** ABI size of command header. */ + public static final int HEADER_SIZE = 16; + + /** Payload size in bytes following this header. */ + private final long dataSize; + + /** Command type. */ + private final CommandType cmd; + + public SessiondCommandHeader(byte[] data) { + ByteBuffer buf = ByteBuffer.wrap(data); + buf.order(ByteOrder.BIG_ENDIAN); + + dataSize = buf.getLong(); + cmd = CommandType.values()[buf.getInt() - 1]; + buf.getInt(); // command version, currently unused + } + + public long getDataSize() { + return dataSize; + } + + public CommandType getCommandType() { + return cmd; + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableAppContextCommand.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableAppContextCommand.java new file mode 100644 index 00000000..4ac991ab --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableAppContextCommand.java @@ -0,0 +1,65 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2016 EfficiOS Inc. + * Copyright (C) 2016 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.client; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Session daemon command indicating to the Java agent that an + * application-specific context was disabled in the tracing session. + * + * @author Alexandre Montplaisir + */ +class SessiondDisableAppContextCommand extends SessiondCommand { + + private final String retrieverName; + private final String contextName; + + private final boolean commandIsValid; + + public SessiondDisableAppContextCommand(byte[] data) { + if (data == null) { + throw new IllegalArgumentException(); + } + ByteBuffer buf = ByteBuffer.wrap(data); + buf.order(ByteOrder.BIG_ENDIAN); + + /* + * The buffer contains the retriever name first, followed by the + * context's name. + */ + retrieverName = readNextString(buf); + contextName = readNextString(buf); + + /* If any of these strings were null then the command was invalid */ + commandIsValid = ((retrieverName != null) && (contextName != null)); + } + + @Override + public LttngAgentResponse execute(ILttngTcpClientListener agent) { + if (!commandIsValid) { + return LttngAgentResponse.FAILURE_RESPONSE; + } + + boolean success = agent.appContextDisabled(retrieverName, contextName); + return (success ? LttngAgentResponse.SUCESS_RESPONSE : DISABLE_APP_CONTEXT_FAILURE_RESPONSE); + } + + /** + * Response sent when the disable-context command asks to disable an + * unknown context name. + */ + private static final LttngAgentResponse DISABLE_APP_CONTEXT_FAILURE_RESPONSE = new LttngAgentResponse() { + @Override + public ReturnCode getReturnCode() { + /* Same return code used for unknown event/logger names */ + return ReturnCode.CODE_UNKNOWN_LOGGER_NAME; + } + }; +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableEventCommand.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableEventCommand.java new file mode 100644 index 00000000..ff8eff3a --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableEventCommand.java @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + * Copyright (C) 2013 David Goulet + */ + +package org.lttng.ust.agent.client; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Session daemon command indicating to the Java agent that some events were + * disabled in the tracing session. + * + * @author Alexandre Montplaisir + * @author David Goulet + */ +class SessiondDisableEventCommand extends SessiondCommand { + + /** + * Response sent when the disable-event command asks to disable an + * unknown event. + */ + private static final LttngAgentResponse DISABLE_EVENT_FAILURE_RESPONSE = new LttngAgentResponse() { + @Override + public ReturnCode getReturnCode() { + return ReturnCode.CODE_UNKNOWN_LOGGER_NAME; + } + }; + + /** Event name to disable from the tracing session */ + private final String eventName; + + public SessiondDisableEventCommand(byte[] data) { + if (data == null) { + throw new IllegalArgumentException(); + } + ByteBuffer buf = ByteBuffer.wrap(data); + buf.order(ByteOrder.BIG_ENDIAN); + eventName = new String(data, SESSIOND_PROTOCOL_CHARSET).trim(); + } + + @Override + public LttngAgentResponse execute(ILttngTcpClientListener agent) { + boolean success = agent.eventDisabled(this.eventName); + return (success ? LttngAgentResponse.SUCESS_RESPONSE : DISABLE_EVENT_FAILURE_RESPONSE); + } + + @Override + public String toString() { + return "SessiondDisableEventCommand[" + + "eventName=" + eventName + +"]"; + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableAppContextCommand.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableAppContextCommand.java new file mode 100644 index 00000000..d0be8cf9 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableAppContextCommand.java @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2016 EfficiOS Inc. + * Copyright (C) 2016 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.client; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Session daemon command indicating to the Java agent that an + * application-specific context was enabled in the tracing session. + * + * @author Alexandre Montplaisir + */ +class SessiondEnableAppContextCommand extends SessiondCommand { + + private final String retrieverName; + private final String contextName; + + private final boolean commandIsValid; + + public SessiondEnableAppContextCommand(byte[] data) { + if (data == null) { + throw new IllegalArgumentException(); + } + ByteBuffer buf = ByteBuffer.wrap(data); + buf.order(ByteOrder.BIG_ENDIAN); + + /* + * The buffer contains the retriever name first, followed by the + * context's name. + */ + retrieverName = readNextString(buf); + contextName = readNextString(buf); + + /* If any of these strings were null then the command was invalid */ + commandIsValid = ((retrieverName != null) && (contextName != null)); + } + + @Override + public LttngAgentResponse execute(ILttngTcpClientListener agent) { + if (!commandIsValid) { + return LttngAgentResponse.FAILURE_RESPONSE; + } + + boolean success = agent.appContextEnabled(retrieverName, contextName); + return (success ? LttngAgentResponse.SUCESS_RESPONSE : LttngAgentResponse.FAILURE_RESPONSE); + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableEventCommand.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableEventCommand.java new file mode 100644 index 00000000..35029c9b --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableEventCommand.java @@ -0,0 +1,77 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + * Copyright (C) 2013 David Goulet + */ + +package org.lttng.ust.agent.client; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import org.lttng.ust.agent.session.EventRule; +import org.lttng.ust.agent.session.LogLevelSelector; + +/** + * Session daemon command indicating to the Java agent that some events were + * enabled in the tracing session. + * + * @author Alexandre Montplaisir + * @author David Goulet + */ +class SessiondEnableEventCommand extends SessiondCommand { + + /** Fixed event name length. Value defined by the lttng agent protocol. */ + private static final int EVENT_NAME_LENGTH = 256; + + private final boolean commandIsValid; + + /* Parameters of the event rule being enabled */ + private final String eventName; + private final LogLevelSelector logLevelFilter; + private final String filterString; + + public SessiondEnableEventCommand(byte[] data) { + if (data == null) { + throw new IllegalArgumentException(); + } + ByteBuffer buf = ByteBuffer.wrap(data); + buf.order(ByteOrder.BIG_ENDIAN); + int logLevel = buf.getInt(); + int logLevelType = buf.getInt(); + logLevelFilter = new LogLevelSelector(logLevel, logLevelType); + + /* Read the event name */ + byte[] eventNameBytes = new byte[EVENT_NAME_LENGTH]; + buf.get(eventNameBytes); + eventName = new String(eventNameBytes, SESSIOND_PROTOCOL_CHARSET).trim(); + + /* Read the filter string */ + filterString = readNextString(buf); + + /* The command was invalid if the string could not be read correctly */ + commandIsValid = (filterString != null); + } + + @Override + public LttngAgentResponse execute(ILttngTcpClientListener agent) { + if (!commandIsValid) { + return LttngAgentResponse.FAILURE_RESPONSE; + } + + EventRule rule = new EventRule(eventName, logLevelFilter, filterString); + boolean success = agent.eventEnabled(rule); + return (success ? LttngAgentResponse.SUCESS_RESPONSE : LttngAgentResponse.FAILURE_RESPONSE); + } + + @Override + public String toString() { + return "SessiondEnableEventCommand[" + + "eventName=" + eventName + + ", logLevel=" + logLevelFilter.toString() + + ", filterString=" + filterString + +"]"; + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondListLoggersCommand.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondListLoggersCommand.java new file mode 100644 index 00000000..0500055c --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondListLoggersCommand.java @@ -0,0 +1,77 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + * Copyright (C) 2013 David Goulet + */ + +package org.lttng.ust.agent.client; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Collection; + +/** + * Session daemon command asking the Java agent to list its registered loggers, + * which corresponds to event names in the tracing session. + * + * @author Alexandre Montplaisir + * @author David Goulet + */ +class SessiondListLoggersCommand extends SessiondCommand { + + @Override + public LttngAgentResponse execute(ILttngTcpClientListener agent) { + final Collection loggerList = agent.listAvailableEvents(); + return new SessiondListLoggersResponse(loggerList); + } + + private static class SessiondListLoggersResponse extends LttngAgentResponse { + + private final static int SIZE = 12; + + private final Collection loggers; + + public SessiondListLoggersResponse(Collection loggers) { + this.loggers = loggers; + } + + @Override + public ReturnCode getReturnCode() { + /* This command can't really fail */ + return ReturnCode.CODE_SUCCESS_CMD; + } + + @Override + public byte[] getBytes() { + /* + * Compute the data size, which is the number of bytes of each + * encoded string, +1 per string for the \0 + */ + int dataSize = 0; + for (String logger : loggers) { + dataSize += logger.getBytes(SESSIOND_PROTOCOL_CHARSET).length + 1; + } + + /* Prepare the buffer */ + byte data[] = new byte[SIZE + dataSize]; + ByteBuffer buf = ByteBuffer.wrap(data); + buf.order(ByteOrder.BIG_ENDIAN); + + /* Write the header section of the response */ + buf.putInt(getReturnCode().getCode()); + buf.putInt(dataSize); + buf.putInt(loggers.size()); + + /* Write the payload */ + for (String logger : loggers) { + buf.put(logger.getBytes(SESSIOND_PROTOCOL_CHARSET)); + /* NULL terminated byte after the logger name. */ + buf.put((byte) 0x0); + } + return data; + } + } + +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoManager.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoManager.java new file mode 100644 index 00000000..22efe022 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoManager.java @@ -0,0 +1,189 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.context; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * The singleton manager of {@link IContextInfoRetriever} objects. + * + * @author Alexandre Montplaisir + */ +public final class ContextInfoManager { + + private static final String SHARED_LIBRARY_NAME = "lttng-ust-context-jni"; + + private static final Pattern VALID_CONTEXT_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_\\.]+$"); + + private static ContextInfoManager instance; + + private final Map contextInfoRetrievers = new ConcurrentHashMap(); + private final Map contextInforRetrieverRefs = new HashMap(); + + /** + * Lock used to keep the two maps above in sync when retrievers are + * registered or unregistered. + */ + private final Object retrieverLock = new Object(); + + /** Singleton class, constructor should not be accessed directly */ + private ContextInfoManager() { + } + + /** + * Get the singleton instance. + * + *

+ * Usage of this class requires the "liblttng-ust-context-jni.so" native + * library to be present on the system and available (passing + * -Djava.library.path=path to the JVM may be needed). + *

+ * + * @return The singleton instance + * @throws IOException + * If the shared library cannot be found. + * @throws SecurityException + * We will forward any SecurityExcepion that may be thrown when + * trying to load the JNI library. + */ + public static synchronized ContextInfoManager getInstance() throws IOException, SecurityException { + if (instance == null) { + try { + System.loadLibrary(SHARED_LIBRARY_NAME); + } catch (UnsatisfiedLinkError e) { + throw new IOException(e); + } + instance = new ContextInfoManager(); + } + return instance; + } + + /** + * Register a new context info retriever. + * + *

+ * Each context info retriever is registered with a given "retriever name", + * which specifies the namespace of the context elements. This name is + * specified separately from the retriever objects, which would allow + * register the same retriever under different namespaces for example. + *

+ * + *

+ * If the method returns false (indicating registration failure), then the + * retriever object will *not* be used for context information. + *

+ * + * @param retrieverName + * The name to register to the context retriever object with. + * @param contextInfoRetriever + * The context info retriever to register + * @return True if the retriever was successfully registered, false if there + * was an error, for example if a retriever is already registered + * with that name. + */ + public boolean registerContextInfoRetriever(String retrieverName, IContextInfoRetriever contextInfoRetriever) { + synchronized (retrieverLock) { + if (!validateRetrieverName(retrieverName)) { + return false; + } + + if (contextInfoRetrievers.containsKey(retrieverName)) { + /* + * There is already a retriever registered with that name, + * refuse the new registration. + */ + return false; + } + /* + * Inform LTTng-UST of the new retriever. The names have to start + * with "$app." on the UST side! + */ + long ref = LttngContextApi.registerProvider("$app." + retrieverName); + if (ref == 0) { + return false; + } + + contextInfoRetrievers.put(retrieverName, contextInfoRetriever); + contextInforRetrieverRefs.put(retrieverName, Long.valueOf(ref)); + + return true; + } + } + + /** + * Unregister a previously added context info retriever. + * + * This method has no effect if the retriever was not already registered. + * + * @param retrieverName + * The context info retriever to unregister + * @return True if unregistration was successful, false if there was an + * error + */ + public boolean unregisterContextInfoRetriever(String retrieverName) { + synchronized (retrieverLock) { + if (!contextInfoRetrievers.containsKey(retrieverName)) { + /* + * There was no retriever registered with that name. + */ + return false; + } + contextInfoRetrievers.remove(retrieverName); + long ref = contextInforRetrieverRefs.remove(retrieverName).longValue(); + + /* Unregister the retriever on the UST side too */ + LttngContextApi.unregisterProvider(ref); + + return true; + } + } + + /** + * Return the context info retriever object registered with the given name. + * + * @param retrieverName + * The retriever name to look for + * @return The corresponding retriever object, or null if there + * was none + */ + public IContextInfoRetriever getContextInfoRetriever(String retrieverName) { + /* + * Note that this method does not take the retrieverLock, it lets + * concurrent threads access the ConcurrentHashMap directly. + * + * It's fine for a get() to happen during a registration or + * unregistration, it's first-come-first-serve. + */ + return contextInfoRetrievers.get(retrieverName); + } + + /** + * Validate that the given retriever name contains only the allowed + * characters, which are alphanumerical characters, period "." and + * underscore "_". The name must also not start with a number. + */ + private static boolean validateRetrieverName(String contextName) { + if (contextName.isEmpty()) { + return false; + } + + /* First character must not be a number */ + if (Character.isDigit(contextName.charAt(0))) { + return false; + } + + /* Validate the other characters of the string */ + Matcher matcher = VALID_CONTEXT_NAME_PATTERN.matcher(contextName); + return matcher.matches(); + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java new file mode 100644 index 00000000..ae650607 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java @@ -0,0 +1,285 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2016 EfficiOS Inc. + * Copyright (C) 2016 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.context; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.Map; + +import org.lttng.ust.agent.utils.LttngUstAgentLogger; + +/** + * This class is used to serialize the list of "context info" objects to pass + * through JNI. + * + * The protocol expects two byte array parameters, which are contained here in + * the {@link SerializedContexts} inner class. + * + * The first byte array is called the "entries array", and contains fixed-size + * entries, one per context element. + * + * The second one is the "strings array", it is of variable length and used to + * hold the variable-length strings. Each one of these strings is formatted as a + * UTF-8 C-string, meaning in will end with a "\0" byte to indicate its end. + * Entries in the first array may refer to offsets in the second array to point + * to relevant strings. + * + * The fixed-size entries in the entries array contain the following elements + * (size in bytes in parentheses): + * + *
    + *
  • The offset in the strings array pointing to the full context name, like + * "$app.myprovider:mycontext" (4)
  • + *
  • The context value type (1)
  • + *
  • The context value itself (8)
  • + *
+ * + * The context value type will indicate how many bytes are used for the value. + * If the it is of String type, then we use 4 bytes to represent the offset in + * the strings array. + * + * So the total size of each entry is 13 bytes. All unused bytes (for context + * values shorter than 8 bytes for example) will be zero'ed. + * + * @author Alexandre Montplaisir + */ +public class ContextInfoSerializer { + + private enum DataType { + NULL(0), + INTEGER(1), + LONG(2), + DOUBLE(3), + FLOAT(4), + BYTE(5), + SHORT(6), + BOOLEAN(7), + STRING(8); + + private final byte value; + + private DataType(int value) { + this.value = (byte) value; + } + + public byte getValue() { + return value; + } + } + + /** + * Class used to wrap the two byte arrays returned by + * {@link #queryAndSerializeRequestedContexts}. + */ + public static class SerializedContexts { + + private final byte[] contextEntries; + private final byte[] contextStrings; + + /** + * Constructor + * + * @param entries + * Arrays for the fixed-size context entries. + * @param strings + * Arrays for variable-length strings + */ + public SerializedContexts(byte[] entries, byte[] strings) { + contextEntries = entries; + contextStrings = strings; + } + + /** + * @return The entries array + */ + public byte[] getEntriesArray() { + return contextEntries; + } + + /** + * @return The strings array + */ + public byte[] getStringsArray() { + return contextStrings; + } + } + + private static final String UST_APP_CTX_PREFIX = "$app."; + private static final int ENTRY_LENGTH = 13; + private static final ByteOrder NATIVE_ORDER = ByteOrder.nativeOrder(); + private static final Charset UTF8_CHARSET = Charset.forName("UTF-8"); + private static final SerializedContexts EMPTY_CONTEXTS = new SerializedContexts(new byte[0], new byte[0]); + + /** + * From the list of requested contexts in the tracing session, look them up + * in the {@link ContextInfoManager}, retrieve the available ones, and + * serialize them into a byte array. + * + * @param enabledContexts + * The contexts that are enabled in the tracing session (indexed + * first by retriever name, then by index names). Should come + * from the LTTng Agent. + * @return The byte array representing the intersection of the requested and + * available contexts. + */ + public static SerializedContexts queryAndSerializeRequestedContexts(Collection>> enabledContexts) { + if (enabledContexts.isEmpty()) { + /* Early return if there is no requested context information */ + return EMPTY_CONTEXTS; + } + + ContextInfoManager contextManager; + try { + contextManager = ContextInfoManager.getInstance(); + } catch (IOException e) { + /* + * The JNI library is not available, do not send any context + * information. No retriever could have been defined anyways. + */ + return EMPTY_CONTEXTS; + } + + /* Compute the total number of contexts (flatten the map) */ + int totalArraySize = 0; + for (Map.Entry> contexts : enabledContexts) { + totalArraySize += contexts.getValue().size() * ENTRY_LENGTH; + } + + /* Prepare the ByteBuffer that will generate the "entries" array */ + ByteBuffer entriesBuffer = ByteBuffer.allocate(totalArraySize); + entriesBuffer.order(NATIVE_ORDER); + entriesBuffer.clear(); + + /* Prepare the streams that will generate the "strings" array */ + ByteArrayOutputStream stringsBaos = new ByteArrayOutputStream(); + DataOutputStream stringsDos = new DataOutputStream(stringsBaos); + + try { + for (Map.Entry> entry : enabledContexts) { + String requestedRetrieverName = entry.getKey(); + Map requestedContexts = entry.getValue(); + + IContextInfoRetriever retriever = contextManager.getContextInfoRetriever(requestedRetrieverName); + + for (String requestedContext : requestedContexts.keySet()) { + Object contextInfo; + if (retriever == null) { + contextInfo = null; + } else { + contextInfo = retriever.retrieveContextInfo(requestedContext); + /* + * 'contextInfo' can still be null here, which would + * indicate the retriever does not supply this context. + * We will still write this information so that the + * tracer can know about it. + */ + } + + /* Serialize the result to the buffers */ + // FIXME Eventually pass the retriever name only once? + String fullContextName = (UST_APP_CTX_PREFIX + requestedRetrieverName + ':' + requestedContext); + byte[] strArray = fullContextName.getBytes(UTF8_CHARSET); + + entriesBuffer.putInt(stringsDos.size()); + stringsDos.write(strArray); + stringsDos.writeChar('\0'); + + LttngUstAgentLogger.log(ContextInfoSerializer.class, + "ContextInfoSerializer: Context to be sent through JNI: " + fullContextName + '=' + + (contextInfo == null ? "null" : contextInfo.toString())); + + serializeContextInfo(entriesBuffer, stringsDos, contextInfo); + } + } + + stringsDos.flush(); + stringsBaos.flush(); + + } catch (IOException e) { + /* + * Should not happen because we are wrapping a + * ByteArrayOutputStream, which writes to memory + */ + e.printStackTrace(); + } + + byte[] entriesArray = entriesBuffer.array(); + byte[] stringsArray = stringsBaos.toByteArray(); + return new SerializedContexts(entriesArray, stringsArray); + } + + private static final int CONTEXT_VALUE_LENGTH = 8; + + private static void serializeContextInfo(ByteBuffer entriesBuffer, DataOutputStream stringsDos, Object contextInfo) throws IOException { + int remainingBytes; + if (contextInfo == null) { + entriesBuffer.put(DataType.NULL.getValue()); + remainingBytes = CONTEXT_VALUE_LENGTH; + + } else if (contextInfo instanceof Integer) { + entriesBuffer.put(DataType.INTEGER.getValue()); + entriesBuffer.putInt(((Integer) contextInfo).intValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 4; + + } else if (contextInfo instanceof Long) { + entriesBuffer.put(DataType.LONG.getValue()); + entriesBuffer.putLong(((Long) contextInfo).longValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 8; + + } else if (contextInfo instanceof Double) { + entriesBuffer.put(DataType.DOUBLE.getValue()); + entriesBuffer.putDouble(((Double) contextInfo).doubleValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 8; + + } else if (contextInfo instanceof Float) { + entriesBuffer.put(DataType.FLOAT.getValue()); + entriesBuffer.putFloat(((Float) contextInfo).floatValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 4; + + } else if (contextInfo instanceof Byte) { + entriesBuffer.put(DataType.BYTE.getValue()); + entriesBuffer.put(((Byte) contextInfo).byteValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 1; + + } else if (contextInfo instanceof Short) { + entriesBuffer.put(DataType.SHORT.getValue()); + entriesBuffer.putShort(((Short) contextInfo).shortValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 2; + + } else if (contextInfo instanceof Boolean) { + entriesBuffer.put(DataType.BOOLEAN.getValue()); + boolean b = ((Boolean) contextInfo).booleanValue(); + /* Converted to one byte, write 1 for true, 0 for false */ + entriesBuffer.put((byte) (b ? 1 : 0)); + remainingBytes = CONTEXT_VALUE_LENGTH - 1; + + } else { + /* Also includes the case of Character. */ + /* + * We'll write the object as a string, into the strings array. We + * will write the corresponding offset to the entries array. + */ + String str = contextInfo.toString(); + byte[] strArray = str.getBytes(UTF8_CHARSET); + + entriesBuffer.put(DataType.STRING.getValue()); + + entriesBuffer.putInt(stringsDos.size()); + stringsDos.write(strArray); + stringsDos.writeChar('\0'); + + remainingBytes = CONTEXT_VALUE_LENGTH - 4; + } + entriesBuffer.position(entriesBuffer.position() + remainingBytes); + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/IContextInfoRetriever.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/IContextInfoRetriever.java new file mode 100644 index 00000000..235a30a5 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/IContextInfoRetriever.java @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.context; + +/** + * Context-retrieving object specified by the application to extract + * application-specific context information, which can then be passed on to the + * Java agents and saved to a trace. + * + * Retriever objects should be registered to the {@link ContextInfoManager} to + * make them available to the LTTng agents. + * + * @author Alexandre Montplaisir + */ +public interface IContextInfoRetriever { + + /** + * Retrieve a piece of context information from the application, identified + * by a key. + * + * @param key + * The key identifying the context information + * @return The context information. + */ + Object retrieveContextInfo(String key); +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/LttngContextApi.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/LttngContextApi.java new file mode 100644 index 00000000..a60d80e1 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/LttngContextApi.java @@ -0,0 +1,44 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2016 EfficiOS Inc. + * Copyright (C) 2016 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.context; + +/** + * Virtual class containing the Java side of the LTTng-UST context provider + * registering/unregistering methods. + * + * @author Alexandre Montplaisir + */ +final class LttngContextApi { + + private LttngContextApi() {} + + /** + * Register a context provider to UST. + * + * The callbacks are the same for all providers, and are defined in the .c + * file. The only needed information is the retriever (which is called + * "provider" from UST'S point of view) name. + * + * @param provider_name + * The name of the provider + * @return The pointer to the created provider object. It's useless in the + * Java space, but will be needed for + * {@link #unregisterProvider(long)}. + */ + static native long registerProvider(String provider_name); + + /** + * Unregister a previously-registered context provider from UST. + * + * @param provider_ref + * The pointer to the provider object, obtained from + * {@link #registerProvider} + */ + static native void unregisterProvider(long provider_ref); +} + diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/FilterChangeNotifier.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/FilterChangeNotifier.java new file mode 100644 index 00000000..e1c96e16 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/FilterChangeNotifier.java @@ -0,0 +1,178 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.filter; + +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.lttng.ust.agent.session.EventRule; + +/** + * Singleton class managing the filter notifications. + * + * Applications can register a {@link IFilterChangeListener} to be notified when + * event filtering rules change in the tracing sessions. + * + * @author Alexandre Montplaisir + */ +public final class FilterChangeNotifier { + + /** Lazy-loaded singleton instance object */ + private static FilterChangeNotifier instance = null; + + private final Map enabledEventRules = new HashMap(); + private final Collection registeredListeners = new LinkedList(); + + + /** + * Private constructor, singleton class should not be instantiated directly. + */ + private FilterChangeNotifier() { + } + + /** + * Get the singleton instance, initializing it if needed. + * + * @return The singleton instance + */ + public static synchronized FilterChangeNotifier getInstance() { + if (instance == null) { + instance = new FilterChangeNotifier(); + } + return instance; + } + + /** + * Notify the filter manager that a new rule was enabled in a tracing + * session ("lttng enable-event ...") + * + * This is meant to be called by the LTTng Agent only. External Java + * applications should not call this. + * + * @param rule + * The rule that was added + */ + public synchronized void addEventRule(EventRule rule) { + Integer count = enabledEventRules.get(rule); + if (count == null) { + /* + * This is the first instance of this rule being enabled. Add it to + * the map and send notifications to the registered notifiers. + */ + enabledEventRules.put(rule, Integer.valueOf(1)); + notifyForAddedRule(rule); + return; + } + if (count.intValue() <= 0) { + /* It should not have been in the map! */ + throw new IllegalStateException(); + } + /* + * This exact event rule was already enabled, just increment its + * refcount without sending notifications + */ + enabledEventRules.put(rule, Integer.valueOf(count.intValue() + 1)); + } + + /** + * Notify the filter manager that an event name was disabled in the tracing + * sessions ("lttng disable-event ..."). + * + * The "disable-event" only specifies an event name. This means all the + * rules containing this event name are to be disabled. + * + * This is meant to be called by the LTTng Agent only. External Java + * applications should not call this. + * + * @param eventName + * The event name to disable + */ + public synchronized void removeEventRules(String eventName) { + List rulesToRemove = new LinkedList(); + + for (EventRule eventRule : enabledEventRules.keySet()) { + if (eventRule.getEventName().equals(eventName)) { + rulesToRemove.add(eventRule); + } + } + /* + * We cannot modify the map while iterating on it. We have to do the + * removal separately from the iteration above. + */ + for (EventRule rule : rulesToRemove) { + removeEventRule(rule); + } + } + + private synchronized void removeEventRule(EventRule eventRule) { + Integer count = enabledEventRules.get(eventRule); + if (count == null || count.intValue() <= 0) { + /* + * We were asked us to disable an event rule that was not enabled + * previously. Command error? + */ + throw new IllegalStateException(); + } + if (count.intValue() == 1) { + /* + * This is the last instance of this event rule being disabled, + * remove it from the map and send notifications of this rule being + * gone. + */ + enabledEventRules.remove(eventRule); + notifyForRemovedRule(eventRule); + return; + } + /* + * Other sessions/daemons are still looking for this event rule, simply + * decrement its refcount, and do not send notifications. + */ + enabledEventRules.put(eventRule, Integer.valueOf(count.intValue() - 1)); + + } + + /** + * Register a new listener to the manager. + * + * @param listener + * The listener to add + */ + public synchronized void registerListener(IFilterChangeListener listener) { + registeredListeners.add(listener); + + /* Send the current rules to the new listener ("statedump") */ + for (EventRule rule : enabledEventRules.keySet()) { + listener.eventRuleAdded(rule); + } + } + + /** + * Unregister a listener from the manager. + * + * @param listener + * The listener to remove + */ + public synchronized void unregisterListener(IFilterChangeListener listener) { + registeredListeners.remove(listener); + } + + private void notifyForAddedRule(final EventRule rule) { + for (IFilterChangeListener notifier : registeredListeners) { + notifier.eventRuleAdded(rule); + } + } + + private void notifyForRemovedRule(final EventRule rule) { + for (IFilterChangeListener notifier : registeredListeners) { + notifier.eventRuleRemoved(rule); + } + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/IFilterChangeListener.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/IFilterChangeListener.java new file mode 100644 index 00000000..e222b229 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/IFilterChangeListener.java @@ -0,0 +1,61 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.filter; + +import org.lttng.ust.agent.session.EventRule; + +/** + * Filter notification listener interface. + *

+ * Applications wanting to be notified of event filtering rule changes should + * implement this interface, then register their listener using + * {@link FilterChangeNotifier#registerListener}. + *

+ *

+ * The callbacks defined in this interface will be called whenever an event rule + * is added or removed. The manager will take care of the reference-counting in + * case multiple tracing sessions enable the exact same rules. For example, the + * {@link #eventRuleRemoved} callback is only called when there are no more + * session interested into it. + *

+ *

+ * Do not forget to unregister the listener after use, using + * {@link FilterChangeNotifier#unregisterListener}. If you do not, or if + * you use an anonymous listener for example, these will remain attached until + * the complete shutdown of the application. + *

+ *

+ * Only one thread is used to dispatch notifications, sequentially. This means + * that if a callback hangs it will prevent other listeners from receiving + * notifications. Please take care of not blocking inside the listener + * callbacks, and use separate threads for potentially long or blocking + * operations. + *

+ * + * @author Alexandre Montplaisir + */ +public interface IFilterChangeListener { + + /** + * Notification that a new event rule is now enabled in the tracing + * sessions. + * + * @param rule + * The event rule that was enabled + */ + void eventRuleAdded(EventRule rule); + + /** + * Notification that an existing event rule is now disabled in the tracing + * sessions. + * + * @param rule + * The event rule that was disabled + */ + void eventRuleRemoved(EventRule rule); +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/EventRule.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/EventRule.java new file mode 100644 index 00000000..dcf05a7e --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/EventRule.java @@ -0,0 +1,130 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.session; + +/** + * Event filtering rule present in a tracing session. + * + * It typically comes from a "lttng enable-event" command, and contains a + * domain, event name, log level and filter string. + * + * @author Alexandre Montplaisir + */ +public class EventRule { + + private final String eventName; + private final LogLevelSelector logLevelSelector; + private final String filterString; + + /** + * Constructor. + * + * @param eventName + * The name of the tracepoint + * @param logLevelSelector + * The log level of the event rule + * @param filterString + * The filtering string. May be null if there is no extra filter. + */ + public EventRule(String eventName, LogLevelSelector logLevelSelector, String filterString) { + this.eventName = eventName; + this.logLevelSelector = logLevelSelector; + this.filterString = filterString; + } + + /** + * Get the event name of this rule. + * + * @return The event name + */ + public String getEventName() { + return eventName; + } + + /** + * Get the log level filter configuration of the rule. + * + * @return The log level selector + */ + public LogLevelSelector getLogLevelSelector() { + return logLevelSelector; + } + + /** + * Get the filter string associated with this rule. + * + * @return The filter string, may be null for no filter string. + */ + public String getFilterString() { + return filterString; + } + + // ------------------------------------------------------------------------ + // Methods from Object + // ------------------------------------------------------------------------ + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((eventName == null) ? 0 : eventName.hashCode()); + result = prime * result + ((filterString == null) ? 0 : filterString.hashCode()); + result = prime * result + ((logLevelSelector == null) ? 0 : logLevelSelector.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + EventRule other = (EventRule) obj; + + if (eventName == null) { + if (other.eventName != null) { + return false; + } + } else if (!eventName.equals(other.eventName)) { + return false; + } + /* else, continue */ + + if (filterString == null) { + if (other.filterString != null) { + return false; + } + } else if (!filterString.equals(other.filterString)) { + return false; + } + /* else, continue */ + + if (logLevelSelector == null) { + if (other.logLevelSelector != null) { + return false; + } + } else if (!logLevelSelector.equals(other.logLevelSelector)) { + return false; + } + /* else, continue */ + + return true; + } + + @Override + public String toString() { + return "Event name = " + getEventName() + + ", Log level selector = (" + getLogLevelSelector().toString() + ")" + + ", Filter string = " + getFilterString(); + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/LogLevelSelector.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/LogLevelSelector.java new file mode 100644 index 00000000..c25ec81d --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/LogLevelSelector.java @@ -0,0 +1,189 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.session; + +/** + * Log level filtering element, which is part of an {@link EventRule}. + * + * @author Alexandre Montplaisir + */ +public class LogLevelSelector { + + /** + * The type of log level filter that is enabled. + * + * Defined from lttng-tools' include/lttng/event.h. + */ + public enum LogLevelType { + /** + * All log levels are enabled. This overrides the value of + * {@link LogLevelSelector#getLogLevel}. + */ + LTTNG_EVENT_LOGLEVEL_ALL(0), + + /** This log level along with all log levels of higher severity are enabled. */ + LTTNG_EVENT_LOGLEVEL_RANGE(1), + + /** Only this exact log level is enabled. */ + LTTNG_EVENT_LOGLEVEL_SINGLE(2); + + private final int value; + + private LogLevelType(int value) { + this.value = value; + } + + /** + * Get the numerical (int) value representing this log level type in the + * communication protocol. + * + * @return The int value + */ + public int getValue() { + return value; + } + + static LogLevelType fromValue(int val) { + switch (val) { + case 0: + return LTTNG_EVENT_LOGLEVEL_ALL; + case 1: + return LTTNG_EVENT_LOGLEVEL_RANGE; + case 2: + return LTTNG_EVENT_LOGLEVEL_SINGLE; + default: + throw new IllegalArgumentException(); + } + } + } + + private final int logLevel; + private final LogLevelType logLevelType; + + /** + * Constructor using numerical values straight from the communication + * protocol. + * + * @param logLevel + * The numerical value of the log level. The exact value depends + * on the tracing domain, see include/lttng/event.h in the + * lttng-tools tree for the complete enumeration. + * @param logLevelType + * The numerical value of the log level type. It will be + * converted to a {@link LogLevelType} by this constructor. + * @throws IllegalArgumentException + * If the 'logLevelType' does not correspond to a valid value. + */ + public LogLevelSelector(int logLevel, int logLevelType) { + this.logLevel = logLevel; + this.logLevelType = LogLevelType.fromValue(logLevelType); + } + + /** + * "Manual" constructor, specifying the {@link LogLevelType} directly. + * + * @param logLevel + * The numerical value of the log level. The exact value depends + * on the tracing domain, see include/lttng/event.h in the + * lttng-tools tree for the complete enumeration. + * @param type + * The log level filter type. + */ + public LogLevelSelector(int logLevel, LogLevelType type) { + this.logLevel = logLevel; + this.logLevelType = type; + } + + /** + * Get the numerical value of the log level element. Does not apply if + * {@link #getLogLevelType} returns + * {@link LogLevelType#LTTNG_EVENT_LOGLEVEL_ALL}. + * + * @return The numerical value of the log level + */ + public int getLogLevel() { + return logLevel; + } + + /** + * Get the log level filter type. + * + * @return The log level filter type + */ + public LogLevelType getLogLevelType() { + return logLevelType; + } + + /** + * Helper method to determine if an event with the given log level should be + * traced when considering this filter. + * + * For example, if this filter object represents "higher severity than 5", + * and the log level passed in parameter is "8", it will return that it + * matches (higher value means higher severity). + * + * @param targetLogLevel + * The log level value of the event to check for + * @return Should this event be traced, or not + */ + public boolean matches(int targetLogLevel) { + switch (logLevelType) { + case LTTNG_EVENT_LOGLEVEL_ALL: + return true; + case LTTNG_EVENT_LOGLEVEL_RANGE: + return (targetLogLevel >= logLevel); + case LTTNG_EVENT_LOGLEVEL_SINGLE: + return (targetLogLevel == logLevel); + default: + throw new IllegalStateException(); + } + } + + // ------------------------------------------------------------------------ + // Methods from Object + // ------------------------------------------------------------------------ + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + logLevel; + result = prime * result + ((logLevelType == null) ? 0 : logLevelType.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LogLevelSelector other = (LogLevelSelector) obj; + + if (logLevel != other.logLevel) { + return false; + } + if (logLevelType != other.logLevelType) { + return false; + } + return true; + } + + @Override + public String toString() { + if (getLogLevelType() == LogLevelType.LTTNG_EVENT_LOGLEVEL_ALL) { + return LogLevelType.LTTNG_EVENT_LOGLEVEL_ALL.toString(); + } + return String.valueOf(getLogLevel()) + ", " + getLogLevelType().toString(); + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/utils/LttngUstAgentLogger.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/utils/LttngUstAgentLogger.java new file mode 100644 index 00000000..3e78553b --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/utils/LttngUstAgentLogger.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2016 EfficiOS Inc. + * Copyright (C) 2016 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.utils; + +/** + * Logging infrastructure for the lttng-ust Java agent. It prints log messages + * to stderr but only when the environment variable LTTNG_UST_DEBUG is defined. + * + * @author Alexandre Montplaisir + */ +public class LttngUstAgentLogger { + + private static final String ENV_VAR_NAME = "LTTNG_UST_DEBUG"; + private static final boolean LOGGING_ENABLED = (System.getenv(ENV_VAR_NAME) == null ? false : true); + + /** + * Log event. Will be printed to stderr if the environment variable + * "LTTNG_UST_DEBUG" is defined. + * + * @param c + * The class logging the message (should normally be called with + * {@link #getClass()}). + * @param message + * The message to print + */ + public static void log(Class c, String message) { + if (LOGGING_ENABLED) { + System.err.println(c.getSimpleName() + ": " + message); + } + } +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile.am b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile.am new file mode 100644 index 00000000..91ac2035 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile.am @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: LGPL-2.1-only + +JAVAROOT = . +AM_JAVACFLAGS = -classpath $(CLASSPATH):$(builddir)/../lttng-ust-agent-common/lttng-ust-agent-common.jar + +pkgpath = org/lttng/ust/agent/jul + +jarfile_version = 1.0.0 +jarfile_manifest = $(srcdir)/Manifest.txt +jarfile_symlink = lttng-ust-agent-jul.jar +jarfile = lttng-ust-agent-jul-$(jarfile_version).jar + +jardir = $(datadir)/java + +juljniout = ../../jni/jul + +dist_noinst_JAVA = $(pkgpath)/LttngJulAgent.java \ + $(pkgpath)/LttngJulApi.java \ + $(pkgpath)/LttngLogHandler.java + +dist_noinst_DATA = $(jarfile_manifest) + +jar_DATA = $(jarfile) + +stamp = jul-jni-header.stamp +classes = $(pkgpath)/*.class + +$(jarfile): classnoinst.stamp + $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink) + +if !HAVE_JAVAH +# If we don't have javah, assume we are running openjdk >= 10 and use javac +# to generate the jni header file. +AM_JAVACFLAGS += -h $(juljniout) +else +jul-jni-header.stamp: $(dist_noinst_JAVA) + $(JAVAH) -classpath $(CLASSPATH):$(srcdir) -d $(juljniout) $(JAVAHFLAGS) org.lttng.ust.agent.jul.LttngJulApi && \ + echo "JUL JNI header generated" > jul-jni-header.stamp + +all-local: $(stamp) +endif + +install-data-hook: + cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink) + +uninstall-hook: + cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) + +CLEANFILES = *.jar \ + $(pkgpath)/*.class \ + jul-jni-header.stamp \ + $(juljniout)/org_lttng_ust_agent_jul_LttngJulApi.h diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/Manifest.txt b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/Manifest.txt new file mode 100644 index 00000000..4aba3600 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/Manifest.txt @@ -0,0 +1,8 @@ +Name: org/lttng/ust/agent/jul/ +Specification-Title: LTTng UST Java Agent JUL Integration +Specification-Version: 1.0.0 +Specification-Vendor: LTTng Project +Implementation-Title: org.lttng.ust.agent.jul +Implementation-Version: 1.0.0 +Implementation-Vendor: LTTng Project +Class-Path: lttng-ust-agent-common.jar diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulAgent.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulAgent.java new file mode 100644 index 00000000..99c5fde0 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulAgent.java @@ -0,0 +1,91 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.jul; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Handler; +import java.util.logging.LogManager; +import java.util.logging.Logger; + +import org.lttng.ust.agent.AbstractLttngAgent; + +/** + * Agent implementation for tracing from JUL loggers. + * + * @author Alexandre Montplaisir + */ +class LttngJulAgent extends AbstractLttngAgent { + + private static LttngJulAgent instance = null; + + private LttngJulAgent() { + super(Domain.JUL); + } + + public static synchronized LttngJulAgent getInstance() { + if (instance == null) { + instance = new LttngJulAgent(); + } + return instance; + } + + @Override + public Collection listAvailableEvents() { + Set ret = new TreeSet(); + + List loggersNames = Collections.list(LogManager.getLogManager().getLoggerNames()); + for (String name : loggersNames) { + /* + * Skip the root logger. An empty string is not a valid event name + * in LTTng. + */ + if (name.equals("") || name.equals("global")) { + continue; + } + + /* + * Check if that logger has at least one LTTng JUL handler attached. + */ + Logger logger = Logger.getLogger(name); + if (hasLttngHandlerAttached(logger)) { + ret.add(name); + } + } + + return ret; + } + + private static boolean hasLttngHandlerAttached(Logger logger) { + for (Handler handler : logger.getHandlers()) { + if (handler instanceof LttngLogHandler) { + return true; + } + } + + /* + * A parent logger, if any, may be connected to an LTTng handler. In + * this case, we will want to include this child logger in the output, + * since it will be accessible by LTTng. + */ + Logger parent = logger.getParent(); + if (parent != null) { + return hasLttngHandlerAttached(parent); + } + + /* + * We have reached the root logger and have not found any LTTng handler, + * this event will not be accessible. + */ + return false; + } + +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulApi.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulApi.java new file mode 100644 index 00000000..07b0cde0 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulApi.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2016 EfficiOS Inc. + * Copyright (C) 2016 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.jul; + +/** + * Virtual class containing the Java side of the LTTng-JUL JNI API methods. + * + * @author Alexandre Montplaisir + */ +final class LttngJulApi { + + private LttngJulApi() {} + + static native void tracepoint(String msg, + String logger_name, + String class_name, + String method_name, + long millis, + int log_level, + int thread_id); + + static native void tracepointWithContext(String msg, + String logger_name, + String class_name, + String method_name, + long millis, + int log_level, + int thread_id, + byte[] contextEntries, + byte[] contextStrings); +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngLogHandler.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngLogHandler.java new file mode 100644 index 00000000..42bea9c4 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngLogHandler.java @@ -0,0 +1,136 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + * Copyright (C) 2013 David Goulet + */ + +package org.lttng.ust.agent.jul; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.LogRecord; + +import org.lttng.ust.agent.ILttngAgent; +import org.lttng.ust.agent.ILttngHandler; +import org.lttng.ust.agent.context.ContextInfoSerializer; + +/** + * LTTng-UST JUL log handler. + * + * Applications can attach this handler to their + * {@link java.util.logging.Logger} to have it generate UST events from logging + * events received through the logger. + * + * It sends its events to UST via the JNI library "liblttng-ust-jul-jni.so". + * Make sure this library is available before using this handler. + * + * @author Alexandre Montplaisir + * @author David Goulet + */ +public class LttngLogHandler extends Handler implements ILttngHandler { + + private static final String SHARED_OBJECT_NAME = "lttng-ust-jul-jni"; + + /** + * Dummy Formatter object, so we can use its + * {@link Formatter#formatMessage(LogRecord)} method. + */ + private static final Formatter FORMATTER = new Formatter() { + @Override + public String format(LogRecord record) { + throw new UnsupportedOperationException(); + } + }; + + private final ILttngAgent agent; + + /** Number of events logged (really sent through JNI) by this handler */ + private final AtomicLong eventCount = new AtomicLong(0); + + /** + * Constructor + * + * @throws IOException + * This handler requires the lttng-ust-jul-jni.so native + * library, through which it will send the trace events. This + * exception is throw is this library cannot be found. + * @throws SecurityException + * We will forward any SecurityExcepion that may be thrown when + * trying to load the JNI library. + */ + public LttngLogHandler() throws IOException, SecurityException { + super(); + /* Initialize LTTng UST tracer. */ + try { + System.loadLibrary(SHARED_OBJECT_NAME); //$NON-NLS-1$ + } catch (UnsatisfiedLinkError e) { + throw new IOException(e); + } + + /** Register to the relevant agent */ + agent = LttngJulAgent.getInstance(); + agent.registerHandler(this); + } + + @Override + public synchronized void close() { + agent.unregisterHandler(this); + } + + /** + * Get the number of events logged by this handler so far. This means the + * number of events actually sent through JNI to UST. + * + * @return The number of events logged so far + */ + @Override + public long getEventCount() { + return eventCount.get(); + } + + @Override + public void flush() { + } + + @Override + public void publish(LogRecord record) { + /* + * Check if the current message should be logged, according to the UST + * session settings. + */ + if (!agent.isEventEnabled(record.getLoggerName())) { + return; + } + + String formattedMessage = FORMATTER.formatMessage(record); + + /* Retrieve all the requested context information we can find */ + Collection>> enabledContexts = agent.getEnabledAppContexts(); + ContextInfoSerializer.SerializedContexts contextInfo = ContextInfoSerializer.queryAndSerializeRequestedContexts(enabledContexts); + + eventCount.incrementAndGet(); + + /* + * Specific tracepoint designed for JUL events. The source class of the + * caller is used for the event name, the raw message is taken, the + * loglevel of the record and the thread ID. + */ + LttngJulApi.tracepointWithContext(formattedMessage, + record.getLoggerName(), + record.getSourceClassName(), + record.getSourceMethodName(), + record.getMillis(), + record.getLevel().intValue(), + record.getThreadID(), + contextInfo.getEntriesArray(), + contextInfo.getStringsArray()); + } + +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile.am b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile.am new file mode 100644 index 00000000..009f1416 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile.am @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: LGPL-2.1-only + +JAVAROOT = . +AM_JAVACFLAGS = -classpath $(CLASSPATH):$(builddir)/../lttng-ust-agent-common/lttng-ust-agent-common.jar + +pkgpath = org/lttng/ust/agent/log4j + +jarfile_version = 1.0.0 +jarfile_manifest = $(srcdir)/Manifest.txt +jarfile_symlink = lttng-ust-agent-log4j.jar +jarfile = lttng-ust-agent-log4j-$(jarfile_version).jar + +jardir = $(datadir)/java + +log4jjniout = ../../jni/log4j + +dist_noinst_JAVA = $(pkgpath)/LttngLog4jAgent.java \ + $(pkgpath)/LttngLog4jApi.java \ + $(pkgpath)/LttngLogAppender.java + +dist_noinst_DATA = $(jarfile_manifest) + +jar_DATA = $(jarfile) + +stamp = log4j-jni-header.stamp +classes = $(pkgpath)/*.class + +$(jarfile): classnoinst.stamp + $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink) + +if !HAVE_JAVAH +# If we don't have javah, assume we are running openjdk >= 10 and use javac +# to generate the jni header file. +AM_JAVACFLAGS += -h $(log4jjniout) +else +log4j-jni-header.stamp: $(dist_noinst_JAVA) + $(JAVAH) -classpath $(CLASSPATH):$(srcdir) -d $(log4jjniout) $(JAVAHFLAGS) org.lttng.ust.agent.log4j.LttngLog4jApi && \ + echo "Log4j JNI header generated" > log4j-jni-header.stamp + +all-local: $(stamp) +endif + +install-data-hook: + cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink) + +uninstall-hook: + cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) + +CLEANFILES = *.jar \ + $(pkgpath)/*.class \ + log4j-jni-header.stamp \ + $(log4jjniout)/org_lttng_ust_agent_log4j_LttngLog4jApi.h diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/Manifest.txt b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/Manifest.txt new file mode 100644 index 00000000..d7b98f42 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/Manifest.txt @@ -0,0 +1,8 @@ +Name: org/lttng/ust/agent/log4j/ +Specification-Title: LTTng UST Java Agent Log4J 1.x Integration +Specification-Version: 1.0.0 +Specification-Vendor: LTTng Project +Implementation-Title: org.lttng.ust.agent.log4j +Implementation-Version: 1.0.0 +Implementation-Vendor: LTTng Project +Class-Path: lttng-ust-agent-common.jar diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jAgent.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jAgent.java new file mode 100644 index 00000000..bb5deb35 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jAgent.java @@ -0,0 +1,95 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.log4j; + +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.log4j.Appender; +import org.apache.log4j.Category; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.lttng.ust.agent.AbstractLttngAgent; + +/** + * Agent implementation for using the Log4j logger, connecting to a root session + * daemon. + * + * @author Alexandre Montplaisir + */ +class LttngLog4jAgent extends AbstractLttngAgent { + + private static LttngLog4jAgent instance = null; + + private LttngLog4jAgent() { + super(Domain.LOG4J); + } + + public static synchronized LttngLog4jAgent getInstance() { + if (instance == null) { + instance = new LttngLog4jAgent(); + } + return instance; + } + + @Override + public Collection listAvailableEvents() { + Set ret = new TreeSet(); + + @SuppressWarnings("unchecked") + List loggers = Collections.list(LogManager.getCurrentLoggers()); + for (Logger logger : loggers) { + if (logger == null) { + continue; + } + + /* + * Check if that logger has at least one LTTng log4j appender + * attached. + */ + if (hasLttngAppenderAttached(logger)) { + ret.add(logger.getName()); + } + } + + return ret; + } + + private static boolean hasLttngAppenderAttached(Category logger) { + @SuppressWarnings("unchecked") + Enumeration appenders = logger.getAllAppenders(); + if (appenders != null) { + for (Appender appender : Collections.list(appenders)) { + if (appender instanceof LttngLogAppender) { + return true; + } + } + } + + /* + * A parent logger, if any, may be connected to an LTTng handler. In + * this case, we will want to include this child logger in the output, + * since it will be accessible by LTTng. + */ + Category parent = logger.getParent(); + if (parent != null) { + return hasLttngAppenderAttached(parent); + } + + /* + * We have reached the root logger and have not found any LTTng handler, + * this event will not be accessible. + */ + return false; + } + +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jApi.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jApi.java new file mode 100644 index 00000000..c3e76eec --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jApi.java @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2016 EfficiOS Inc. + * Copyright (C) 2016 Alexandre Montplaisir + */ + +package org.lttng.ust.agent.log4j; + +/** + * Virtual class containing the Java side of the LTTng-log4j JNI API methods. + * + * @author Alexandre Montplaisir + */ +final class LttngLog4jApi { + + private LttngLog4jApi() {} + + static native void tracepoint(String msg, + String logger_name, + String class_name, + String method_name, + String file_name, + int line_number, + long timestamp, + int loglevel, + String thread_name); + + static native void tracepointWithContext(String msg, + String logger_name, + String class_name, + String method_name, + String file_name, + int line_number, + long timestamp, + int loglevel, + String thread_name, + byte[] contextEntries, + byte[] contextStrings); +} diff --git a/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLogAppender.java b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLogAppender.java new file mode 100644 index 00000000..c232fb8b --- /dev/null +++ b/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLogAppender.java @@ -0,0 +1,132 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir + * Copyright (C) 2014 Christian Babeux + */ + +package org.lttng.ust.agent.log4j; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.spi.LoggingEvent; +import org.lttng.ust.agent.ILttngAgent; +import org.lttng.ust.agent.ILttngHandler; +import org.lttng.ust.agent.context.ContextInfoSerializer; + +/** + * LTTng-UST Log4j 1.x log handler. + * + * Applications can attach this appender to their + * {@link org.apache.log4j.Logger} to have it generate UST events from logging + * events received through the logger. + * + * It sends its events to UST via the JNI library "liblttng-ust-log4j-jni.so". + * Make sure this library is available before using this appender. + * + * @author Alexandre Montplaisir + * @author Christian Babeux + */ +public class LttngLogAppender extends AppenderSkeleton implements ILttngHandler { + + private static final String SHARED_OBJECT_NAME = "lttng-ust-log4j-jni"; + + private final AtomicLong eventCount = new AtomicLong(0); + + private final ILttngAgent agent; + + + /** + * Constructor + * + * @throws IOException + * This handler requires the lttng-ust-log4j-jni.so native + * library, through which it will send the trace events. This + * exception is throw is this library cannot be found. + * @throws SecurityException + * We will forward any SecurityExcepion that may be thrown when + * trying to load the JNI library. + */ + public LttngLogAppender() throws IOException, SecurityException { + super(); + /* Initialize LTTng UST tracer. */ + try { + System.loadLibrary(SHARED_OBJECT_NAME); // $NON-NLS-1$ + } catch (UnsatisfiedLinkError e) { + throw new IOException(e); + } + + /** Register to the relevant agent */ + agent = LttngLog4jAgent.getInstance(); + agent.registerHandler(this); + } + + @Override + public synchronized void close() { + agent.unregisterHandler(this); + } + + /** + * Get the number of events logged by this handler so far. This means the + * number of events actually sent through JNI to UST. + * + * @return The number of events logged so far + */ + @Override + public long getEventCount() { + return eventCount.get(); + } + + @Override + public boolean requiresLayout() { + return false; + } + + @Override + protected void append(LoggingEvent event) { + /* + * Check if the current message should be logged, according to the UST + * session settings. + */ + if (!agent.isEventEnabled(event.getLoggerName())) { + return; + } + + /* + * The line number returned from LocationInformation is a string. At + * least try to convert to a proper int. + */ + int line; + try { + String lineString = event.getLocationInformation().getLineNumber(); + line = Integer.parseInt(lineString); + } catch (NumberFormatException n) { + line = -1; + } + + /* Retrieve all the requested context information we can find */ + Collection>> enabledContexts = agent.getEnabledAppContexts(); + ContextInfoSerializer.SerializedContexts contextInfo = ContextInfoSerializer.queryAndSerializeRequestedContexts(enabledContexts); + + eventCount.incrementAndGet(); + + LttngLog4jApi.tracepointWithContext(event.getRenderedMessage(), + event.getLoggerName(), + event.getLocationInformation().getClassName(), + event.getLocationInformation().getMethodName(), + event.getLocationInformation().getFileName(), + line, + event.getTimeStamp(), + event.getLevel().toInt(), + event.getThreadName(), + contextInfo.getEntriesArray(), + contextInfo.getStringsArray()); + } + +} diff --git a/src/lib/lttng-ust-java-agent/jni/Makefile.am b/src/lib/lttng-ust-java-agent/jni/Makefile.am new file mode 100644 index 00000000..711fd475 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/jni/Makefile.am @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: LGPL-2.1-only + +SUBDIRS = common + +if ENABLE_JAVA_AGENT_WITH_JUL +SUBDIRS += jul +endif + +if ENABLE_JAVA_AGENT_WITH_LOG4J +SUBDIRS += log4j +endif diff --git a/src/lib/lttng-ust-java-agent/jni/common/Makefile.am b/src/lib/lttng-ust-java-agent/jni/common/Makefile.am new file mode 100644 index 00000000..c066157b --- /dev/null +++ b/src/lib/lttng-ust-java-agent/jni/common/Makefile.am @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: LGPL-2.1-only + +AM_CPPFLAGS += -I$(builddir) -I$(srcdir) $(JNI_CPPFLAGS) + +lib_LTLIBRARIES = liblttng-ust-context-jni.la +liblttng_ust_context_jni_la_SOURCES = lttng_ust_context.c lttng_ust_context.h + +nodist_liblttng_ust_context_jni_la_SOURCES = org_lttng_ust_agent_context_LttngContextApi.h + +liblttng_ust_context_jni_la_LIBADD = -lc \ + $(top_builddir)/src/liblttng-ust/liblttng-ust.la diff --git a/src/lib/lttng-ust-java-agent/jni/common/lttng_ust_context.c b/src/lib/lttng-ust-java-agent/jni/common/lttng_ust_context.c new file mode 100644 index 00000000..8570b211 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/jni/common/lttng_ust_context.c @@ -0,0 +1,397 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2016 EfficiOS Inc. + * Copyright (C) 2016 Alexandre Montplaisir + * Copyright (C) 2016 Mathieu Desnoyers + */ + +#include "org_lttng_ust_agent_context_LttngContextApi.h" + +#include +#include +#include +#include +#include + +#include "common/macros.h" +#include "lttng_ust_context.h" + +enum lttng_ust_jni_type { + JNI_TYPE_NULL = 0, + JNI_TYPE_INTEGER = 1, + JNI_TYPE_LONG = 2, + JNI_TYPE_DOUBLE = 3, + JNI_TYPE_FLOAT = 4, + JNI_TYPE_BYTE = 5, + JNI_TYPE_SHORT = 6, + JNI_TYPE_BOOLEAN = 7, + JNI_TYPE_STRING = 8, +}; + +struct lttng_ust_jni_ctx_entry { + int32_t context_name_offset; + char type; /* enum lttng_ust_jni_type */ + union { + int32_t _integer; + int64_t _long; + double _double; + float _float; + signed char _byte; + int16_t _short; + signed char _boolean; + int32_t _string_offset; + } value; +} __attribute__((packed)); + +struct lttng_ust_jni_provider { + struct lttng_ust_registered_context_provider *reg_provider; + char *name; + struct lttng_ust_context_provider provider; +}; + +/* TLS passing context info from JNI to callbacks. */ +__thread struct lttng_ust_jni_tls lttng_ust_context_info_tls; + +static const char *get_ctx_string_at_offset(int32_t offset) +{ + signed char *ctx_strings_array = lttng_ust_context_info_tls.ctx_strings; + + if (offset < 0 || offset >= lttng_ust_context_info_tls.ctx_strings_len) { + return NULL; + } + return (const char *) (ctx_strings_array + offset); +} + +static struct lttng_ust_jni_ctx_entry *lookup_ctx_by_name(const char *ctx_name) +{ + struct lttng_ust_jni_ctx_entry *ctx_entries_array = lttng_ust_context_info_tls.ctx_entries; + int i, len = lttng_ust_context_info_tls.ctx_entries_len / sizeof(struct lttng_ust_jni_ctx_entry); + + for (i = 0; i < len; i++) { + int32_t offset = ctx_entries_array[i].context_name_offset; + const char *string = get_ctx_string_at_offset(offset); + + if (string && strcmp(string, ctx_name) == 0) { + return &ctx_entries_array[i]; + } + } + return NULL; +} + +static size_t get_size_cb(void *priv, size_t offset) +{ + struct lttng_ust_jni_ctx_entry *jctx; + size_t size = 0; + struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv; + const char *ctx_name = jni_provider->name; + enum lttng_ust_jni_type jni_type; + + size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(char)); + size += sizeof(char); /* tag */ + jctx = lookup_ctx_by_name(ctx_name); + if (!jctx) { + jni_type = JNI_TYPE_NULL; + } else { + jni_type = jctx->type; + } + switch (jni_type) { + case JNI_TYPE_NULL: + break; + case JNI_TYPE_INTEGER: + size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(int32_t)); + size += sizeof(int32_t); /* variant */ + break; + case JNI_TYPE_LONG: + size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(int64_t)); + size += sizeof(int64_t); /* variant */ + break; + case JNI_TYPE_DOUBLE: + size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(double)); + size += sizeof(double); /* variant */ + break; + case JNI_TYPE_FLOAT: + size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(float)); + size += sizeof(float); /* variant */ + break; + case JNI_TYPE_SHORT: + size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(int16_t)); + size += sizeof(int16_t); /* variant */ + break; + case JNI_TYPE_BYTE: /* Fall-through. */ + case JNI_TYPE_BOOLEAN: + size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(char)); + size += sizeof(char); /* variant */ + break; + case JNI_TYPE_STRING: + { + /* The value is an offset, the string is in the "strings" array */ + int32_t string_offset = jctx->value._string_offset; + const char *string = get_ctx_string_at_offset(string_offset); + + if (string) { + size += strlen(string) + 1; + } + break; + } + default: + abort(); + } + return size; + +} + +static void record_cb(void *priv, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_ust_channel_buffer *lttng_chan_buf) +{ + struct lttng_ust_jni_ctx_entry *jctx; + struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv; + const char *ctx_name = jni_provider->name; + enum lttng_ust_jni_type jni_type; + char sel_char; + + jctx = lookup_ctx_by_name(ctx_name); + if (!jctx) { + jni_type = JNI_TYPE_NULL; + } else { + jni_type = jctx->type; + } + + switch (jni_type) { + case JNI_TYPE_NULL: + sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE; + lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); + break; + case JNI_TYPE_INTEGER: + { + int32_t v = jctx->value._integer; + + sel_char = LTTNG_UST_DYNAMIC_TYPE_S32; + lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); + lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); + break; + } + case JNI_TYPE_LONG: + { + int64_t v = jctx->value._long; + + sel_char = LTTNG_UST_DYNAMIC_TYPE_S64; + lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); + lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); + break; + } + case JNI_TYPE_DOUBLE: + { + double v = jctx->value._double; + + sel_char = LTTNG_UST_DYNAMIC_TYPE_DOUBLE; + lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); + lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); + break; + } + case JNI_TYPE_FLOAT: + { + float v = jctx->value._float; + + sel_char = LTTNG_UST_DYNAMIC_TYPE_FLOAT; + lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); + lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); + break; + } + case JNI_TYPE_SHORT: + { + int16_t v = jctx->value._short; + + sel_char = LTTNG_UST_DYNAMIC_TYPE_S16; + lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); + lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); + break; + } + case JNI_TYPE_BYTE: + { + char v = jctx->value._byte; + + sel_char = LTTNG_UST_DYNAMIC_TYPE_S8; + lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); + lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); + break; + } + case JNI_TYPE_BOOLEAN: + { + char v = jctx->value._boolean; + + sel_char = LTTNG_UST_DYNAMIC_TYPE_S8; + lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); + lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); + break; + } + case JNI_TYPE_STRING: + { + int32_t offset = jctx->value._string_offset; + const char *str = get_ctx_string_at_offset(offset); + + if (str) { + sel_char = LTTNG_UST_DYNAMIC_TYPE_STRING; + } else { + sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE; + } + lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); + if (str) { + lttng_chan_buf->ops->event_write(ctx, str, strlen(str) + 1, 1); + } + break; + } + default: + abort(); + } +} + +static void get_value_cb(void *priv, struct lttng_ust_ctx_value *value) +{ + struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv; + struct lttng_ust_jni_ctx_entry *jctx; + const char *ctx_name = jni_provider->name; + enum lttng_ust_jni_type jni_type; + + jctx = lookup_ctx_by_name(ctx_name); + if (!jctx) { + jni_type = JNI_TYPE_NULL; + } else { + jni_type = jctx->type; + } + + switch (jni_type) { + case JNI_TYPE_NULL: + value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE; + break; + case JNI_TYPE_INTEGER: + value->sel = LTTNG_UST_DYNAMIC_TYPE_S64; + value->u.s64 = (int64_t) jctx->value._integer; + break; + case JNI_TYPE_LONG: + value->sel = LTTNG_UST_DYNAMIC_TYPE_S64; + value->u.s64 = jctx->value._long; + break; + case JNI_TYPE_DOUBLE: + value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE; + value->u.d = jctx->value._double; + break; + case JNI_TYPE_FLOAT: + value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE; + value->u.d = (double) jctx->value._float; + break; + case JNI_TYPE_SHORT: + value->sel = LTTNG_UST_DYNAMIC_TYPE_S64; + value->u.s64 = (int64_t) jctx->value._short; + break; + case JNI_TYPE_BYTE: + value->sel = LTTNG_UST_DYNAMIC_TYPE_S64; + value->u.s64 = (int64_t) jctx->value._byte; + break; + case JNI_TYPE_BOOLEAN: + value->sel = LTTNG_UST_DYNAMIC_TYPE_S64; + value->u.s64 = (int64_t) jctx->value._boolean; + break; + case JNI_TYPE_STRING: + { + int32_t offset = jctx->value._string_offset; + const char *str = get_ctx_string_at_offset(offset); + + if (str) { + value->sel = LTTNG_UST_DYNAMIC_TYPE_STRING; + value->u.str = str; + } else { + value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE; + } + break; + } + default: + abort(); + } +} + +/* + * Register a context provider to UST. + * + * Called from the Java side when an application registers a context retriever, + * so we create and register a corresponding provider on the C side. + */ +JNIEXPORT jlong JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv *env, + jobject jobj __attribute__((unused)), + jstring provider_name) +{ + jboolean iscopy; + const char *provider_name_jstr; + char *provider_name_cstr; + struct lttng_ust_context_provider *provider; + struct lttng_ust_jni_provider *jni_provider; + /* + * Note: a "jlong" is 8 bytes on all architectures, whereas a + * C "long" varies. + */ + jlong provider_ref; + + provider_name_jstr = (*env)->GetStringUTFChars(env, provider_name, &iscopy); + if (!provider_name_jstr) { + goto error_jstr; + } + /* Keep our own copy of the string so UST can use it. */ + provider_name_cstr = strdup(provider_name_jstr); + (*env)->ReleaseStringUTFChars(env, provider_name, provider_name_jstr); + if (!provider_name_cstr) { + goto error_strdup; + } + jni_provider = zmalloc(sizeof(*jni_provider)); + if (!jni_provider) { + goto error_provider; + } + provider = &jni_provider->provider; + provider->struct_size = sizeof(*provider); + jni_provider->name = provider_name_cstr; + provider->name = jni_provider->name; + provider->get_size = get_size_cb; + provider->record = record_cb; + provider->get_value = get_value_cb; + provider->priv = jni_provider; + + jni_provider->reg_provider = lttng_ust_context_provider_register(provider); + if (!jni_provider->reg_provider) { + goto error_register; + } + + provider_ref = (jlong) (long) jni_provider; + return provider_ref; + + /* Error handling. */ +error_register: + free(jni_provider); +error_provider: + free(provider_name_cstr); +error_strdup: +error_jstr: + return 0; +} + +/* + * Unregister a previously-registered context provider. + * + * Called from the Java side when an application unregisters a context retriever, + * so we unregister and delete the corresponding provider on the C side. + */ +JNIEXPORT void JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv *env __attribute__((unused)), + jobject jobj __attribute__((unused)), + jlong provider_ref) +{ + struct lttng_ust_jni_provider *jni_provider = + (struct lttng_ust_jni_provider *) (unsigned long) provider_ref; + + if (!jni_provider) { + return; + } + + lttng_ust_context_provider_unregister(jni_provider->reg_provider); + + free(jni_provider->name); + free(jni_provider); +} diff --git a/src/lib/lttng-ust-java-agent/jni/common/lttng_ust_context.h b/src/lib/lttng-ust-java-agent/jni/common/lttng_ust_context.h new file mode 100644 index 00000000..ab003c89 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/jni/common/lttng_ust_context.h @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2016 EfficiOS Inc. + * Copyright (C) 2016 Alexandre Montplaisir + */ + +#ifndef LIBLTTNG_UST_JAVA_AGENT_JNI_COMMON_LTTNG_UST_CONTEXT_H_ +#define LIBLTTNG_UST_JAVA_AGENT_JNI_COMMON_LTTNG_UST_CONTEXT_H_ + +struct lttng_ust_jni_ctx_entry; + +struct lttng_ust_jni_tls { + struct lttng_ust_jni_ctx_entry *ctx_entries; + int32_t ctx_entries_len; + signed char *ctx_strings; + int32_t ctx_strings_len; +}; + +extern __thread struct lttng_ust_jni_tls lttng_ust_context_info_tls; + +#endif /* LIBLTTNG_UST_JAVA_AGENT_JNI_COMMON_LTTNG_UST_CONTEXT_H_ */ diff --git a/src/lib/lttng-ust-java-agent/jni/jul/Makefile.am b/src/lib/lttng-ust-java-agent/jni/jul/Makefile.am new file mode 100644 index 00000000..295b033d --- /dev/null +++ b/src/lib/lttng-ust-java-agent/jni/jul/Makefile.am @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: LGPL-2.1-only + +AM_CPPFLAGS += -I$(builddir) -I$(srcdir) $(JNI_CPPFLAGS) + +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_LttngJulApi.h + +liblttng_ust_jul_jni_la_LIBADD = -lc \ + $(top_builddir)/src/liblttng-ust/liblttng-ust.la \ + $(top_builddir)/src/lib/lttng-ust-java-agent/jni/common/liblttng-ust-context-jni.la diff --git a/src/lib/lttng-ust-java-agent/jni/jul/lttng_ust_jul.c b/src/lib/lttng-ust-java-agent/jni/jul/lttng_ust_jul.c new file mode 100644 index 00000000..afc9f111 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/jni/jul/lttng_ust_jul.c @@ -0,0 +1,92 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2016 EfficiOS Inc. + * Copyright (C) 2016 Alexandre Montplaisir + * Copyright (C) 2011-2012 Mathieu Desnoyers + */ + +#define _LGPL_SOURCE +#include "org_lttng_ust_agent_jul_LttngJulApi.h" + +#define TRACEPOINT_DEFINE +#define TRACEPOINT_CREATE_PROBES +#include "lttng_ust_jul.h" +#include "../common/lttng_ust_context.h" + +/* + * Deprecated function from before the context information was passed. + */ +JNIEXPORT void JNICALL Java_org_lttng_ust_agent_jul_LttngJulApi_tracepoint(JNIEnv *env, + jobject jobj __attribute__((unused)), + 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, 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); +} + +/* + * Tracepoint used by Java applications using the JUL handler. + */ +JNIEXPORT void JNICALL Java_org_lttng_ust_agent_jul_LttngJulApi_tracepointWithContext(JNIEnv *env, + jobject jobj __attribute__((unused)), + jstring msg, + jstring logger_name, + jstring class_name, + jstring method_name, + jlong millis, + jint log_level, + jint thread_id, + jbyteArray context_info_entries, + jbyteArray context_info_strings) +{ + 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); + signed char *context_info_entries_array; + signed char *context_info_strings_array; + + /* + * Write these to the TLS variables, so that the UST callbacks in + * lttng_ust_context.c can access them. + */ + context_info_entries_array = (*env)->GetByteArrayElements(env, context_info_entries, &iscopy); + lttng_ust_context_info_tls.ctx_entries = (struct lttng_ust_jni_ctx_entry *) context_info_entries_array; + lttng_ust_context_info_tls.ctx_entries_len = (*env)->GetArrayLength(env, context_info_entries); + context_info_strings_array = (*env)->GetByteArrayElements(env, context_info_strings, &iscopy); + lttng_ust_context_info_tls.ctx_strings = context_info_strings_array; + lttng_ust_context_info_tls.ctx_strings_len = (*env)->GetArrayLength(env, context_info_strings); + + tracepoint(lttng_jul, event, msg_cstr, logger_name_cstr, + class_name_cstr, method_name_cstr, millis, log_level, thread_id); + + lttng_ust_context_info_tls.ctx_entries = NULL; + lttng_ust_context_info_tls.ctx_entries_len = 0; + lttng_ust_context_info_tls.ctx_strings = NULL; + lttng_ust_context_info_tls.ctx_strings_len = 0; + (*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)->ReleaseByteArrayElements(env, context_info_entries, context_info_entries_array, 0); + (*env)->ReleaseByteArrayElements(env, context_info_strings, context_info_strings_array, 0); +} diff --git a/src/lib/lttng-ust-java-agent/jni/jul/lttng_ust_jul.h b/src/lib/lttng-ust-java-agent/jni/jul/lttng_ust_jul.h new file mode 100644 index 00000000..13003bf2 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/jni/jul/lttng_ust_jul.h @@ -0,0 +1,44 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2011 Mathieu Desnoyers + */ + +#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 + +#include + +/* + * Tracepoint used by Java applications using the JUL handler. + */ +TRACEPOINT_EVENT(lttng_jul, 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/src/lib/lttng-ust-java-agent/jni/log4j/Makefile.am b/src/lib/lttng-ust-java-agent/jni/log4j/Makefile.am new file mode 100644 index 00000000..029462e9 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/jni/log4j/Makefile.am @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: LGPL-2.1-only + +AM_CPPFLAGS += -I$(builddir) -I$(srcdir) $(JNI_CPPFLAGS) + +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_LttngLog4jApi.h + +liblttng_ust_log4j_jni_la_LIBADD = -lc \ + $(top_builddir)/src/liblttng-ust/liblttng-ust.la \ + $(top_builddir)/src/lib/lttng-ust-java-agent/jni/common/liblttng-ust-context-jni.la diff --git a/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c b/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c new file mode 100644 index 00000000..e88235a6 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c @@ -0,0 +1,106 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2016 EfficiOS Inc. + * Copyright (C) 2016 Alexandre Montplaisir + * Copyright (C) 2011-2012 Mathieu Desnoyers + */ + +#define _LGPL_SOURCE +#include "org_lttng_ust_agent_log4j_LttngLog4jApi.h" + +#define TRACEPOINT_DEFINE +#define TRACEPOINT_CREATE_PROBES +#include "lttng_ust_log4j.h" +#include "../common/lttng_ust_context.h" + +/* + * Deprecated function from before the context information was passed. + */ +JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j_LttngLog4jApi_tracepoint(JNIEnv *env, + jobject jobj __attribute__((unused)), + 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, 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); +} + +/* + * Tracepoint used by Java applications using the log4j handler. + */ +JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j_LttngLog4jApi_tracepointWithContext(JNIEnv *env, + jobject jobj __attribute__((unused)), + jstring msg, + jstring logger_name, + jstring class_name, + jstring method_name, + jstring file_name, + jint line_number, + jlong timestamp, + jint loglevel, + jstring thread_name, + jbyteArray context_info_entries, + jbyteArray context_info_strings) +{ + 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); + signed char *context_info_entries_array; + signed char *context_info_strings_array; + + /* + * Write these to the TLS variables, so that the UST callbacks in + * lttng_ust_context.c can access them. + */ + context_info_entries_array = (*env)->GetByteArrayElements(env, context_info_entries, &iscopy); + lttng_ust_context_info_tls.ctx_entries = (struct lttng_ust_jni_ctx_entry *) context_info_entries_array; + lttng_ust_context_info_tls.ctx_entries_len = (*env)->GetArrayLength(env, context_info_entries); + context_info_strings_array = (*env)->GetByteArrayElements(env, context_info_strings, &iscopy); + lttng_ust_context_info_tls.ctx_strings = context_info_strings_array; + lttng_ust_context_info_tls.ctx_strings_len = (*env)->GetArrayLength(env, context_info_strings); + + tracepoint(lttng_log4j, event, msg_cstr, logger_name_cstr, + class_name_cstr, method_name_cstr, file_name_cstr, + line_number, timestamp, loglevel, thread_name_cstr); + + lttng_ust_context_info_tls.ctx_entries = NULL; + lttng_ust_context_info_tls.ctx_entries_len = 0; + lttng_ust_context_info_tls.ctx_strings = NULL; + lttng_ust_context_info_tls.ctx_strings_len = 0; + (*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); + (*env)->ReleaseByteArrayElements(env, context_info_entries, context_info_entries_array, 0); + (*env)->ReleaseByteArrayElements(env, context_info_strings, context_info_strings_array, 0); +} diff --git a/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h b/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h new file mode 100644 index 00000000..c7d7d525 --- /dev/null +++ b/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2011 Mathieu Desnoyers + */ + +#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 + +#include + +/* + * Tracepoint used by Java applications using the log4j log appender. + */ +TRACEPOINT_EVENT(lttng_log4j, 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/src/lib/lttng-ust-java/.gitignore b/src/lib/lttng-ust-java/.gitignore new file mode 100644 index 00000000..e07ee503 --- /dev/null +++ b/src/lib/lttng-ust-java/.gitignore @@ -0,0 +1,3 @@ +org_lttng_ust_LTTngUst.h +org/ +liblttng-ust-java.jar diff --git a/src/lib/lttng-ust-java/LTTngUst.c b/src/lib/lttng-ust-java/LTTngUst.c new file mode 100644 index 00000000..f5e0c96b --- /dev/null +++ b/src/lib/lttng-ust-java/LTTngUst.c @@ -0,0 +1,82 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2011-2012 Mathieu Desnoyers + */ + +#define _LGPL_SOURCE +#include "org_lttng_ust_LTTngUst.h" + +#define TRACEPOINT_DEFINE +#define TRACEPOINT_CREATE_PROBES +#include "lttng_ust_java.h" + +JNIEXPORT void JNICALL Java_org_lttng_ust_LTTngUst_tracepointInt(JNIEnv *env, + jobject jobj __attribute__((unused)), + jstring ev_name, + jint payload) +{ + jboolean iscopy; + const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, &iscopy); + + tracepoint(lttng_ust_java, int_event, ev_name_cstr, payload); + + (*env)->ReleaseStringUTFChars(env, ev_name, ev_name_cstr); +} + +JNIEXPORT void JNICALL Java_org_lttng_ust_LTTngUst_tracepointIntInt(JNIEnv *env, + jobject jobj __attribute__((unused)), + jstring ev_name, + jint payload1, + jint payload2) +{ + jboolean iscopy; + const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, &iscopy); + + tracepoint(lttng_ust_java, int_int_event, ev_name_cstr, payload1, payload2); + + (*env)->ReleaseStringUTFChars(env, ev_name, ev_name_cstr); +} + +JNIEXPORT void JNICALL Java_org_lttng_ust_LTTngUst_tracepointLong(JNIEnv *env, + jobject jobj __attribute__((unused)), + jstring ev_name, + jlong payload) +{ + jboolean iscopy; + const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, &iscopy); + + tracepoint(lttng_ust_java, long_event, ev_name_cstr, payload); + + (*env)->ReleaseStringUTFChars(env, ev_name, ev_name_cstr); +} + +JNIEXPORT void JNICALL Java_org_lttng_ust_LTTngUst_tracepointLongLong(JNIEnv *env, + jobject jobj __attribute__((unused)), + jstring ev_name, + jlong payload1, + jlong payload2) +{ + jboolean iscopy; + const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, &iscopy); + + tracepoint(lttng_ust_java, long_long_event, ev_name_cstr, payload1, payload2); + + (*env)->ReleaseStringUTFChars(env, ev_name, ev_name_cstr); +} + +JNIEXPORT void JNICALL Java_org_lttng_ust_LTTngUst_tracepointString(JNIEnv *env, + jobject jobj __attribute__((unused)), + jstring ev_name, + jstring payload) +{ + jboolean iscopy; + const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, &iscopy); + const char *payload_cstr = (*env)->GetStringUTFChars(env, payload, &iscopy); + + tracepoint(lttng_ust_java, string_event, ev_name_cstr, payload_cstr); + + (*env)->ReleaseStringUTFChars(env, ev_name, ev_name_cstr); + (*env)->ReleaseStringUTFChars(env, payload, payload_cstr); +} + diff --git a/src/lib/lttng-ust-java/Makefile.am b/src/lib/lttng-ust-java/Makefile.am new file mode 100644 index 00000000..55252fbb --- /dev/null +++ b/src/lib/lttng-ust-java/Makefile.am @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: LGPL-2.1-only + +JAVAROOT = . +jarfile = liblttng-ust-java.jar +jardir = $(datadir)/java +pkgpath = org/lttng/ust + +dist_noinst_JAVA = $(pkgpath)/LTTngUst.java +jar_DATA = $(jarfile) +BUILT_SOURCES = org_lttng_ust_LTTngUst.h + +AM_CPPFLAGS += -I$(builddir) -I$(srcdir) $(JNI_CPPFLAGS) +lib_LTLIBRARIES = liblttng-ust-java.la +liblttng_ust_java_la_SOURCES = LTTngUst.c lttng_ust_java.h +nodist_liblttng_ust_java_la_SOURCES = org_lttng_ust_LTTngUst.h + +liblttng_ust_java_la_LIBADD = -lc \ + $(top_builddir)/src/liblttng-ust/liblttng-ust.la + +$(jarfile): classnoinst.stamp + $(JAR) cf $(JARFLAGS) $@ $(pkgpath)/*.class + +if !HAVE_JAVAH +# If we don't have javah, assume we are running openjdk >= 10 and use javac +# to generate the jni header file. +AM_JAVACFLAGS = -h . + +org_lttng_ust_LTTngUst.h: $(jarfile) +else +org_lttng_ust_LTTngUst.h: jni-header.stamp + +jni-header.stamp: $(dist_noinst_JAVA) + $(JAVAH) -classpath $(srcdir) $(JAVAHFLAGS) org.lttng.ust.LTTngUst && \ + echo "JNI header generated" > jni-header.stamp +endif + +all-local: org_lttng_ust_LTTngUst.h + +EXTRA_DIST = README + +CLEANFILES = $(jarfile) $(pkgpath)/*.class jni-header.stamp org_lttng_ust_LTTngUst.h diff --git a/src/lib/lttng-ust-java/README b/src/lib/lttng-ust-java/README new file mode 100644 index 00000000..d2ca4781 --- /dev/null +++ b/src/lib/lttng-ust-java/README @@ -0,0 +1,15 @@ +This directory contains a simple API for instrumenting java applications. + +Configuration examples to build this library: + +dependency: openjdk-7-jdk +./configure --enable-jni-interface + +Note that the OpenJDK 7 is used for development and continuous integration thus +we directly support that version for this library. However, it has been tested +with OpenJDK 6 also. Please let us know if other Java version (commercial or +not) work with this library. + +After building, you can use the liblttng-ust-java.jar file in a Java project. +It requires the liblttng-ust-java.so* files (which get installed when doing +`make install') so make sure those are in the linker's library path. diff --git a/src/lib/lttng-ust-java/lttng_ust_java.h b/src/lib/lttng-ust-java/lttng_ust_java.h new file mode 100644 index 00000000..ea515a84 --- /dev/null +++ b/src/lib/lttng-ust-java/lttng_ust_java.h @@ -0,0 +1,63 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2011 Mathieu Desnoyers + */ + +#undef TRACEPOINT_PROVIDER +#define TRACEPOINT_PROVIDER lttng_ust_java + +#if !defined(_TRACEPOINT_LTTNG_UST_JAVA_H) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define _TRACEPOINT_LTTNG_UST_JAVA_H + +#include + +TRACEPOINT_EVENT(lttng_ust_java, int_event, + TP_ARGS(const char *, name, int, payload), + TP_FIELDS( + ctf_string(name, name) + ctf_integer(int, int_payload, payload) + ) +) + +TRACEPOINT_EVENT(lttng_ust_java, int_int_event, + TP_ARGS(const char *, name, int, payload1, int, payload2), + TP_FIELDS( + ctf_string(name, name) + ctf_integer(int, int_payload1, payload1) + ctf_integer(int, int_payload2, payload2) + ) +) + +TRACEPOINT_EVENT(lttng_ust_java, long_event, + TP_ARGS(const char *, name, long, payload), + TP_FIELDS( + ctf_string(name, name) + ctf_integer(long, long_payload, payload) + ) +) + +TRACEPOINT_EVENT(lttng_ust_java, long_long_event, + TP_ARGS(const char *, name, long, payload1, long, payload2), + TP_FIELDS( + ctf_string(name, name) + ctf_integer(long, long_payload1, payload1) + ctf_integer(long, long_payload2, payload2) + ) +) + +TRACEPOINT_EVENT(lttng_ust_java, string_event, + TP_ARGS(const char *, name, const char *, payload), + TP_FIELDS( + ctf_string(name, name) + ctf_string(string_payload, payload) + ) +) + +#endif /* _TRACEPOINT_LTTNG_UST_JAVA_H */ + +#undef TRACEPOINT_INCLUDE +#define TRACEPOINT_INCLUDE "./lttng_ust_java.h" + +/* This part must be outside protection */ +#include diff --git a/src/lib/lttng-ust-java/org/lttng/ust/LTTngUst.java b/src/lib/lttng-ust-java/org/lttng/ust/LTTngUst.java new file mode 100644 index 00000000..cc14a729 --- /dev/null +++ b/src/lib/lttng-ust-java/org/lttng/ust/LTTngUst.java @@ -0,0 +1,98 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (C) 2011-2012 Mathieu Desnoyers + * Copyright (C) 2012 Alexandre Montplaisir + */ + +package org.lttng.ust; + +/** + * 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 + * + */ +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-java"); //$NON-NLS-1$ + } + + /** + * Insert a tracepoint with a payload of type Integer. + * + * @param name + * The name assigned to this event. For best performance, this + * should be a statically-defined String, or a literal. + * @param payload + * The int payload + */ + public static native void tracepointInt(String name, int payload); + + /** + * Insert a tracepoint with a payload consisting of two integers. + * + * @param name + * The name assigned to this event. For best performance, this + * should be a statically-defined String, or a literal. + * @param payload1 + * The first int payload + * @param payload2 + * The second int payload + */ + public static native void + tracepointIntInt(String name, int payload1, int payload2); + + /** + * Insert a tracepoint with a payload of type Long + * + * @param name + * The name assigned to this event. For best performance, this + * should be a statically-defined String, or a literal. + * @param payload + * The long payload + */ + public static native void tracepointLong(String name, long payload); + + /** + * Insert a tracepoint with a payload consisting of two longs. + * + * @param name + * The name assigned to this event. For best performance, this + * should be a statically-defined String, or a literal. + * @param payload1 + * The first long payload + * @param payload2 + * The second long payload + */ + public static native void + tracepointLongLong(String name, long payload1, long payload2); + + /** + * Insert a tracepoint with a String payload. + * + * @param name + * The name assigned to this event. For best performance, this + * should be a statically-defined String, or a literal. + * @param payload + * The String payload + */ + public static native void tracepointString(String name, String payload); + +} + diff --git a/src/liblttng-ust-java-agent/Makefile.am b/src/liblttng-ust-java-agent/Makefile.am deleted file mode 100644 index ad47256d..00000000 --- a/src/liblttng-ust-java-agent/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-only - -SUBDIRS = java jni diff --git a/src/liblttng-ust-java-agent/java/Makefile.am b/src/liblttng-ust-java-agent/java/Makefile.am deleted file mode 100644 index 96d575aa..00000000 --- a/src/liblttng-ust-java-agent/java/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-only - -SUBDIRS = lttng-ust-agent-common lttng-ust-agent-all - -if ENABLE_JAVA_AGENT_WITH_JUL -SUBDIRS += lttng-ust-agent-jul -endif - -if ENABLE_JAVA_AGENT_WITH_LOG4J -SUBDIRS += lttng-ust-agent-log4j -endif diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-all/Makefile.am b/src/liblttng-ust-java-agent/java/lttng-ust-agent-all/Makefile.am deleted file mode 100644 index b6cf9aad..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-all/Makefile.am +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-only - -JAVAROOT = . - -jarfile_version = 1.0.0 -jarfile_manifest = $(srcdir)/Manifest.txt -jarfile_symlink = lttng-ust-agent-all.jar -jarfile = lttng-ust-agent-all-$(jarfile_version).jar - -# Compatibility symlink provided for applications expecting the agent -# jar file installed by UST 2.7. -jarfile_compat_symlink = liblttng-ust-agent.jar - -jardir = $(datadir)/java - -dist_noinst_DATA = $(jarfile_manifest) - -jar_DATA = $(jarfile) - -$(jarfile): - $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) \ - && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink) \ - && rm -f $(jarfile_compat_symlink) && $(LN_S) $(jarfile_symlink) $(jarfile_compat_symlink) - -install-data-hook: - cd $(DESTDIR)/$(jardir) \ - && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink) \ - && rm -f $(jarfile_compat_symlink) && $(LN_S) $(jarfile_symlink) $(jarfile_compat_symlink) - -uninstall-hook: - cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && rm -f $(jarfile_compat_symlink) - -CLEANFILES = *.jar diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-all/Manifest.txt b/src/liblttng-ust-java-agent/java/lttng-ust-agent-all/Manifest.txt deleted file mode 100644 index e09c85ec..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-all/Manifest.txt +++ /dev/null @@ -1,8 +0,0 @@ -Name: org/lttng/ust/agent/all/ -Specification-Title: LTTng UST All Java Agents -Specification-Version: 1.0.0 -Specification-Vendor: LTTng Project -Implementation-Title: org.lttng.ust.agent.all -Implementation-Version: 1.0.0 -Implementation-Vendor: LTTng Project -Class-Path: lttng-ust-agent-common.jar lttng-ust-agent-jul.jar lttng-ust-agent-log4j.jar diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am deleted file mode 100644 index 473e8729..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am +++ /dev/null @@ -1,81 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-only - -JAVAROOT = . - -pkgpath = org/lttng/ust/agent - -jarfile_version = 1.0.0 -jarfile_manifest = $(srcdir)/Manifest.txt -jarfile_symlink = lttng-ust-agent-common.jar -jarfile = lttng-ust-agent-common-$(jarfile_version).jar - -jardir = $(datadir)/java -jnioutdir = ../../jni/common - -dist_noinst_JAVA = $(pkgpath)/AbstractLttngAgent.java \ - $(pkgpath)/EventNamePattern.java \ - $(pkgpath)/ILttngAgent.java \ - $(pkgpath)/ILttngHandler.java \ - $(pkgpath)/LTTngAgent.java \ - $(pkgpath)/client/ILttngTcpClientListener.java \ - $(pkgpath)/client/SessiondCommand.java \ - $(pkgpath)/client/LttngAgentResponse.java \ - $(pkgpath)/client/LttngTcpSessiondClient.java \ - $(pkgpath)/client/SessiondCommandHeader.java \ - $(pkgpath)/client/SessiondDisableAppContextCommand.java \ - $(pkgpath)/client/SessiondDisableEventCommand.java \ - $(pkgpath)/client/SessiondEnableAppContextCommand.java \ - $(pkgpath)/client/SessiondEnableEventCommand.java \ - $(pkgpath)/client/SessiondListLoggersCommand.java \ - $(pkgpath)/context/LttngContextApi.java \ - $(pkgpath)/context/ContextInfoManager.java \ - $(pkgpath)/context/ContextInfoSerializer.java \ - $(pkgpath)/context/IContextInfoRetriever.java \ - $(pkgpath)/filter/FilterChangeNotifier.java \ - $(pkgpath)/filter/IFilterChangeListener.java \ - $(pkgpath)/session/EventRule.java \ - $(pkgpath)/session/LogLevelSelector.java \ - $(pkgpath)/utils/LttngUstAgentLogger.java - - -dist_noinst_DATA = $(jarfile_manifest) - -jar_DATA = $(jarfile) - -classes = $(pkgpath)/*.class \ - $(pkgpath)/client/*.class \ - $(pkgpath)/context/*.class \ - $(pkgpath)/filter/*.class \ - $(pkgpath)/session/*.class \ - $(pkgpath)/utils/*.class - -$(jarfile): classnoinst.stamp - $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink) - -if !HAVE_JAVAH -# If we don't have javah, assume we are running openjdk >= 10 and use javac -# to generate the jni header file. -AM_JAVACFLAGS = -h $(jnioutdir) -else -context-jni-header.stamp: $(dist_noinst_JAVA) - $(JAVAH) -classpath $(CLASSPATH):$(srcdir) -d $(jnioutdir) $(JAVAHFLAGS) org.lttng.ust.agent.context.LttngContextApi && \ - echo "Context API JNI header generated" > context-jni-header.stamp - -all-local: context-jni-header.stamp -endif - -install-data-hook: - cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink) - -uninstall-hook: - cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) - -CLEANFILES = *.jar \ - $(pkgpath)/*.class \ - $(pkgpath)/client/*.class \ - $(pkgpath)/context/*.class \ - $(pkgpath)/filter/*.class \ - $(pkgpath)/session/*.class \ - $(pkgpath)/utils/*.class \ - context-jni-header.stamp \ - $(jnioutdir)/org_lttng_ust_agent_context_LttngContextApi.h diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/Manifest.txt b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/Manifest.txt deleted file mode 100644 index d3c7e264..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/Manifest.txt +++ /dev/null @@ -1,7 +0,0 @@ -Name: org/lttng/ust/agent/ -Specification-Title: LTTng UST Java Agent -Specification-Version: 1.0.0 -Specification-Vendor: LTTng Project -Implementation-Title: org.lttng.ust.agent -Implementation-Version: 1.0.0 -Implementation-Vendor: LTTng Project diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java deleted file mode 100644 index acbdc4f1..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java +++ /dev/null @@ -1,386 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - * Copyright (C) 2013 David Goulet - */ - -package org.lttng.ust.agent; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.regex.Matcher; - -import org.lttng.ust.agent.client.ILttngTcpClientListener; -import org.lttng.ust.agent.client.LttngTcpSessiondClient; -import org.lttng.ust.agent.filter.FilterChangeNotifier; -import org.lttng.ust.agent.session.EventRule; -import org.lttng.ust.agent.utils.LttngUstAgentLogger; - -/** - * Base implementation of a {@link ILttngAgent}. - * - * @author Alexandre Montplaisir - * @param - * The type of logging handler that should register to this agent - */ -public abstract class AbstractLttngAgent - implements ILttngAgent, ILttngTcpClientListener { - - private static final int INIT_TIMEOUT = 3; /* Seconds */ - - /** The handlers registered to this agent */ - private final Set registeredHandlers = new HashSet(); - - /** - * The trace events currently enabled in the sessions. - * - * The key is the {@link EventNamePattern} that comes from the event name. - * The value is the ref count (how many different sessions currently have - * this event enabled). Once the ref count falls to 0, this means we can - * avoid sending log events through JNI because nobody wants them. - * - * Its accesses should be protected by the {@link #enabledEventNamesLock} - * below. - */ - private final Map enabledPatterns = new HashMap(); - - /** - * Cache of already-checked event names. As long as enabled/disabled events - * don't change in the session, we can avoid re-checking events that were - * previously checked against all known enabled patterns. - * - * Its accesses should be protected by the {@link #enabledEventNamesLock} - * below, with the exception of concurrent get operations. - */ - private final Map enabledEventNamesCache = new ConcurrentHashMap(); - - /** - * Lock protecting accesses to the {@link #enabledPatterns} and - * {@link #enabledEventNamesCache} maps. - */ - private final Lock enabledEventNamesLock = new ReentrantLock(); - - /** - * The application contexts currently enabled in the tracing sessions. - * - * It is first indexed by context retriever, then by context name. This - * allows to efficiently query all the contexts for a given retriever. - * - * Works similarly as {@link #enabledEvents}, but for app contexts (and with - * an extra degree of indexing). - * - * TODO Could be changed to a Guava Table once/if we start using it. - */ - private final Map> enabledAppContexts = new ConcurrentHashMap>(); - - /** Tracing domain. Defined by the sub-classes via the constructor. */ - private final Domain domain; - - /* Lazy-loaded sessiond clients and their thread objects */ - private LttngTcpSessiondClient rootSessiondClient = null; - private LttngTcpSessiondClient userSessiondClient = null; - private Thread rootSessiondClientThread = null; - private Thread userSessiondClientThread = null; - - /** Indicates if this agent has been initialized. */ - private boolean initialized = false; - - /** - * Constructor. Should only be called by sub-classes via super(...); - * - * @param domain - * The tracing domain of this agent. - */ - protected AbstractLttngAgent(Domain domain) { - this.domain = domain; - } - - @Override - public Domain getDomain() { - return domain; - } - - @Override - public void registerHandler(T handler) { - synchronized (registeredHandlers) { - if (registeredHandlers.isEmpty()) { - /* - * This is the first handler that registers, we will initialize - * the agent. - */ - init(); - } - registeredHandlers.add(handler); - } - } - - @Override - public void unregisterHandler(T handler) { - synchronized (registeredHandlers) { - registeredHandlers.remove(handler); - if (registeredHandlers.isEmpty()) { - /* There are no more registered handlers, close the connection. */ - dispose(); - } - } - } - - private void init() { - /* - * Only called from a synchronized (registeredHandlers) block, should - * not need additional synchronization. - */ - if (initialized) { - return; - } - - LttngUstAgentLogger.log(AbstractLttngAgent.class, "Initializing Agent for domain: " + domain.name()); - - String rootClientThreadName = "Root sessiond client started by agent: " + this.getClass().getSimpleName(); - - rootSessiondClient = new LttngTcpSessiondClient(this, getDomain().value(), true); - rootSessiondClientThread = new Thread(rootSessiondClient, rootClientThreadName); - rootSessiondClientThread.setDaemon(true); - rootSessiondClientThread.start(); - - String userClientThreadName = "User sessiond client started by agent: " + this.getClass().getSimpleName(); - - userSessiondClient = new LttngTcpSessiondClient(this, getDomain().value(), false); - userSessiondClientThread = new Thread(userSessiondClient, userClientThreadName); - userSessiondClientThread.setDaemon(true); - userSessiondClientThread.start(); - - /* Give the threads' registration a chance to end. */ - if (!rootSessiondClient.waitForConnection(INIT_TIMEOUT)) { - userSessiondClient.waitForConnection(INIT_TIMEOUT); - } - - initialized = true; - } - - /** - * Dispose the agent - */ - private void dispose() { - LttngUstAgentLogger.log(AbstractLttngAgent.class, "Disposing Agent for domain: " + domain.name()); - - /* - * Only called from a synchronized (registeredHandlers) block, should - * not need additional synchronization. - */ - rootSessiondClient.close(); - userSessiondClient.close(); - - try { - rootSessiondClientThread.join(); - userSessiondClientThread.join(); - - } catch (InterruptedException e) { - e.printStackTrace(); - } - rootSessiondClient = null; - rootSessiondClientThread = null; - userSessiondClient = null; - userSessiondClientThread = null; - - /* - * Send filter change notifications for all event rules currently - * active, then clear them. - */ - FilterChangeNotifier fcn = FilterChangeNotifier.getInstance(); - - enabledEventNamesLock.lock(); - try { - for (Map.Entry entry : enabledPatterns.entrySet()) { - String eventName = entry.getKey().getEventName(); - Integer nb = entry.getValue(); - for (int i = 0; i < nb.intValue(); i++) { - fcn.removeEventRules(eventName); - } - } - enabledPatterns.clear(); - enabledEventNamesCache.clear(); - } finally { - enabledEventNamesLock.unlock(); - } - - /* - * Also clear tracked app contexts (no filter notifications sent for - * those currently). - */ - enabledAppContexts.clear(); - - initialized = false; - } - - @Override - public boolean eventEnabled(EventRule eventRule) { - /* Notify the filter change manager of the command */ - FilterChangeNotifier.getInstance().addEventRule(eventRule); - - String eventName = eventRule.getEventName(); - EventNamePattern pattern = new EventNamePattern(eventName); - - enabledEventNamesLock.lock(); - try { - boolean ret = incrementRefCount(pattern, enabledPatterns); - enabledEventNamesCache.clear(); - return ret; - } finally { - enabledEventNamesLock.unlock(); - } - } - - @Override - public boolean eventDisabled(String eventName) { - /* Notify the filter change manager of the command */ - FilterChangeNotifier.getInstance().removeEventRules(eventName); - - EventNamePattern pattern = new EventNamePattern(eventName); - - enabledEventNamesLock.lock(); - try { - boolean ret = decrementRefCount(pattern, enabledPatterns); - enabledEventNamesCache.clear(); - return ret; - } finally { - enabledEventNamesLock.unlock(); - } - } - - @Override - public boolean appContextEnabled(String contextRetrieverName, String contextName) { - synchronized (enabledAppContexts) { - Map retrieverMap = enabledAppContexts.get(contextRetrieverName); - if (retrieverMap == null) { - /* There is no submap for this retriever, let's create one. */ - retrieverMap = new ConcurrentHashMap(); - enabledAppContexts.put(contextRetrieverName, retrieverMap); - } - - return incrementRefCount(contextName, retrieverMap); - } - } - - @Override - public boolean appContextDisabled(String contextRetrieverName, String contextName) { - synchronized (enabledAppContexts) { - Map retrieverMap = enabledAppContexts.get(contextRetrieverName); - if (retrieverMap == null) { - /* There was no submap for this retriever, invalid command? */ - return false; - } - - boolean ret = decrementRefCount(contextName, retrieverMap); - - /* If the submap is now empty we can remove it from the main map. */ - if (retrieverMap.isEmpty()) { - enabledAppContexts.remove(contextRetrieverName); - } - - return ret; - } - } - - /* - * Implementation of this method is domain-specific. - */ - @Override - public abstract Collection listAvailableEvents(); - - @Override - public boolean isEventEnabled(String eventName) { - Boolean cachedEnabled = enabledEventNamesCache.get(eventName); - if (cachedEnabled != null) { - /* We have seen this event previously */ - /* - * Careful! enabled == null could also mean that the null value is - * associated with the key. But we should have never inserted null - * values in the map. - */ - return cachedEnabled.booleanValue(); - } - - /* - * We have not previously checked this event. Run it against all known - * enabled event patterns to determine if it should pass or not. - */ - enabledEventNamesLock.lock(); - try { - boolean enabled = false; - for (EventNamePattern enabledPattern : enabledPatterns.keySet()) { - Matcher matcher = enabledPattern.getPattern().matcher(eventName); - if (matcher.matches()) { - enabled = true; - break; - } - } - - /* Add the result to the cache */ - enabledEventNamesCache.put(eventName, Boolean.valueOf(enabled)); - return enabled; - - } finally { - enabledEventNamesLock.unlock(); - } - } - - @Override - public Collection>> getEnabledAppContexts() { - return enabledAppContexts.entrySet(); - } - - private static boolean incrementRefCount(T key, Map refCountMap) { - synchronized (refCountMap) { - Integer count = refCountMap.get(key); - if (count == null) { - /* This is the first instance of this event being enabled */ - refCountMap.put(key, Integer.valueOf(1)); - return true; - } - if (count.intValue() <= 0) { - /* It should not have been in the map in the first place! */ - throw new IllegalStateException(); - } - /* The event was already enabled, increment its refcount */ - refCountMap.put(key, Integer.valueOf(count.intValue() + 1)); - return true; - } - } - - private static boolean decrementRefCount(T key, Map refCountMap) { - synchronized (refCountMap) { - Integer count = refCountMap.get(key); - if (count == null || count.intValue() <= 0) { - /* - * The sessiond asked us to disable an event that was not - * enabled previously. Command error? - */ - return false; - } - if (count.intValue() == 1) { - /* - * This is the last instance of this event being disabled, - * remove it from the map so that we stop sending it. - */ - refCountMap.remove(key); - return true; - } - /* - * Other sessions are still looking for this event, simply decrement - * its refcount. - */ - refCountMap.put(key, Integer.valueOf(count.intValue() - 1)); - return true; - } - } -} - diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/EventNamePattern.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/EventNamePattern.java deleted file mode 100644 index ada5c95f..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/EventNamePattern.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2017 EfficiOS Inc. - * Copyright (C) 2017 Philippe Proulx - */ - -package org.lttng.ust.agent; - -import java.util.regex.Pattern; - -/** - * Class encapsulating an event name from the session daemon, and its - * corresponding {@link Pattern}. This allows referring back to the original - * event name, for example when we receive a disable command. - * - * @author Philippe Proulx - * @author Alexandre Montplaisir - */ -class EventNamePattern { - - private final String originalEventName; - - /* - * Note that two Patterns coming from the exact same String will not be - * equals()! As such, it would be confusing to make the pattern part of this - * class's equals/hashCode - */ - private final transient Pattern pattern; - - public EventNamePattern(String eventName) { - if (eventName == null) { - throw new IllegalArgumentException(); - } - - originalEventName = eventName; - pattern = patternFromEventName(eventName); - } - - public String getEventName() { - return originalEventName; - } - - public Pattern getPattern() { - return pattern; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + originalEventName.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - EventNamePattern other = (EventNamePattern) obj; - if (!originalEventName.equals(other.originalEventName)) { - return false; - } - return true; - } - - private static Pattern patternFromEventName(String eventName) { - /* - * The situation here is that `\*` means a literal `*` in the event - * name, and `*` is a wildcard star. We check the event name one - * character at a time and create a list of tokens to be converter to - * partial patterns. - */ - StringBuilder bigBuilder = new StringBuilder("^"); - StringBuilder smallBuilder = new StringBuilder(); - - for (int i = 0; i < eventName.length(); i++) { - char c = eventName.charAt(i); - - switch (c) { - case '*': - /* Add current quoted builder's string if not empty. */ - if (smallBuilder.length() > 0) { - bigBuilder.append(Pattern.quote(smallBuilder.toString())); - smallBuilder.setLength(0); - } - - /* Append the equivalent regex which is `.*`. */ - bigBuilder.append(".*"); - continue; - - case '\\': - /* We only escape `*` and `\` here. */ - if (i < (eventName.length() - 1)) { - char nextChar = eventName.charAt(i + 1); - - if (nextChar == '*' || nextChar == '\\') { - smallBuilder.append(nextChar); - } else { - smallBuilder.append(c); - smallBuilder.append(nextChar); - } - - i++; - continue; - } - break; - - default: - break; - } - - smallBuilder.append(c); - } - - /* Add current quoted builder's string if not empty. */ - if (smallBuilder.length() > 0) { - bigBuilder.append(Pattern.quote(smallBuilder.toString())); - } - - bigBuilder.append("$"); - - return Pattern.compile(bigBuilder.toString()); - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngAgent.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngAgent.java deleted file mode 100644 index ca2358a5..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngAgent.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - */ - -package org.lttng.ust.agent; - -import java.util.Collection; -import java.util.Map; - -/** - * Interface to define LTTng Java agents. - * - * An "agent" is a representative of an LTTng session daemon in the Java world. - * It tracks the settings of a tracing session as they defined in the session - * daemon. - * - * It also track the current logging handlers that are sending events to UST. - * - * @author Alexandre Montplaisir - * - * @param - * The type of logging handler that should register to this agent - */ -public interface ILttngAgent { - - // ------------------------------------------------------------------------ - // Agent configuration elements - // ------------------------------------------------------------------------ - - /** - * Tracing domains. Corresponds to domains defined by LTTng Tools. - */ - enum Domain { - JUL(3), LOG4J(4); - private int value; - - private Domain(int value) { - this.value = value; - } - - public int value() { - return value; - } - } - - /** - * The tracing domain of this agent. - * - * @return The tracing domain. - */ - Domain getDomain(); - - // ------------------------------------------------------------------------ - // Log handler registering - // ------------------------------------------------------------------------ - - /** - * Register a handler to this agent. - * - * @param handler - * The handler to register - */ - void registerHandler(T handler); - - /** - * Deregister a handler from this agent. - * - * @param handler - * The handler to deregister. - */ - void unregisterHandler(T handler); - - // ------------------------------------------------------------------------ - // Tracing session parameters - // ------------------------------------------------------------------------ - - /** - * Query if a given event is currently enabled in a current tracing session, - * meaning it should be sent to UST. - * - * @param eventName - * The name of the event to check. - * @return True if the event is currently enabled, false if it is not. - */ - boolean isEventEnabled(String eventName); - - /** - * Return the list of application contexts enabled in the tracing sessions. - * - * @return The application contexts, first indexed by retriever name, then - * by context name - */ - Collection>> getEnabledAppContexts(); -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngHandler.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngHandler.java deleted file mode 100644 index 0d1bd799..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/ILttngHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - */ - -package org.lttng.ust.agent; - -/** - * Simple interface to organize all LTTng log handlers under one type. - * - * @author Alexandre Montplaisir - */ -public interface ILttngHandler { - - /** - * Get the number of events logged by this handler since its inception. - * - * @return The number of logged events - */ - long getEventCount(); - - /** - * Close the log handler. Should be called once the application is done - * logging through it. - */ - void close(); -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngAgent.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngAgent.java deleted file mode 100644 index f6aae351..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/LTTngAgent.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2013 David Goulet - */ - -package org.lttng.ust.agent; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.logging.Handler; -import java.util.logging.Logger; - -/** - * The central agent managing the JUL and Log4j handlers. - * - * @author David Goulet - * @deprecated Applications are now expected to manage their Logger and Handler - * objects. - */ -@Deprecated -public class LTTngAgent { - - private static LTTngAgent instance = null; - - /** - * Public getter to acquire a reference to this singleton object. - * - * @return The agent instance - */ - public static synchronized LTTngAgent getLTTngAgent() { - if (instance == null) { - instance = new LTTngAgent(); - } - return instance; - } - - /** - * Dispose the agent. Applications should call this once they are done - * logging. This dispose function is non-static for backwards - * compatibility purposes. - */ - @SuppressWarnings("static-method") - public void dispose() { - synchronized (LTTngAgent.class) { - if (instance != null) { - instance.disposeInstance(); - instance = null; - } - } - return; - } - - private ILttngHandler julHandler = null; - private ILttngHandler log4jAppender = null; - - /** - * Private constructor. This is a singleton and a reference should be - * acquired using {@link #getLTTngAgent()}. - */ - private LTTngAgent() { - initJulHandler(); - initLog4jAppender(); - } - - /** - * "Destructor" method. - */ - private void disposeInstance() { - disposeJulHandler(); - disposeLog4jAppender(); - } - - /** - * Create a LTTng-JUL handler, and attach it to the JUL root logger. - */ - private void initJulHandler() { - try { - Class julHandlerClass = Class.forName("org.lttng.ust.agent.jul.LttngLogHandler"); - /* - * It is safer to use Constructor.newInstance() rather than - * Class.newInstance(), because it will catch the exceptions thrown - * by the constructor below (which happens if the Java library is - * present, but the matching JNI one is not). - */ - Constructor julHandlerCtor = julHandlerClass.getConstructor(); - julHandler = (ILttngHandler) julHandlerCtor.newInstance(); - - /* Attach the handler to the root JUL logger */ - Logger.getLogger("").addHandler((Handler) julHandler); - - /* - * If any of the following exceptions happen, it means we could not - * find or initialize LTTng JUL classes. We will not setup LTTng JUL - * tracing in this case. - */ - } catch (SecurityException e) { - } catch (IllegalAccessException e) { - } catch (IllegalArgumentException e) { - } catch (ClassNotFoundException e) { - } catch (NoSuchMethodException e) { - } catch (InstantiationException e) { - } catch (InvocationTargetException e) { - } - } - - /** - * Create a LTTng-logj4 appender, and attach it to the log4j root logger. - */ - private void initLog4jAppender() { - /* - * Since Log4j is a 3rd party library, we first need to check if we can - * load any of its classes. - */ - if (!testLog4jClasses()) { - return; - } - - try { - Class log4jAppenderClass = Class.forName("org.lttng.ust.agent.log4j.LttngLogAppender"); - Constructor log4jAppendCtor = log4jAppenderClass.getConstructor(); - log4jAppender = (ILttngHandler) log4jAppendCtor.newInstance(); - - /* - * If any of the following exceptions happen, it means we could not - * find or initialize LTTng log4j classes. We will not setup LTTng - * log4j tracing in this case. - */ - } catch (SecurityException e) { - return; - } catch (ClassNotFoundException e) { - return; - } catch (NoSuchMethodException e) { - return; - } catch (IllegalArgumentException e) { - return; - } catch (InstantiationException e) { - return; - } catch (IllegalAccessException e) { - return; - } catch (InvocationTargetException e) { - return; - } - - /* - * Attach the appender to the root Log4j logger. Slightly more tricky - * here, as log4j.Logger is not in the base Java library, and we do not - * want the "common" package to depend on log4j. So we have to obtain it - * through reflection too. - */ - try { - Class loggerClass = Class.forName("org.apache.log4j.Logger"); - Class appenderClass = Class.forName("org.apache.log4j.Appender"); - - Method getRootLoggerMethod = loggerClass.getMethod("getRootLogger", (Class[]) null); - Method addAppenderMethod = loggerClass.getMethod("addAppender", appenderClass); - - Object rootLogger = getRootLoggerMethod.invoke(null, (Object[]) null); - addAppenderMethod.invoke(rootLogger, log4jAppender); - - /* - * We have checked for the log4j library version previously, none of - * the following exceptions should happen. - */ - } catch (SecurityException e) { - throw new IllegalStateException(e); - } catch (ClassNotFoundException e) { - throw new IllegalStateException(e); - } catch (NoSuchMethodException e) { - throw new IllegalStateException(e); - } catch (IllegalArgumentException e) { - throw new IllegalStateException(e); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } catch (InvocationTargetException e) { - throw new IllegalStateException(e); - } - } - - /** - * Check if log4j >= 1.2.15 library is present. - */ - private static boolean testLog4jClasses() { - Class loggingEventClass; - - try { - loggingEventClass = Class.forName("org.apache.log4j.spi.LoggingEvent"); - } catch (ClassNotFoundException e) { - /* - * Log4j classes not found, no need to create the relevant objects - */ - return false; - } - - /* - * Detect capabilities of the log4j library. We only support log4j >= - * 1.2.15. The getTimeStamp() method was introduced in log4j 1.2.15, so - * verify that it is available. - * - * We can't rely on the getPackage().getImplementationVersion() call - * that would retrieves information from the manifest file found in the - * JAR since the manifest file shipped from upstream is known to be - * broken in several versions of the library. - * - * More info: https://issues.apache.org/bugzilla/show_bug.cgi?id=44370 - */ - try { - loggingEventClass.getDeclaredMethod("getTimeStamp"); - } catch (NoSuchMethodException e) { - System.err.println( - "Warning: The loaded log4j library is too old. Log4j tracing with LTTng will be disabled."); - return false; - } catch (SecurityException e) { - return false; - } - - return true; - } - - /** - * Detach the JUL handler from its logger and close it. - */ - private void disposeJulHandler() { - if (julHandler == null) { - /* The JUL handler was not activated, we have nothing to do */ - return; - } - Logger.getLogger("").removeHandler((Handler) julHandler); - julHandler.close(); - julHandler = null; - } - - /** - * Detach the log4j appender from its logger and close it. - */ - private void disposeLog4jAppender() { - if (log4jAppender == null) { - /* The log4j appender was not active, we have nothing to do */ - return; - } - - /* - * Detach the appender from the log4j root logger. Again, we have to do - * this via reflection. - */ - try { - Class loggerClass = Class.forName("org.apache.log4j.Logger"); - Class appenderClass = Class.forName("org.apache.log4j.Appender"); - - Method getRootLoggerMethod = loggerClass.getMethod("getRootLogger", (Class[]) null); - Method removeAppenderMethod = loggerClass.getMethod("removeAppender", appenderClass); - - Object rootLogger = getRootLoggerMethod.invoke(null, (Object[]) null); - removeAppenderMethod.invoke(rootLogger, log4jAppender); - - /* - * We were able to attach the appender previously, we should not - * have problems here either! - */ - } catch (SecurityException e) { - throw new IllegalStateException(e); - } catch (ClassNotFoundException e) { - throw new IllegalStateException(e); - } catch (NoSuchMethodException e) { - throw new IllegalStateException(e); - } catch (IllegalArgumentException e) { - throw new IllegalStateException(e); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } catch (InvocationTargetException e) { - throw new IllegalStateException(e); - } - - /* Close the appender */ - log4jAppender.close(); - log4jAppender = null; - } - -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/ILttngTcpClientListener.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/ILttngTcpClientListener.java deleted file mode 100644 index e6edb567..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/ILttngTcpClientListener.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.client; - -import java.util.Collection; - -import org.lttng.ust.agent.session.EventRule; - -/** - * TCP client listener interface. - * - * This interface contains callbacks that are called when the TCP client - * receives commands from the session daemon. These callbacks will define what - * do to with each command. - * - * @author Alexandre Montplaisir - */ -public interface ILttngTcpClientListener { - - /** - * Callback for the TCP client to notify the listener agent that a request - * for enabling an event rule was sent from the session daemon. - * - * @param eventRule - * The event rule that was requested to be enabled - * @return Since we do not track individual sessions, right now this command - * cannot fail. It will always return true. - */ - boolean eventEnabled(EventRule eventRule); - - /** - * Callback for the TCP client to notify the listener agent that a request - * for disabling an event was sent from the session daemon. - * - * @param eventName - * The name of the event that was requested to be disabled. - * @return True if the command completed successfully, false if we should - * report an error (event was not enabled, etc.) - */ - boolean eventDisabled(String eventName); - - /** - * Callback for the TCP client to notify the listener agent that a request - * for enabling an application-specific context was sent from the session - * daemon. - * - * @param contextRetrieverName - * The name of the retriever in which the context is present. - * This is used to namespace the contexts. - * @param contextName - * The name of the context that was requested to be enabled - * @return Since we do not track individual sessions, right now this command - * cannot fail. It will always return true. - */ - boolean appContextEnabled(String contextRetrieverName, String contextName); - - /** - * Callback for the TCP client to notify the listener agent that a request - * for disabling an application-specific context was sent from the session - * daemon. - * - * @param contextRetrieverName - * The name of the retriever in which the context is present. - * This is used to namespace the contexts. - * @param contextName - * The name of the context that was requested to be disabled. - * @return True if the command completed successfully, false if we should - * report an error (context was not previously enabled for example) - */ - boolean appContextDisabled(String contextRetrieverName, String contextName); - - /** - * List the events that are available in the agent's tracing domain. - * - * In Java terms, this means loggers that have at least one LTTng log - * handler of their corresponding domain attached. - * - * @return The list of available events - */ - Collection listAvailableEvents(); -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngAgentResponse.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngAgentResponse.java deleted file mode 100644 index 4ffeccd9..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngAgentResponse.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - * Copyright (C) 2013 David Goulet - */ - -package org.lttng.ust.agent.client; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * Interface for all response messages sent from the Java agent to the sessiond - * daemon. Normally sent after a command coming from the session daemon was - * executed. - * - * @author Alexandre Montplaisir - */ -abstract class LttngAgentResponse { - - private static final int INT_SIZE = 4; - - public static final LttngAgentResponse SUCESS_RESPONSE = new LttngAgentResponse() { - @Override - public ReturnCode getReturnCode() { - return ReturnCode.CODE_SUCCESS_CMD; - } - }; - - public static final LttngAgentResponse FAILURE_RESPONSE = new LttngAgentResponse() { - @Override - public ReturnCode getReturnCode() { - return ReturnCode.CODE_INVALID_CMD; - } - }; - - /** - * Return codes used in agent responses, to indicate success or different - * types of failures of the commands. - */ - protected enum ReturnCode { - - CODE_SUCCESS_CMD(1, "sucess"), - CODE_INVALID_CMD(2, "invalid"), - CODE_UNKNOWN_LOGGER_NAME(3, "unknown logger name"); - - private final int code; - private final String toString; - - private ReturnCode(int c, String str) { - code = c; - toString = str; - } - - public int getCode() { - return code; - } - - /** - * Mainly used for debugging. The strings are not sent through the - * socket. - */ - @Override - public String toString() { - return toString; - } - } - - /** - * Get the {@link ReturnCode} that goes with this response. It is expected - * by the session daemon, but some commands may require more than this - * in their response. - * - * @return The return code - */ - public abstract ReturnCode getReturnCode(); - - /** - * Gets a byte array of the response so that it may be streamed. - * - * @return The byte array of the response - */ - public byte[] getBytes() { - byte data[] = new byte[INT_SIZE]; - ByteBuffer buf = ByteBuffer.wrap(data); - buf.order(ByteOrder.BIG_ENDIAN); - buf.putInt(getReturnCode().getCode()); - return data; - } - - @Override - public String toString() { - return "LttngAgentResponse[" - + "code=" + getReturnCode().getCode() - + ", " + getReturnCode().toString() - + "]"; - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngTcpSessiondClient.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngTcpSessiondClient.java deleted file mode 100644 index 9fa8c3ac..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngTcpSessiondClient.java +++ /dev/null @@ -1,429 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015-2016 EfficiOS Inc. - * Copyright (C) 2015-2016 Alexandre Montplaisir - * Copyright (C) 2013 David Goulet - */ - -package org.lttng.ust.agent.client; - -import java.io.BufferedReader; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.lang.management.ManagementFactory; -import java.net.Socket; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.charset.Charset; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.lttng.ust.agent.utils.LttngUstAgentLogger; - -/** - * Client for agents to connect to a local session daemon, using a TCP socket. - * - * @author David Goulet - */ -public class LttngTcpSessiondClient implements Runnable { - - private static final String SESSION_HOST = "127.0.0.1"; - private static final String ROOT_PORT_FILE = "/var/run/lttng/agent.port"; - private static final String USER_PORT_FILE = "/.lttng/agent.port"; - private static final Charset PORT_FILE_ENCODING = Charset.forName("UTF-8"); - - private static final int PROTOCOL_MAJOR_VERSION = 2; - private static final int PROTOCOL_MINOR_VERSION = 0; - - /** Command header from the session deamon. */ - private final CountDownLatch registrationLatch = new CountDownLatch(1); - - private Socket sessiondSock; - private volatile boolean quit = false; - - private DataInputStream inFromSessiond; - private DataOutputStream outToSessiond; - - private final ILttngTcpClientListener logAgent; - private final int domainValue; - private final boolean isRoot; - - /** - * Constructor - * - * @param logAgent - * The listener this client will operate on, typically an LTTng - * agent. - * @param domainValue - * The integer to send to the session daemon representing the - * tracing domain to handle. - * @param isRoot - * True if this client should connect to the root session daemon, - * false if it should connect to the user one. - */ - public LttngTcpSessiondClient(ILttngTcpClientListener logAgent, int domainValue, boolean isRoot) { - this.logAgent = logAgent; - this.domainValue = domainValue; - this.isRoot = isRoot; - } - - /** - * Wait until this client has successfully established a connection to its - * target session daemon. - * - * @param seconds - * A timeout in seconds after which this method will return - * anyway. - * @return True if the the client actually established the connection, false - * if we returned because the timeout has elapsed or the thread was - * interrupted. - */ - public boolean waitForConnection(int seconds) { - try { - return registrationLatch.await(seconds, TimeUnit.SECONDS); - } catch (InterruptedException e) { - return false; - } - } - - @Override - public void run() { - for (;;) { - if (this.quit) { - break; - } - - try { - - /* - * Connect to the session daemon before anything else. - */ - log("Connecting to sessiond"); - connectToSessiond(); - - /* - * Register to the session daemon as the Java component of the - * UST application. - */ - log("Registering to sessiond"); - 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. - */ - log("Waiting on sessiond commands..."); - handleSessiondCmd(); - } catch (UnknownHostException uhe) { - uhe.printStackTrace(); - /* - * Terminate agent thread. - */ - close(); - } catch (IOException ioe) { - /* - * I/O exception may have been triggered by a session daemon - * closing the socket. Close our own socket and - * retry connecting after a delay. - */ - try { - if (this.sessiondSock != null) { - this.sessiondSock.close(); - } - Thread.sleep(3000); - } catch (InterruptedException e) { - /* - * Retry immediately if sleep is interrupted. - */ - } catch (IOException closeioe) { - closeioe.printStackTrace(); - /* - * Terminate agent thread. - */ - close(); - } - } - } - } - - /** - * Dispose this client and close any socket connection it may hold. - */ - public void close() { - log("Closing client"); - this.quit = true; - - try { - if (this.sessiondSock != null) { - this.sessiondSock.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void connectToSessiond() throws IOException { - int rootPort = getPortFromFile(ROOT_PORT_FILE); - int userPort = getPortFromFile(getHomePath() + USER_PORT_FILE); - - /* - * Check for the edge case of both files existing but pointing to the - * same port. In this case, let the root client handle it. - */ - if ((rootPort != 0) && (rootPort == userPort) && (!isRoot)) { - log("User and root config files both point to port " + rootPort + - ". Letting the root client handle it."); - throw new IOException(); - } - - int portToUse = (isRoot ? rootPort : userPort); - - if (portToUse == 0) { - /* No session daemon available. Stop and retry later. */ - throw new IOException(); - } - - this.sessiondSock = new Socket(SESSION_HOST, portToUse); - this.inFromSessiond = new DataInputStream(sessiondSock.getInputStream()); - this.outToSessiond = new DataOutputStream(sessiondSock.getOutputStream()); - } - - private static String getHomePath() { - /* - * The environment variable LTTNG_HOME overrides HOME if - * defined. - */ - String homePath = System.getenv("LTTNG_HOME"); - - if (homePath == null) { - homePath = System.getProperty("user.home"); - } - return homePath; - } - - /** - * Read port number from file created by the session daemon. - * - * @return port value if found else 0. - */ - private static int getPortFromFile(String path) throws IOException { - BufferedReader br = null; - - try { - br = new BufferedReader(new InputStreamReader(new FileInputStream(path), PORT_FILE_ENCODING)); - String line = br.readLine(); - if (line == null) { - /* File exists but is empty. */ - return 0; - } - - int port = Integer.parseInt(line, 10); - if (port < 0 || port > 65535) { - /* Invalid value. Ignore. */ - port = 0; - } - return port; - - } catch (NumberFormatException e) { - /* File contained something that was not a number. */ - return 0; - } catch (FileNotFoundException e) { - /* No port available. */ - return 0; - } finally { - if (br != null) { - br.close(); - } - } - } - - private void registerToSessiond() throws IOException { - byte data[] = new byte[16]; - ByteBuffer buf = ByteBuffer.wrap(data); - String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0]; - - buf.putInt(domainValue); - buf.putInt(Integer.parseInt(pid)); - buf.putInt(PROTOCOL_MAJOR_VERSION); - buf.putInt(PROTOCOL_MINOR_VERSION); - this.outToSessiond.write(data, 0, data.length); - this.outToSessiond.flush(); - } - - /** - * Handle session command from the session daemon. - */ - private void handleSessiondCmd() throws IOException { - /* Data read from the socket */ - byte inputData[] = null; - /* Reply data written to the socket, sent to the sessiond */ - LttngAgentResponse response; - - while (true) { - /* Get header from session daemon. */ - SessiondCommandHeader cmdHeader = recvHeader(); - - if (cmdHeader.getDataSize() > 0) { - inputData = recvPayload(cmdHeader); - } - - switch (cmdHeader.getCommandType()) { - case CMD_REG_DONE: - { - /* - * Countdown the registration latch, meaning registration is - * done and we can proceed to continue tracing. - */ - registrationLatch.countDown(); - /* - * We don't send any reply to the registration done command. - * This just marks the end of the initial session setup. - */ - log("Registration done"); - continue; - } - case CMD_LIST: - { - SessiondCommand listLoggerCmd = new SessiondListLoggersCommand(); - response = listLoggerCmd.execute(logAgent); - log("Received list loggers command"); - break; - } - case CMD_EVENT_ENABLE: - { - if (inputData == null) { - /* Invalid command */ - response = LttngAgentResponse.FAILURE_RESPONSE; - break; - } - SessiondCommand enableEventCmd = new SessiondEnableEventCommand(inputData); - response = enableEventCmd.execute(logAgent); - log("Received enable event command: " + enableEventCmd.toString()); - break; - } - case CMD_EVENT_DISABLE: - { - if (inputData == null) { - /* Invalid command */ - response = LttngAgentResponse.FAILURE_RESPONSE; - break; - } - SessiondCommand disableEventCmd = new SessiondDisableEventCommand(inputData); - response = disableEventCmd.execute(logAgent); - log("Received disable event command: " + disableEventCmd.toString()); - break; - } - case CMD_APP_CTX_ENABLE: - { - if (inputData == null) { - /* This commands expects a payload, invalid command */ - response = LttngAgentResponse.FAILURE_RESPONSE; - break; - } - SessiondCommand enableAppCtxCmd = new SessiondEnableAppContextCommand(inputData); - response = enableAppCtxCmd.execute(logAgent); - log("Received enable app-context command"); - break; - } - case CMD_APP_CTX_DISABLE: - { - if (inputData == null) { - /* This commands expects a payload, invalid command */ - response = LttngAgentResponse.FAILURE_RESPONSE; - break; - } - SessiondCommand disableAppCtxCmd = new SessiondDisableAppContextCommand(inputData); - response = disableAppCtxCmd.execute(logAgent); - log("Received disable app-context command"); - break; - } - default: - { - /* Unknown command, send empty reply */ - response = null; - log("Received unknown command, ignoring"); - break; - } - } - - /* Send response to the session daemon. */ - byte[] responseData; - if (response == null) { - responseData = new byte[4]; - ByteBuffer buf = ByteBuffer.wrap(responseData); - buf.order(ByteOrder.BIG_ENDIAN); - } else { - log("Sending response: " + response.toString()); - responseData = response.getBytes(); - } - this.outToSessiond.write(responseData, 0, responseData.length); - this.outToSessiond.flush(); - } - } - - /** - * Receive header data from the session daemon using the LTTng command - * static buffer of the right size. - */ - private SessiondCommandHeader recvHeader() throws IOException { - byte data[] = new byte[SessiondCommandHeader.HEADER_SIZE]; - int bytesLeft = data.length; - int bytesOffset = 0; - - while (bytesLeft > 0) { - int bytesRead = this.inFromSessiond.read(data, bytesOffset, bytesLeft); - - if (bytesRead < 0) { - throw new IOException(); - } - bytesLeft -= bytesRead; - bytesOffset += bytesRead; - } - return new SessiondCommandHeader(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(SessiondCommandHeader headerCmd) throws IOException { - byte payload[] = new byte[(int) headerCmd.getDataSize()]; - int bytesLeft = payload.length; - int bytesOffset = 0; - - /* Failsafe check so we don't waste our time reading 0 bytes. */ - if (bytesLeft == 0) { - return null; - } - - while (bytesLeft > 0) { - int bytesRead = inFromSessiond.read(payload, bytesOffset, bytesLeft); - - if (bytesRead < 0) { - throw new IOException(); - } - bytesLeft -= bytesRead; - bytesOffset += bytesRead; - } - return payload; - } - - /** - * Wrapper for this class's logging, adds the connection's characteristics - * to help differentiate between multiple TCP clients. - */ - private void log(String message) { - LttngUstAgentLogger.log(getClass(), - "(root=" + isRoot + ", domain=" + domainValue + ") " + message); - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommand.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommand.java deleted file mode 100644 index 27aba232..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommand.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015-2016 EfficiOS Inc. - * Copyright (C) 2015-2016 Alexandre Montplaisir - * Copyright (C) 2013 David Goulet - */ - -package org.lttng.ust.agent.client; - -import java.nio.ByteBuffer; -import java.nio.charset.Charset; - -/** - * Base class to represent all commands sent from the session daemon to the Java - * agent. The agent is then expected to execute the command and provide a - * response. - * - * @author Alexandre Montplaisir - */ -abstract class SessiondCommand { - - /** - * Encoding that should be used for the strings in the sessiond agent - * protocol on the socket. - */ - protected static final Charset SESSIOND_PROTOCOL_CHARSET = Charset.forName("UTF-8"); - - enum CommandType { - /** List logger(s). */ - CMD_LIST(1), - /** Enable logger by name. */ - CMD_EVENT_ENABLE(2), - /** Disable logger by name. */ - CMD_EVENT_DISABLE(3), - /** Registration done */ - CMD_REG_DONE(4), - /** Enable application context */ - CMD_APP_CTX_ENABLE(5), - /** Disable application context */ - CMD_APP_CTX_DISABLE(6); - - private int code; - - private CommandType(int c) { - code = c; - } - - public int getCommandType() { - return code; - } - } - - /** - * Execute the command handler's action on the specified tracing agent. - * - * @param agent - * The agent on which to execute the command - * @return If the command completed successfully or not - */ - public abstract LttngAgentResponse execute(ILttngTcpClientListener agent); - - /** - * Utility method to read agent-protocol strings passed on the socket. The - * buffer will contain a 32-bit integer representing the length, immediately - * followed by the string itself. - * - * @param buffer - * The ByteBuffer from which to read. It should already be setup - * and positioned where the read should begin. - * @return The string that was read, or null if it was badly - * formatted. - */ - protected static String readNextString(ByteBuffer buffer) { - int nbBytes = buffer.getInt(); - if (nbBytes < 0) { - /* The string length should be positive */ - return null; - } - if (nbBytes == 0) { - /* The string is explicitly an empty string */ - return ""; - } - - byte[] stringBytes = new byte[nbBytes]; - buffer.get(stringBytes); - return new String(stringBytes, SESSIOND_PROTOCOL_CHARSET).trim(); - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommandHeader.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommandHeader.java deleted file mode 100644 index 845109d7..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommandHeader.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - * Copyright (C) 2013 David Goulet - */ - -package org.lttng.ust.agent.client; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import org.lttng.ust.agent.client.SessiondCommand.CommandType; - -/** - * Header of session daemon commands. - * - * @author Alexandre Montplaisir - * @author David Goulet - */ -class SessiondCommandHeader { - - /** ABI size of command header. */ - public static final int HEADER_SIZE = 16; - - /** Payload size in bytes following this header. */ - private final long dataSize; - - /** Command type. */ - private final CommandType cmd; - - public SessiondCommandHeader(byte[] data) { - ByteBuffer buf = ByteBuffer.wrap(data); - buf.order(ByteOrder.BIG_ENDIAN); - - dataSize = buf.getLong(); - cmd = CommandType.values()[buf.getInt() - 1]; - buf.getInt(); // command version, currently unused - } - - public long getDataSize() { - return dataSize; - } - - public CommandType getCommandType() { - return cmd; - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableAppContextCommand.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableAppContextCommand.java deleted file mode 100644 index 4ac991ab..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableAppContextCommand.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.client; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * Session daemon command indicating to the Java agent that an - * application-specific context was disabled in the tracing session. - * - * @author Alexandre Montplaisir - */ -class SessiondDisableAppContextCommand extends SessiondCommand { - - private final String retrieverName; - private final String contextName; - - private final boolean commandIsValid; - - public SessiondDisableAppContextCommand(byte[] data) { - if (data == null) { - throw new IllegalArgumentException(); - } - ByteBuffer buf = ByteBuffer.wrap(data); - buf.order(ByteOrder.BIG_ENDIAN); - - /* - * The buffer contains the retriever name first, followed by the - * context's name. - */ - retrieverName = readNextString(buf); - contextName = readNextString(buf); - - /* If any of these strings were null then the command was invalid */ - commandIsValid = ((retrieverName != null) && (contextName != null)); - } - - @Override - public LttngAgentResponse execute(ILttngTcpClientListener agent) { - if (!commandIsValid) { - return LttngAgentResponse.FAILURE_RESPONSE; - } - - boolean success = agent.appContextDisabled(retrieverName, contextName); - return (success ? LttngAgentResponse.SUCESS_RESPONSE : DISABLE_APP_CONTEXT_FAILURE_RESPONSE); - } - - /** - * Response sent when the disable-context command asks to disable an - * unknown context name. - */ - private static final LttngAgentResponse DISABLE_APP_CONTEXT_FAILURE_RESPONSE = new LttngAgentResponse() { - @Override - public ReturnCode getReturnCode() { - /* Same return code used for unknown event/logger names */ - return ReturnCode.CODE_UNKNOWN_LOGGER_NAME; - } - }; -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableEventCommand.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableEventCommand.java deleted file mode 100644 index ff8eff3a..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableEventCommand.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - * Copyright (C) 2013 David Goulet - */ - -package org.lttng.ust.agent.client; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * Session daemon command indicating to the Java agent that some events were - * disabled in the tracing session. - * - * @author Alexandre Montplaisir - * @author David Goulet - */ -class SessiondDisableEventCommand extends SessiondCommand { - - /** - * Response sent when the disable-event command asks to disable an - * unknown event. - */ - private static final LttngAgentResponse DISABLE_EVENT_FAILURE_RESPONSE = new LttngAgentResponse() { - @Override - public ReturnCode getReturnCode() { - return ReturnCode.CODE_UNKNOWN_LOGGER_NAME; - } - }; - - /** Event name to disable from the tracing session */ - private final String eventName; - - public SessiondDisableEventCommand(byte[] data) { - if (data == null) { - throw new IllegalArgumentException(); - } - ByteBuffer buf = ByteBuffer.wrap(data); - buf.order(ByteOrder.BIG_ENDIAN); - eventName = new String(data, SESSIOND_PROTOCOL_CHARSET).trim(); - } - - @Override - public LttngAgentResponse execute(ILttngTcpClientListener agent) { - boolean success = agent.eventDisabled(this.eventName); - return (success ? LttngAgentResponse.SUCESS_RESPONSE : DISABLE_EVENT_FAILURE_RESPONSE); - } - - @Override - public String toString() { - return "SessiondDisableEventCommand[" - + "eventName=" + eventName - +"]"; - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableAppContextCommand.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableAppContextCommand.java deleted file mode 100644 index d0be8cf9..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableAppContextCommand.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.client; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * Session daemon command indicating to the Java agent that an - * application-specific context was enabled in the tracing session. - * - * @author Alexandre Montplaisir - */ -class SessiondEnableAppContextCommand extends SessiondCommand { - - private final String retrieverName; - private final String contextName; - - private final boolean commandIsValid; - - public SessiondEnableAppContextCommand(byte[] data) { - if (data == null) { - throw new IllegalArgumentException(); - } - ByteBuffer buf = ByteBuffer.wrap(data); - buf.order(ByteOrder.BIG_ENDIAN); - - /* - * The buffer contains the retriever name first, followed by the - * context's name. - */ - retrieverName = readNextString(buf); - contextName = readNextString(buf); - - /* If any of these strings were null then the command was invalid */ - commandIsValid = ((retrieverName != null) && (contextName != null)); - } - - @Override - public LttngAgentResponse execute(ILttngTcpClientListener agent) { - if (!commandIsValid) { - return LttngAgentResponse.FAILURE_RESPONSE; - } - - boolean success = agent.appContextEnabled(retrieverName, contextName); - return (success ? LttngAgentResponse.SUCESS_RESPONSE : LttngAgentResponse.FAILURE_RESPONSE); - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableEventCommand.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableEventCommand.java deleted file mode 100644 index 35029c9b..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableEventCommand.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - * Copyright (C) 2013 David Goulet - */ - -package org.lttng.ust.agent.client; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import org.lttng.ust.agent.session.EventRule; -import org.lttng.ust.agent.session.LogLevelSelector; - -/** - * Session daemon command indicating to the Java agent that some events were - * enabled in the tracing session. - * - * @author Alexandre Montplaisir - * @author David Goulet - */ -class SessiondEnableEventCommand extends SessiondCommand { - - /** Fixed event name length. Value defined by the lttng agent protocol. */ - private static final int EVENT_NAME_LENGTH = 256; - - private final boolean commandIsValid; - - /* Parameters of the event rule being enabled */ - private final String eventName; - private final LogLevelSelector logLevelFilter; - private final String filterString; - - public SessiondEnableEventCommand(byte[] data) { - if (data == null) { - throw new IllegalArgumentException(); - } - ByteBuffer buf = ByteBuffer.wrap(data); - buf.order(ByteOrder.BIG_ENDIAN); - int logLevel = buf.getInt(); - int logLevelType = buf.getInt(); - logLevelFilter = new LogLevelSelector(logLevel, logLevelType); - - /* Read the event name */ - byte[] eventNameBytes = new byte[EVENT_NAME_LENGTH]; - buf.get(eventNameBytes); - eventName = new String(eventNameBytes, SESSIOND_PROTOCOL_CHARSET).trim(); - - /* Read the filter string */ - filterString = readNextString(buf); - - /* The command was invalid if the string could not be read correctly */ - commandIsValid = (filterString != null); - } - - @Override - public LttngAgentResponse execute(ILttngTcpClientListener agent) { - if (!commandIsValid) { - return LttngAgentResponse.FAILURE_RESPONSE; - } - - EventRule rule = new EventRule(eventName, logLevelFilter, filterString); - boolean success = agent.eventEnabled(rule); - return (success ? LttngAgentResponse.SUCESS_RESPONSE : LttngAgentResponse.FAILURE_RESPONSE); - } - - @Override - public String toString() { - return "SessiondEnableEventCommand[" - + "eventName=" + eventName - + ", logLevel=" + logLevelFilter.toString() - + ", filterString=" + filterString - +"]"; - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondListLoggersCommand.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondListLoggersCommand.java deleted file mode 100644 index 0500055c..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondListLoggersCommand.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - * Copyright (C) 2013 David Goulet - */ - -package org.lttng.ust.agent.client; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Collection; - -/** - * Session daemon command asking the Java agent to list its registered loggers, - * which corresponds to event names in the tracing session. - * - * @author Alexandre Montplaisir - * @author David Goulet - */ -class SessiondListLoggersCommand extends SessiondCommand { - - @Override - public LttngAgentResponse execute(ILttngTcpClientListener agent) { - final Collection loggerList = agent.listAvailableEvents(); - return new SessiondListLoggersResponse(loggerList); - } - - private static class SessiondListLoggersResponse extends LttngAgentResponse { - - private final static int SIZE = 12; - - private final Collection loggers; - - public SessiondListLoggersResponse(Collection loggers) { - this.loggers = loggers; - } - - @Override - public ReturnCode getReturnCode() { - /* This command can't really fail */ - return ReturnCode.CODE_SUCCESS_CMD; - } - - @Override - public byte[] getBytes() { - /* - * Compute the data size, which is the number of bytes of each - * encoded string, +1 per string for the \0 - */ - int dataSize = 0; - for (String logger : loggers) { - dataSize += logger.getBytes(SESSIOND_PROTOCOL_CHARSET).length + 1; - } - - /* Prepare the buffer */ - byte data[] = new byte[SIZE + dataSize]; - ByteBuffer buf = ByteBuffer.wrap(data); - buf.order(ByteOrder.BIG_ENDIAN); - - /* Write the header section of the response */ - buf.putInt(getReturnCode().getCode()); - buf.putInt(dataSize); - buf.putInt(loggers.size()); - - /* Write the payload */ - for (String logger : loggers) { - buf.put(logger.getBytes(SESSIOND_PROTOCOL_CHARSET)); - /* NULL terminated byte after the logger name. */ - buf.put((byte) 0x0); - } - return data; - } - } - -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoManager.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoManager.java deleted file mode 100644 index 22efe022..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoManager.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.context; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * The singleton manager of {@link IContextInfoRetriever} objects. - * - * @author Alexandre Montplaisir - */ -public final class ContextInfoManager { - - private static final String SHARED_LIBRARY_NAME = "lttng-ust-context-jni"; - - private static final Pattern VALID_CONTEXT_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_\\.]+$"); - - private static ContextInfoManager instance; - - private final Map contextInfoRetrievers = new ConcurrentHashMap(); - private final Map contextInforRetrieverRefs = new HashMap(); - - /** - * Lock used to keep the two maps above in sync when retrievers are - * registered or unregistered. - */ - private final Object retrieverLock = new Object(); - - /** Singleton class, constructor should not be accessed directly */ - private ContextInfoManager() { - } - - /** - * Get the singleton instance. - * - *

- * Usage of this class requires the "liblttng-ust-context-jni.so" native - * library to be present on the system and available (passing - * -Djava.library.path=path to the JVM may be needed). - *

- * - * @return The singleton instance - * @throws IOException - * If the shared library cannot be found. - * @throws SecurityException - * We will forward any SecurityExcepion that may be thrown when - * trying to load the JNI library. - */ - public static synchronized ContextInfoManager getInstance() throws IOException, SecurityException { - if (instance == null) { - try { - System.loadLibrary(SHARED_LIBRARY_NAME); - } catch (UnsatisfiedLinkError e) { - throw new IOException(e); - } - instance = new ContextInfoManager(); - } - return instance; - } - - /** - * Register a new context info retriever. - * - *

- * Each context info retriever is registered with a given "retriever name", - * which specifies the namespace of the context elements. This name is - * specified separately from the retriever objects, which would allow - * register the same retriever under different namespaces for example. - *

- * - *

- * If the method returns false (indicating registration failure), then the - * retriever object will *not* be used for context information. - *

- * - * @param retrieverName - * The name to register to the context retriever object with. - * @param contextInfoRetriever - * The context info retriever to register - * @return True if the retriever was successfully registered, false if there - * was an error, for example if a retriever is already registered - * with that name. - */ - public boolean registerContextInfoRetriever(String retrieverName, IContextInfoRetriever contextInfoRetriever) { - synchronized (retrieverLock) { - if (!validateRetrieverName(retrieverName)) { - return false; - } - - if (contextInfoRetrievers.containsKey(retrieverName)) { - /* - * There is already a retriever registered with that name, - * refuse the new registration. - */ - return false; - } - /* - * Inform LTTng-UST of the new retriever. The names have to start - * with "$app." on the UST side! - */ - long ref = LttngContextApi.registerProvider("$app." + retrieverName); - if (ref == 0) { - return false; - } - - contextInfoRetrievers.put(retrieverName, contextInfoRetriever); - contextInforRetrieverRefs.put(retrieverName, Long.valueOf(ref)); - - return true; - } - } - - /** - * Unregister a previously added context info retriever. - * - * This method has no effect if the retriever was not already registered. - * - * @param retrieverName - * The context info retriever to unregister - * @return True if unregistration was successful, false if there was an - * error - */ - public boolean unregisterContextInfoRetriever(String retrieverName) { - synchronized (retrieverLock) { - if (!contextInfoRetrievers.containsKey(retrieverName)) { - /* - * There was no retriever registered with that name. - */ - return false; - } - contextInfoRetrievers.remove(retrieverName); - long ref = contextInforRetrieverRefs.remove(retrieverName).longValue(); - - /* Unregister the retriever on the UST side too */ - LttngContextApi.unregisterProvider(ref); - - return true; - } - } - - /** - * Return the context info retriever object registered with the given name. - * - * @param retrieverName - * The retriever name to look for - * @return The corresponding retriever object, or null if there - * was none - */ - public IContextInfoRetriever getContextInfoRetriever(String retrieverName) { - /* - * Note that this method does not take the retrieverLock, it lets - * concurrent threads access the ConcurrentHashMap directly. - * - * It's fine for a get() to happen during a registration or - * unregistration, it's first-come-first-serve. - */ - return contextInfoRetrievers.get(retrieverName); - } - - /** - * Validate that the given retriever name contains only the allowed - * characters, which are alphanumerical characters, period "." and - * underscore "_". The name must also not start with a number. - */ - private static boolean validateRetrieverName(String contextName) { - if (contextName.isEmpty()) { - return false; - } - - /* First character must not be a number */ - if (Character.isDigit(contextName.charAt(0))) { - return false; - } - - /* Validate the other characters of the string */ - Matcher matcher = VALID_CONTEXT_NAME_PATTERN.matcher(contextName); - return matcher.matches(); - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java deleted file mode 100644 index ae650607..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.context; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.charset.Charset; -import java.util.Collection; -import java.util.Map; - -import org.lttng.ust.agent.utils.LttngUstAgentLogger; - -/** - * This class is used to serialize the list of "context info" objects to pass - * through JNI. - * - * The protocol expects two byte array parameters, which are contained here in - * the {@link SerializedContexts} inner class. - * - * The first byte array is called the "entries array", and contains fixed-size - * entries, one per context element. - * - * The second one is the "strings array", it is of variable length and used to - * hold the variable-length strings. Each one of these strings is formatted as a - * UTF-8 C-string, meaning in will end with a "\0" byte to indicate its end. - * Entries in the first array may refer to offsets in the second array to point - * to relevant strings. - * - * The fixed-size entries in the entries array contain the following elements - * (size in bytes in parentheses): - * - *
    - *
  • The offset in the strings array pointing to the full context name, like - * "$app.myprovider:mycontext" (4)
  • - *
  • The context value type (1)
  • - *
  • The context value itself (8)
  • - *
- * - * The context value type will indicate how many bytes are used for the value. - * If the it is of String type, then we use 4 bytes to represent the offset in - * the strings array. - * - * So the total size of each entry is 13 bytes. All unused bytes (for context - * values shorter than 8 bytes for example) will be zero'ed. - * - * @author Alexandre Montplaisir - */ -public class ContextInfoSerializer { - - private enum DataType { - NULL(0), - INTEGER(1), - LONG(2), - DOUBLE(3), - FLOAT(4), - BYTE(5), - SHORT(6), - BOOLEAN(7), - STRING(8); - - private final byte value; - - private DataType(int value) { - this.value = (byte) value; - } - - public byte getValue() { - return value; - } - } - - /** - * Class used to wrap the two byte arrays returned by - * {@link #queryAndSerializeRequestedContexts}. - */ - public static class SerializedContexts { - - private final byte[] contextEntries; - private final byte[] contextStrings; - - /** - * Constructor - * - * @param entries - * Arrays for the fixed-size context entries. - * @param strings - * Arrays for variable-length strings - */ - public SerializedContexts(byte[] entries, byte[] strings) { - contextEntries = entries; - contextStrings = strings; - } - - /** - * @return The entries array - */ - public byte[] getEntriesArray() { - return contextEntries; - } - - /** - * @return The strings array - */ - public byte[] getStringsArray() { - return contextStrings; - } - } - - private static final String UST_APP_CTX_PREFIX = "$app."; - private static final int ENTRY_LENGTH = 13; - private static final ByteOrder NATIVE_ORDER = ByteOrder.nativeOrder(); - private static final Charset UTF8_CHARSET = Charset.forName("UTF-8"); - private static final SerializedContexts EMPTY_CONTEXTS = new SerializedContexts(new byte[0], new byte[0]); - - /** - * From the list of requested contexts in the tracing session, look them up - * in the {@link ContextInfoManager}, retrieve the available ones, and - * serialize them into a byte array. - * - * @param enabledContexts - * The contexts that are enabled in the tracing session (indexed - * first by retriever name, then by index names). Should come - * from the LTTng Agent. - * @return The byte array representing the intersection of the requested and - * available contexts. - */ - public static SerializedContexts queryAndSerializeRequestedContexts(Collection>> enabledContexts) { - if (enabledContexts.isEmpty()) { - /* Early return if there is no requested context information */ - return EMPTY_CONTEXTS; - } - - ContextInfoManager contextManager; - try { - contextManager = ContextInfoManager.getInstance(); - } catch (IOException e) { - /* - * The JNI library is not available, do not send any context - * information. No retriever could have been defined anyways. - */ - return EMPTY_CONTEXTS; - } - - /* Compute the total number of contexts (flatten the map) */ - int totalArraySize = 0; - for (Map.Entry> contexts : enabledContexts) { - totalArraySize += contexts.getValue().size() * ENTRY_LENGTH; - } - - /* Prepare the ByteBuffer that will generate the "entries" array */ - ByteBuffer entriesBuffer = ByteBuffer.allocate(totalArraySize); - entriesBuffer.order(NATIVE_ORDER); - entriesBuffer.clear(); - - /* Prepare the streams that will generate the "strings" array */ - ByteArrayOutputStream stringsBaos = new ByteArrayOutputStream(); - DataOutputStream stringsDos = new DataOutputStream(stringsBaos); - - try { - for (Map.Entry> entry : enabledContexts) { - String requestedRetrieverName = entry.getKey(); - Map requestedContexts = entry.getValue(); - - IContextInfoRetriever retriever = contextManager.getContextInfoRetriever(requestedRetrieverName); - - for (String requestedContext : requestedContexts.keySet()) { - Object contextInfo; - if (retriever == null) { - contextInfo = null; - } else { - contextInfo = retriever.retrieveContextInfo(requestedContext); - /* - * 'contextInfo' can still be null here, which would - * indicate the retriever does not supply this context. - * We will still write this information so that the - * tracer can know about it. - */ - } - - /* Serialize the result to the buffers */ - // FIXME Eventually pass the retriever name only once? - String fullContextName = (UST_APP_CTX_PREFIX + requestedRetrieverName + ':' + requestedContext); - byte[] strArray = fullContextName.getBytes(UTF8_CHARSET); - - entriesBuffer.putInt(stringsDos.size()); - stringsDos.write(strArray); - stringsDos.writeChar('\0'); - - LttngUstAgentLogger.log(ContextInfoSerializer.class, - "ContextInfoSerializer: Context to be sent through JNI: " + fullContextName + '=' + - (contextInfo == null ? "null" : contextInfo.toString())); - - serializeContextInfo(entriesBuffer, stringsDos, contextInfo); - } - } - - stringsDos.flush(); - stringsBaos.flush(); - - } catch (IOException e) { - /* - * Should not happen because we are wrapping a - * ByteArrayOutputStream, which writes to memory - */ - e.printStackTrace(); - } - - byte[] entriesArray = entriesBuffer.array(); - byte[] stringsArray = stringsBaos.toByteArray(); - return new SerializedContexts(entriesArray, stringsArray); - } - - private static final int CONTEXT_VALUE_LENGTH = 8; - - private static void serializeContextInfo(ByteBuffer entriesBuffer, DataOutputStream stringsDos, Object contextInfo) throws IOException { - int remainingBytes; - if (contextInfo == null) { - entriesBuffer.put(DataType.NULL.getValue()); - remainingBytes = CONTEXT_VALUE_LENGTH; - - } else if (contextInfo instanceof Integer) { - entriesBuffer.put(DataType.INTEGER.getValue()); - entriesBuffer.putInt(((Integer) contextInfo).intValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 4; - - } else if (contextInfo instanceof Long) { - entriesBuffer.put(DataType.LONG.getValue()); - entriesBuffer.putLong(((Long) contextInfo).longValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 8; - - } else if (contextInfo instanceof Double) { - entriesBuffer.put(DataType.DOUBLE.getValue()); - entriesBuffer.putDouble(((Double) contextInfo).doubleValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 8; - - } else if (contextInfo instanceof Float) { - entriesBuffer.put(DataType.FLOAT.getValue()); - entriesBuffer.putFloat(((Float) contextInfo).floatValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 4; - - } else if (contextInfo instanceof Byte) { - entriesBuffer.put(DataType.BYTE.getValue()); - entriesBuffer.put(((Byte) contextInfo).byteValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 1; - - } else if (contextInfo instanceof Short) { - entriesBuffer.put(DataType.SHORT.getValue()); - entriesBuffer.putShort(((Short) contextInfo).shortValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 2; - - } else if (contextInfo instanceof Boolean) { - entriesBuffer.put(DataType.BOOLEAN.getValue()); - boolean b = ((Boolean) contextInfo).booleanValue(); - /* Converted to one byte, write 1 for true, 0 for false */ - entriesBuffer.put((byte) (b ? 1 : 0)); - remainingBytes = CONTEXT_VALUE_LENGTH - 1; - - } else { - /* Also includes the case of Character. */ - /* - * We'll write the object as a string, into the strings array. We - * will write the corresponding offset to the entries array. - */ - String str = contextInfo.toString(); - byte[] strArray = str.getBytes(UTF8_CHARSET); - - entriesBuffer.put(DataType.STRING.getValue()); - - entriesBuffer.putInt(stringsDos.size()); - stringsDos.write(strArray); - stringsDos.writeChar('\0'); - - remainingBytes = CONTEXT_VALUE_LENGTH - 4; - } - entriesBuffer.position(entriesBuffer.position() + remainingBytes); - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/IContextInfoRetriever.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/IContextInfoRetriever.java deleted file mode 100644 index 235a30a5..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/IContextInfoRetriever.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.context; - -/** - * Context-retrieving object specified by the application to extract - * application-specific context information, which can then be passed on to the - * Java agents and saved to a trace. - * - * Retriever objects should be registered to the {@link ContextInfoManager} to - * make them available to the LTTng agents. - * - * @author Alexandre Montplaisir - */ -public interface IContextInfoRetriever { - - /** - * Retrieve a piece of context information from the application, identified - * by a key. - * - * @param key - * The key identifying the context information - * @return The context information. - */ - Object retrieveContextInfo(String key); -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/LttngContextApi.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/LttngContextApi.java deleted file mode 100644 index a60d80e1..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/LttngContextApi.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.context; - -/** - * Virtual class containing the Java side of the LTTng-UST context provider - * registering/unregistering methods. - * - * @author Alexandre Montplaisir - */ -final class LttngContextApi { - - private LttngContextApi() {} - - /** - * Register a context provider to UST. - * - * The callbacks are the same for all providers, and are defined in the .c - * file. The only needed information is the retriever (which is called - * "provider" from UST'S point of view) name. - * - * @param provider_name - * The name of the provider - * @return The pointer to the created provider object. It's useless in the - * Java space, but will be needed for - * {@link #unregisterProvider(long)}. - */ - static native long registerProvider(String provider_name); - - /** - * Unregister a previously-registered context provider from UST. - * - * @param provider_ref - * The pointer to the provider object, obtained from - * {@link #registerProvider} - */ - static native void unregisterProvider(long provider_ref); -} - diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/FilterChangeNotifier.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/FilterChangeNotifier.java deleted file mode 100644 index e1c96e16..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/FilterChangeNotifier.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.filter; - -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.lttng.ust.agent.session.EventRule; - -/** - * Singleton class managing the filter notifications. - * - * Applications can register a {@link IFilterChangeListener} to be notified when - * event filtering rules change in the tracing sessions. - * - * @author Alexandre Montplaisir - */ -public final class FilterChangeNotifier { - - /** Lazy-loaded singleton instance object */ - private static FilterChangeNotifier instance = null; - - private final Map enabledEventRules = new HashMap(); - private final Collection registeredListeners = new LinkedList(); - - - /** - * Private constructor, singleton class should not be instantiated directly. - */ - private FilterChangeNotifier() { - } - - /** - * Get the singleton instance, initializing it if needed. - * - * @return The singleton instance - */ - public static synchronized FilterChangeNotifier getInstance() { - if (instance == null) { - instance = new FilterChangeNotifier(); - } - return instance; - } - - /** - * Notify the filter manager that a new rule was enabled in a tracing - * session ("lttng enable-event ...") - * - * This is meant to be called by the LTTng Agent only. External Java - * applications should not call this. - * - * @param rule - * The rule that was added - */ - public synchronized void addEventRule(EventRule rule) { - Integer count = enabledEventRules.get(rule); - if (count == null) { - /* - * This is the first instance of this rule being enabled. Add it to - * the map and send notifications to the registered notifiers. - */ - enabledEventRules.put(rule, Integer.valueOf(1)); - notifyForAddedRule(rule); - return; - } - if (count.intValue() <= 0) { - /* It should not have been in the map! */ - throw new IllegalStateException(); - } - /* - * This exact event rule was already enabled, just increment its - * refcount without sending notifications - */ - enabledEventRules.put(rule, Integer.valueOf(count.intValue() + 1)); - } - - /** - * Notify the filter manager that an event name was disabled in the tracing - * sessions ("lttng disable-event ..."). - * - * The "disable-event" only specifies an event name. This means all the - * rules containing this event name are to be disabled. - * - * This is meant to be called by the LTTng Agent only. External Java - * applications should not call this. - * - * @param eventName - * The event name to disable - */ - public synchronized void removeEventRules(String eventName) { - List rulesToRemove = new LinkedList(); - - for (EventRule eventRule : enabledEventRules.keySet()) { - if (eventRule.getEventName().equals(eventName)) { - rulesToRemove.add(eventRule); - } - } - /* - * We cannot modify the map while iterating on it. We have to do the - * removal separately from the iteration above. - */ - for (EventRule rule : rulesToRemove) { - removeEventRule(rule); - } - } - - private synchronized void removeEventRule(EventRule eventRule) { - Integer count = enabledEventRules.get(eventRule); - if (count == null || count.intValue() <= 0) { - /* - * We were asked us to disable an event rule that was not enabled - * previously. Command error? - */ - throw new IllegalStateException(); - } - if (count.intValue() == 1) { - /* - * This is the last instance of this event rule being disabled, - * remove it from the map and send notifications of this rule being - * gone. - */ - enabledEventRules.remove(eventRule); - notifyForRemovedRule(eventRule); - return; - } - /* - * Other sessions/daemons are still looking for this event rule, simply - * decrement its refcount, and do not send notifications. - */ - enabledEventRules.put(eventRule, Integer.valueOf(count.intValue() - 1)); - - } - - /** - * Register a new listener to the manager. - * - * @param listener - * The listener to add - */ - public synchronized void registerListener(IFilterChangeListener listener) { - registeredListeners.add(listener); - - /* Send the current rules to the new listener ("statedump") */ - for (EventRule rule : enabledEventRules.keySet()) { - listener.eventRuleAdded(rule); - } - } - - /** - * Unregister a listener from the manager. - * - * @param listener - * The listener to remove - */ - public synchronized void unregisterListener(IFilterChangeListener listener) { - registeredListeners.remove(listener); - } - - private void notifyForAddedRule(final EventRule rule) { - for (IFilterChangeListener notifier : registeredListeners) { - notifier.eventRuleAdded(rule); - } - } - - private void notifyForRemovedRule(final EventRule rule) { - for (IFilterChangeListener notifier : registeredListeners) { - notifier.eventRuleRemoved(rule); - } - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/IFilterChangeListener.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/IFilterChangeListener.java deleted file mode 100644 index e222b229..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/filter/IFilterChangeListener.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.filter; - -import org.lttng.ust.agent.session.EventRule; - -/** - * Filter notification listener interface. - *

- * Applications wanting to be notified of event filtering rule changes should - * implement this interface, then register their listener using - * {@link FilterChangeNotifier#registerListener}. - *

- *

- * The callbacks defined in this interface will be called whenever an event rule - * is added or removed. The manager will take care of the reference-counting in - * case multiple tracing sessions enable the exact same rules. For example, the - * {@link #eventRuleRemoved} callback is only called when there are no more - * session interested into it. - *

- *

- * Do not forget to unregister the listener after use, using - * {@link FilterChangeNotifier#unregisterListener}. If you do not, or if - * you use an anonymous listener for example, these will remain attached until - * the complete shutdown of the application. - *

- *

- * Only one thread is used to dispatch notifications, sequentially. This means - * that if a callback hangs it will prevent other listeners from receiving - * notifications. Please take care of not blocking inside the listener - * callbacks, and use separate threads for potentially long or blocking - * operations. - *

- * - * @author Alexandre Montplaisir - */ -public interface IFilterChangeListener { - - /** - * Notification that a new event rule is now enabled in the tracing - * sessions. - * - * @param rule - * The event rule that was enabled - */ - void eventRuleAdded(EventRule rule); - - /** - * Notification that an existing event rule is now disabled in the tracing - * sessions. - * - * @param rule - * The event rule that was disabled - */ - void eventRuleRemoved(EventRule rule); -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/EventRule.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/EventRule.java deleted file mode 100644 index dcf05a7e..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/EventRule.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.session; - -/** - * Event filtering rule present in a tracing session. - * - * It typically comes from a "lttng enable-event" command, and contains a - * domain, event name, log level and filter string. - * - * @author Alexandre Montplaisir - */ -public class EventRule { - - private final String eventName; - private final LogLevelSelector logLevelSelector; - private final String filterString; - - /** - * Constructor. - * - * @param eventName - * The name of the tracepoint - * @param logLevelSelector - * The log level of the event rule - * @param filterString - * The filtering string. May be null if there is no extra filter. - */ - public EventRule(String eventName, LogLevelSelector logLevelSelector, String filterString) { - this.eventName = eventName; - this.logLevelSelector = logLevelSelector; - this.filterString = filterString; - } - - /** - * Get the event name of this rule. - * - * @return The event name - */ - public String getEventName() { - return eventName; - } - - /** - * Get the log level filter configuration of the rule. - * - * @return The log level selector - */ - public LogLevelSelector getLogLevelSelector() { - return logLevelSelector; - } - - /** - * Get the filter string associated with this rule. - * - * @return The filter string, may be null for no filter string. - */ - public String getFilterString() { - return filterString; - } - - // ------------------------------------------------------------------------ - // Methods from Object - // ------------------------------------------------------------------------ - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((eventName == null) ? 0 : eventName.hashCode()); - result = prime * result + ((filterString == null) ? 0 : filterString.hashCode()); - result = prime * result + ((logLevelSelector == null) ? 0 : logLevelSelector.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - EventRule other = (EventRule) obj; - - if (eventName == null) { - if (other.eventName != null) { - return false; - } - } else if (!eventName.equals(other.eventName)) { - return false; - } - /* else, continue */ - - if (filterString == null) { - if (other.filterString != null) { - return false; - } - } else if (!filterString.equals(other.filterString)) { - return false; - } - /* else, continue */ - - if (logLevelSelector == null) { - if (other.logLevelSelector != null) { - return false; - } - } else if (!logLevelSelector.equals(other.logLevelSelector)) { - return false; - } - /* else, continue */ - - return true; - } - - @Override - public String toString() { - return "Event name = " + getEventName() + - ", Log level selector = (" + getLogLevelSelector().toString() + ")" + - ", Filter string = " + getFilterString(); - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/LogLevelSelector.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/LogLevelSelector.java deleted file mode 100644 index c25ec81d..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/LogLevelSelector.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.session; - -/** - * Log level filtering element, which is part of an {@link EventRule}. - * - * @author Alexandre Montplaisir - */ -public class LogLevelSelector { - - /** - * The type of log level filter that is enabled. - * - * Defined from lttng-tools' include/lttng/event.h. - */ - public enum LogLevelType { - /** - * All log levels are enabled. This overrides the value of - * {@link LogLevelSelector#getLogLevel}. - */ - LTTNG_EVENT_LOGLEVEL_ALL(0), - - /** This log level along with all log levels of higher severity are enabled. */ - LTTNG_EVENT_LOGLEVEL_RANGE(1), - - /** Only this exact log level is enabled. */ - LTTNG_EVENT_LOGLEVEL_SINGLE(2); - - private final int value; - - private LogLevelType(int value) { - this.value = value; - } - - /** - * Get the numerical (int) value representing this log level type in the - * communication protocol. - * - * @return The int value - */ - public int getValue() { - return value; - } - - static LogLevelType fromValue(int val) { - switch (val) { - case 0: - return LTTNG_EVENT_LOGLEVEL_ALL; - case 1: - return LTTNG_EVENT_LOGLEVEL_RANGE; - case 2: - return LTTNG_EVENT_LOGLEVEL_SINGLE; - default: - throw new IllegalArgumentException(); - } - } - } - - private final int logLevel; - private final LogLevelType logLevelType; - - /** - * Constructor using numerical values straight from the communication - * protocol. - * - * @param logLevel - * The numerical value of the log level. The exact value depends - * on the tracing domain, see include/lttng/event.h in the - * lttng-tools tree for the complete enumeration. - * @param logLevelType - * The numerical value of the log level type. It will be - * converted to a {@link LogLevelType} by this constructor. - * @throws IllegalArgumentException - * If the 'logLevelType' does not correspond to a valid value. - */ - public LogLevelSelector(int logLevel, int logLevelType) { - this.logLevel = logLevel; - this.logLevelType = LogLevelType.fromValue(logLevelType); - } - - /** - * "Manual" constructor, specifying the {@link LogLevelType} directly. - * - * @param logLevel - * The numerical value of the log level. The exact value depends - * on the tracing domain, see include/lttng/event.h in the - * lttng-tools tree for the complete enumeration. - * @param type - * The log level filter type. - */ - public LogLevelSelector(int logLevel, LogLevelType type) { - this.logLevel = logLevel; - this.logLevelType = type; - } - - /** - * Get the numerical value of the log level element. Does not apply if - * {@link #getLogLevelType} returns - * {@link LogLevelType#LTTNG_EVENT_LOGLEVEL_ALL}. - * - * @return The numerical value of the log level - */ - public int getLogLevel() { - return logLevel; - } - - /** - * Get the log level filter type. - * - * @return The log level filter type - */ - public LogLevelType getLogLevelType() { - return logLevelType; - } - - /** - * Helper method to determine if an event with the given log level should be - * traced when considering this filter. - * - * For example, if this filter object represents "higher severity than 5", - * and the log level passed in parameter is "8", it will return that it - * matches (higher value means higher severity). - * - * @param targetLogLevel - * The log level value of the event to check for - * @return Should this event be traced, or not - */ - public boolean matches(int targetLogLevel) { - switch (logLevelType) { - case LTTNG_EVENT_LOGLEVEL_ALL: - return true; - case LTTNG_EVENT_LOGLEVEL_RANGE: - return (targetLogLevel >= logLevel); - case LTTNG_EVENT_LOGLEVEL_SINGLE: - return (targetLogLevel == logLevel); - default: - throw new IllegalStateException(); - } - } - - // ------------------------------------------------------------------------ - // Methods from Object - // ------------------------------------------------------------------------ - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + logLevel; - result = prime * result + ((logLevelType == null) ? 0 : logLevelType.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - LogLevelSelector other = (LogLevelSelector) obj; - - if (logLevel != other.logLevel) { - return false; - } - if (logLevelType != other.logLevelType) { - return false; - } - return true; - } - - @Override - public String toString() { - if (getLogLevelType() == LogLevelType.LTTNG_EVENT_LOGLEVEL_ALL) { - return LogLevelType.LTTNG_EVENT_LOGLEVEL_ALL.toString(); - } - return String.valueOf(getLogLevel()) + ", " + getLogLevelType().toString(); - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/utils/LttngUstAgentLogger.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/utils/LttngUstAgentLogger.java deleted file mode 100644 index 3e78553b..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/utils/LttngUstAgentLogger.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.utils; - -/** - * Logging infrastructure for the lttng-ust Java agent. It prints log messages - * to stderr but only when the environment variable LTTNG_UST_DEBUG is defined. - * - * @author Alexandre Montplaisir - */ -public class LttngUstAgentLogger { - - private static final String ENV_VAR_NAME = "LTTNG_UST_DEBUG"; - private static final boolean LOGGING_ENABLED = (System.getenv(ENV_VAR_NAME) == null ? false : true); - - /** - * Log event. Will be printed to stderr if the environment variable - * "LTTNG_UST_DEBUG" is defined. - * - * @param c - * The class logging the message (should normally be called with - * {@link #getClass()}). - * @param message - * The message to print - */ - public static void log(Class c, String message) { - if (LOGGING_ENABLED) { - System.err.println(c.getSimpleName() + ": " + message); - } - } -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile.am b/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile.am deleted file mode 100644 index 91ac2035..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile.am +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-only - -JAVAROOT = . -AM_JAVACFLAGS = -classpath $(CLASSPATH):$(builddir)/../lttng-ust-agent-common/lttng-ust-agent-common.jar - -pkgpath = org/lttng/ust/agent/jul - -jarfile_version = 1.0.0 -jarfile_manifest = $(srcdir)/Manifest.txt -jarfile_symlink = lttng-ust-agent-jul.jar -jarfile = lttng-ust-agent-jul-$(jarfile_version).jar - -jardir = $(datadir)/java - -juljniout = ../../jni/jul - -dist_noinst_JAVA = $(pkgpath)/LttngJulAgent.java \ - $(pkgpath)/LttngJulApi.java \ - $(pkgpath)/LttngLogHandler.java - -dist_noinst_DATA = $(jarfile_manifest) - -jar_DATA = $(jarfile) - -stamp = jul-jni-header.stamp -classes = $(pkgpath)/*.class - -$(jarfile): classnoinst.stamp - $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink) - -if !HAVE_JAVAH -# If we don't have javah, assume we are running openjdk >= 10 and use javac -# to generate the jni header file. -AM_JAVACFLAGS += -h $(juljniout) -else -jul-jni-header.stamp: $(dist_noinst_JAVA) - $(JAVAH) -classpath $(CLASSPATH):$(srcdir) -d $(juljniout) $(JAVAHFLAGS) org.lttng.ust.agent.jul.LttngJulApi && \ - echo "JUL JNI header generated" > jul-jni-header.stamp - -all-local: $(stamp) -endif - -install-data-hook: - cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink) - -uninstall-hook: - cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) - -CLEANFILES = *.jar \ - $(pkgpath)/*.class \ - jul-jni-header.stamp \ - $(juljniout)/org_lttng_ust_agent_jul_LttngJulApi.h diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Manifest.txt b/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Manifest.txt deleted file mode 100644 index 4aba3600..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/Manifest.txt +++ /dev/null @@ -1,8 +0,0 @@ -Name: org/lttng/ust/agent/jul/ -Specification-Title: LTTng UST Java Agent JUL Integration -Specification-Version: 1.0.0 -Specification-Vendor: LTTng Project -Implementation-Title: org.lttng.ust.agent.jul -Implementation-Version: 1.0.0 -Implementation-Vendor: LTTng Project -Class-Path: lttng-ust-agent-common.jar diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulAgent.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulAgent.java deleted file mode 100644 index 99c5fde0..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulAgent.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.jul; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import java.util.logging.Handler; -import java.util.logging.LogManager; -import java.util.logging.Logger; - -import org.lttng.ust.agent.AbstractLttngAgent; - -/** - * Agent implementation for tracing from JUL loggers. - * - * @author Alexandre Montplaisir - */ -class LttngJulAgent extends AbstractLttngAgent { - - private static LttngJulAgent instance = null; - - private LttngJulAgent() { - super(Domain.JUL); - } - - public static synchronized LttngJulAgent getInstance() { - if (instance == null) { - instance = new LttngJulAgent(); - } - return instance; - } - - @Override - public Collection listAvailableEvents() { - Set ret = new TreeSet(); - - List loggersNames = Collections.list(LogManager.getLogManager().getLoggerNames()); - for (String name : loggersNames) { - /* - * Skip the root logger. An empty string is not a valid event name - * in LTTng. - */ - if (name.equals("") || name.equals("global")) { - continue; - } - - /* - * Check if that logger has at least one LTTng JUL handler attached. - */ - Logger logger = Logger.getLogger(name); - if (hasLttngHandlerAttached(logger)) { - ret.add(name); - } - } - - return ret; - } - - private static boolean hasLttngHandlerAttached(Logger logger) { - for (Handler handler : logger.getHandlers()) { - if (handler instanceof LttngLogHandler) { - return true; - } - } - - /* - * A parent logger, if any, may be connected to an LTTng handler. In - * this case, we will want to include this child logger in the output, - * since it will be accessible by LTTng. - */ - Logger parent = logger.getParent(); - if (parent != null) { - return hasLttngHandlerAttached(parent); - } - - /* - * We have reached the root logger and have not found any LTTng handler, - * this event will not be accessible. - */ - return false; - } - -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulApi.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulApi.java deleted file mode 100644 index 07b0cde0..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulApi.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.jul; - -/** - * Virtual class containing the Java side of the LTTng-JUL JNI API methods. - * - * @author Alexandre Montplaisir - */ -final class LttngJulApi { - - private LttngJulApi() {} - - static native void tracepoint(String msg, - String logger_name, - String class_name, - String method_name, - long millis, - int log_level, - int thread_id); - - static native void tracepointWithContext(String msg, - String logger_name, - String class_name, - String method_name, - long millis, - int log_level, - int thread_id, - byte[] contextEntries, - byte[] contextStrings); -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngLogHandler.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngLogHandler.java deleted file mode 100644 index 42bea9c4..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngLogHandler.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - * Copyright (C) 2013 David Goulet - */ - -package org.lttng.ust.agent.jul; - -import java.io.IOException; -import java.util.Collection; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.atomic.AtomicLong; -import java.util.logging.Formatter; -import java.util.logging.Handler; -import java.util.logging.LogRecord; - -import org.lttng.ust.agent.ILttngAgent; -import org.lttng.ust.agent.ILttngHandler; -import org.lttng.ust.agent.context.ContextInfoSerializer; - -/** - * LTTng-UST JUL log handler. - * - * Applications can attach this handler to their - * {@link java.util.logging.Logger} to have it generate UST events from logging - * events received through the logger. - * - * It sends its events to UST via the JNI library "liblttng-ust-jul-jni.so". - * Make sure this library is available before using this handler. - * - * @author Alexandre Montplaisir - * @author David Goulet - */ -public class LttngLogHandler extends Handler implements ILttngHandler { - - private static final String SHARED_OBJECT_NAME = "lttng-ust-jul-jni"; - - /** - * Dummy Formatter object, so we can use its - * {@link Formatter#formatMessage(LogRecord)} method. - */ - private static final Formatter FORMATTER = new Formatter() { - @Override - public String format(LogRecord record) { - throw new UnsupportedOperationException(); - } - }; - - private final ILttngAgent agent; - - /** Number of events logged (really sent through JNI) by this handler */ - private final AtomicLong eventCount = new AtomicLong(0); - - /** - * Constructor - * - * @throws IOException - * This handler requires the lttng-ust-jul-jni.so native - * library, through which it will send the trace events. This - * exception is throw is this library cannot be found. - * @throws SecurityException - * We will forward any SecurityExcepion that may be thrown when - * trying to load the JNI library. - */ - public LttngLogHandler() throws IOException, SecurityException { - super(); - /* Initialize LTTng UST tracer. */ - try { - System.loadLibrary(SHARED_OBJECT_NAME); //$NON-NLS-1$ - } catch (UnsatisfiedLinkError e) { - throw new IOException(e); - } - - /** Register to the relevant agent */ - agent = LttngJulAgent.getInstance(); - agent.registerHandler(this); - } - - @Override - public synchronized void close() { - agent.unregisterHandler(this); - } - - /** - * Get the number of events logged by this handler so far. This means the - * number of events actually sent through JNI to UST. - * - * @return The number of events logged so far - */ - @Override - public long getEventCount() { - return eventCount.get(); - } - - @Override - public void flush() { - } - - @Override - public void publish(LogRecord record) { - /* - * Check if the current message should be logged, according to the UST - * session settings. - */ - if (!agent.isEventEnabled(record.getLoggerName())) { - return; - } - - String formattedMessage = FORMATTER.formatMessage(record); - - /* Retrieve all the requested context information we can find */ - Collection>> enabledContexts = agent.getEnabledAppContexts(); - ContextInfoSerializer.SerializedContexts contextInfo = ContextInfoSerializer.queryAndSerializeRequestedContexts(enabledContexts); - - eventCount.incrementAndGet(); - - /* - * Specific tracepoint designed for JUL events. The source class of the - * caller is used for the event name, the raw message is taken, the - * loglevel of the record and the thread ID. - */ - LttngJulApi.tracepointWithContext(formattedMessage, - record.getLoggerName(), - record.getSourceClassName(), - record.getSourceMethodName(), - record.getMillis(), - record.getLevel().intValue(), - record.getThreadID(), - contextInfo.getEntriesArray(), - contextInfo.getStringsArray()); - } - -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile.am b/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile.am deleted file mode 100644 index 009f1416..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile.am +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-only - -JAVAROOT = . -AM_JAVACFLAGS = -classpath $(CLASSPATH):$(builddir)/../lttng-ust-agent-common/lttng-ust-agent-common.jar - -pkgpath = org/lttng/ust/agent/log4j - -jarfile_version = 1.0.0 -jarfile_manifest = $(srcdir)/Manifest.txt -jarfile_symlink = lttng-ust-agent-log4j.jar -jarfile = lttng-ust-agent-log4j-$(jarfile_version).jar - -jardir = $(datadir)/java - -log4jjniout = ../../jni/log4j - -dist_noinst_JAVA = $(pkgpath)/LttngLog4jAgent.java \ - $(pkgpath)/LttngLog4jApi.java \ - $(pkgpath)/LttngLogAppender.java - -dist_noinst_DATA = $(jarfile_manifest) - -jar_DATA = $(jarfile) - -stamp = log4j-jni-header.stamp -classes = $(pkgpath)/*.class - -$(jarfile): classnoinst.stamp - $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink) - -if !HAVE_JAVAH -# If we don't have javah, assume we are running openjdk >= 10 and use javac -# to generate the jni header file. -AM_JAVACFLAGS += -h $(log4jjniout) -else -log4j-jni-header.stamp: $(dist_noinst_JAVA) - $(JAVAH) -classpath $(CLASSPATH):$(srcdir) -d $(log4jjniout) $(JAVAHFLAGS) org.lttng.ust.agent.log4j.LttngLog4jApi && \ - echo "Log4j JNI header generated" > log4j-jni-header.stamp - -all-local: $(stamp) -endif - -install-data-hook: - cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink) - -uninstall-hook: - cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) - -CLEANFILES = *.jar \ - $(pkgpath)/*.class \ - log4j-jni-header.stamp \ - $(log4jjniout)/org_lttng_ust_agent_log4j_LttngLog4jApi.h diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Manifest.txt b/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Manifest.txt deleted file mode 100644 index d7b98f42..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Manifest.txt +++ /dev/null @@ -1,8 +0,0 @@ -Name: org/lttng/ust/agent/log4j/ -Specification-Title: LTTng UST Java Agent Log4J 1.x Integration -Specification-Version: 1.0.0 -Specification-Vendor: LTTng Project -Implementation-Title: org.lttng.ust.agent.log4j -Implementation-Version: 1.0.0 -Implementation-Vendor: LTTng Project -Class-Path: lttng-ust-agent-common.jar diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jAgent.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jAgent.java deleted file mode 100644 index bb5deb35..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jAgent.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.log4j; - -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; - -import org.apache.log4j.Appender; -import org.apache.log4j.Category; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.lttng.ust.agent.AbstractLttngAgent; - -/** - * Agent implementation for using the Log4j logger, connecting to a root session - * daemon. - * - * @author Alexandre Montplaisir - */ -class LttngLog4jAgent extends AbstractLttngAgent { - - private static LttngLog4jAgent instance = null; - - private LttngLog4jAgent() { - super(Domain.LOG4J); - } - - public static synchronized LttngLog4jAgent getInstance() { - if (instance == null) { - instance = new LttngLog4jAgent(); - } - return instance; - } - - @Override - public Collection listAvailableEvents() { - Set ret = new TreeSet(); - - @SuppressWarnings("unchecked") - List loggers = Collections.list(LogManager.getCurrentLoggers()); - for (Logger logger : loggers) { - if (logger == null) { - continue; - } - - /* - * Check if that logger has at least one LTTng log4j appender - * attached. - */ - if (hasLttngAppenderAttached(logger)) { - ret.add(logger.getName()); - } - } - - return ret; - } - - private static boolean hasLttngAppenderAttached(Category logger) { - @SuppressWarnings("unchecked") - Enumeration appenders = logger.getAllAppenders(); - if (appenders != null) { - for (Appender appender : Collections.list(appenders)) { - if (appender instanceof LttngLogAppender) { - return true; - } - } - } - - /* - * A parent logger, if any, may be connected to an LTTng handler. In - * this case, we will want to include this child logger in the output, - * since it will be accessible by LTTng. - */ - Category parent = logger.getParent(); - if (parent != null) { - return hasLttngAppenderAttached(parent); - } - - /* - * We have reached the root logger and have not found any LTTng handler, - * this event will not be accessible. - */ - return false; - } - -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jApi.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jApi.java deleted file mode 100644 index c3e76eec..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jApi.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.log4j; - -/** - * Virtual class containing the Java side of the LTTng-log4j JNI API methods. - * - * @author Alexandre Montplaisir - */ -final class LttngLog4jApi { - - private LttngLog4jApi() {} - - static native void tracepoint(String msg, - String logger_name, - String class_name, - String method_name, - String file_name, - int line_number, - long timestamp, - int loglevel, - String thread_name); - - static native void tracepointWithContext(String msg, - String logger_name, - String class_name, - String method_name, - String file_name, - int line_number, - long timestamp, - int loglevel, - String thread_name, - byte[] contextEntries, - byte[] contextStrings); -} diff --git a/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLogAppender.java b/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLogAppender.java deleted file mode 100644 index c232fb8b..00000000 --- a/src/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLogAppender.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2015 EfficiOS Inc. - * Copyright (C) 2015 Alexandre Montplaisir - * Copyright (C) 2014 Christian Babeux - */ - -package org.lttng.ust.agent.log4j; - -import java.io.IOException; -import java.util.Collection; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.atomic.AtomicLong; - -import org.apache.log4j.AppenderSkeleton; -import org.apache.log4j.spi.LoggingEvent; -import org.lttng.ust.agent.ILttngAgent; -import org.lttng.ust.agent.ILttngHandler; -import org.lttng.ust.agent.context.ContextInfoSerializer; - -/** - * LTTng-UST Log4j 1.x log handler. - * - * Applications can attach this appender to their - * {@link org.apache.log4j.Logger} to have it generate UST events from logging - * events received through the logger. - * - * It sends its events to UST via the JNI library "liblttng-ust-log4j-jni.so". - * Make sure this library is available before using this appender. - * - * @author Alexandre Montplaisir - * @author Christian Babeux - */ -public class LttngLogAppender extends AppenderSkeleton implements ILttngHandler { - - private static final String SHARED_OBJECT_NAME = "lttng-ust-log4j-jni"; - - private final AtomicLong eventCount = new AtomicLong(0); - - private final ILttngAgent agent; - - - /** - * Constructor - * - * @throws IOException - * This handler requires the lttng-ust-log4j-jni.so native - * library, through which it will send the trace events. This - * exception is throw is this library cannot be found. - * @throws SecurityException - * We will forward any SecurityExcepion that may be thrown when - * trying to load the JNI library. - */ - public LttngLogAppender() throws IOException, SecurityException { - super(); - /* Initialize LTTng UST tracer. */ - try { - System.loadLibrary(SHARED_OBJECT_NAME); // $NON-NLS-1$ - } catch (UnsatisfiedLinkError e) { - throw new IOException(e); - } - - /** Register to the relevant agent */ - agent = LttngLog4jAgent.getInstance(); - agent.registerHandler(this); - } - - @Override - public synchronized void close() { - agent.unregisterHandler(this); - } - - /** - * Get the number of events logged by this handler so far. This means the - * number of events actually sent through JNI to UST. - * - * @return The number of events logged so far - */ - @Override - public long getEventCount() { - return eventCount.get(); - } - - @Override - public boolean requiresLayout() { - return false; - } - - @Override - protected void append(LoggingEvent event) { - /* - * Check if the current message should be logged, according to the UST - * session settings. - */ - if (!agent.isEventEnabled(event.getLoggerName())) { - return; - } - - /* - * The line number returned from LocationInformation is a string. At - * least try to convert to a proper int. - */ - int line; - try { - String lineString = event.getLocationInformation().getLineNumber(); - line = Integer.parseInt(lineString); - } catch (NumberFormatException n) { - line = -1; - } - - /* Retrieve all the requested context information we can find */ - Collection>> enabledContexts = agent.getEnabledAppContexts(); - ContextInfoSerializer.SerializedContexts contextInfo = ContextInfoSerializer.queryAndSerializeRequestedContexts(enabledContexts); - - eventCount.incrementAndGet(); - - LttngLog4jApi.tracepointWithContext(event.getRenderedMessage(), - event.getLoggerName(), - event.getLocationInformation().getClassName(), - event.getLocationInformation().getMethodName(), - event.getLocationInformation().getFileName(), - line, - event.getTimeStamp(), - event.getLevel().toInt(), - event.getThreadName(), - contextInfo.getEntriesArray(), - contextInfo.getStringsArray()); - } - -} diff --git a/src/liblttng-ust-java-agent/jni/Makefile.am b/src/liblttng-ust-java-agent/jni/Makefile.am deleted file mode 100644 index 711fd475..00000000 --- a/src/liblttng-ust-java-agent/jni/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-only - -SUBDIRS = common - -if ENABLE_JAVA_AGENT_WITH_JUL -SUBDIRS += jul -endif - -if ENABLE_JAVA_AGENT_WITH_LOG4J -SUBDIRS += log4j -endif diff --git a/src/liblttng-ust-java-agent/jni/common/Makefile.am b/src/liblttng-ust-java-agent/jni/common/Makefile.am deleted file mode 100644 index c066157b..00000000 --- a/src/liblttng-ust-java-agent/jni/common/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-only - -AM_CPPFLAGS += -I$(builddir) -I$(srcdir) $(JNI_CPPFLAGS) - -lib_LTLIBRARIES = liblttng-ust-context-jni.la -liblttng_ust_context_jni_la_SOURCES = lttng_ust_context.c lttng_ust_context.h - -nodist_liblttng_ust_context_jni_la_SOURCES = org_lttng_ust_agent_context_LttngContextApi.h - -liblttng_ust_context_jni_la_LIBADD = -lc \ - $(top_builddir)/src/liblttng-ust/liblttng-ust.la diff --git a/src/liblttng-ust-java-agent/jni/common/lttng_ust_context.c b/src/liblttng-ust-java-agent/jni/common/lttng_ust_context.c deleted file mode 100644 index 8570b211..00000000 --- a/src/liblttng-ust-java-agent/jni/common/lttng_ust_context.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - * Copyright (C) 2016 Mathieu Desnoyers - */ - -#include "org_lttng_ust_agent_context_LttngContextApi.h" - -#include -#include -#include -#include -#include - -#include "common/macros.h" -#include "lttng_ust_context.h" - -enum lttng_ust_jni_type { - JNI_TYPE_NULL = 0, - JNI_TYPE_INTEGER = 1, - JNI_TYPE_LONG = 2, - JNI_TYPE_DOUBLE = 3, - JNI_TYPE_FLOAT = 4, - JNI_TYPE_BYTE = 5, - JNI_TYPE_SHORT = 6, - JNI_TYPE_BOOLEAN = 7, - JNI_TYPE_STRING = 8, -}; - -struct lttng_ust_jni_ctx_entry { - int32_t context_name_offset; - char type; /* enum lttng_ust_jni_type */ - union { - int32_t _integer; - int64_t _long; - double _double; - float _float; - signed char _byte; - int16_t _short; - signed char _boolean; - int32_t _string_offset; - } value; -} __attribute__((packed)); - -struct lttng_ust_jni_provider { - struct lttng_ust_registered_context_provider *reg_provider; - char *name; - struct lttng_ust_context_provider provider; -}; - -/* TLS passing context info from JNI to callbacks. */ -__thread struct lttng_ust_jni_tls lttng_ust_context_info_tls; - -static const char *get_ctx_string_at_offset(int32_t offset) -{ - signed char *ctx_strings_array = lttng_ust_context_info_tls.ctx_strings; - - if (offset < 0 || offset >= lttng_ust_context_info_tls.ctx_strings_len) { - return NULL; - } - return (const char *) (ctx_strings_array + offset); -} - -static struct lttng_ust_jni_ctx_entry *lookup_ctx_by_name(const char *ctx_name) -{ - struct lttng_ust_jni_ctx_entry *ctx_entries_array = lttng_ust_context_info_tls.ctx_entries; - int i, len = lttng_ust_context_info_tls.ctx_entries_len / sizeof(struct lttng_ust_jni_ctx_entry); - - for (i = 0; i < len; i++) { - int32_t offset = ctx_entries_array[i].context_name_offset; - const char *string = get_ctx_string_at_offset(offset); - - if (string && strcmp(string, ctx_name) == 0) { - return &ctx_entries_array[i]; - } - } - return NULL; -} - -static size_t get_size_cb(void *priv, size_t offset) -{ - struct lttng_ust_jni_ctx_entry *jctx; - size_t size = 0; - struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv; - const char *ctx_name = jni_provider->name; - enum lttng_ust_jni_type jni_type; - - size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(char)); - size += sizeof(char); /* tag */ - jctx = lookup_ctx_by_name(ctx_name); - if (!jctx) { - jni_type = JNI_TYPE_NULL; - } else { - jni_type = jctx->type; - } - switch (jni_type) { - case JNI_TYPE_NULL: - break; - case JNI_TYPE_INTEGER: - size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(int32_t)); - size += sizeof(int32_t); /* variant */ - break; - case JNI_TYPE_LONG: - size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(int64_t)); - size += sizeof(int64_t); /* variant */ - break; - case JNI_TYPE_DOUBLE: - size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(double)); - size += sizeof(double); /* variant */ - break; - case JNI_TYPE_FLOAT: - size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(float)); - size += sizeof(float); /* variant */ - break; - case JNI_TYPE_SHORT: - size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(int16_t)); - size += sizeof(int16_t); /* variant */ - break; - case JNI_TYPE_BYTE: /* Fall-through. */ - case JNI_TYPE_BOOLEAN: - size += lttng_ust_lib_ring_buffer_align(offset, lttng_ust_rb_alignof(char)); - size += sizeof(char); /* variant */ - break; - case JNI_TYPE_STRING: - { - /* The value is an offset, the string is in the "strings" array */ - int32_t string_offset = jctx->value._string_offset; - const char *string = get_ctx_string_at_offset(string_offset); - - if (string) { - size += strlen(string) + 1; - } - break; - } - default: - abort(); - } - return size; - -} - -static void record_cb(void *priv, - struct lttng_ust_lib_ring_buffer_ctx *ctx, - struct lttng_ust_channel_buffer *lttng_chan_buf) -{ - struct lttng_ust_jni_ctx_entry *jctx; - struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv; - const char *ctx_name = jni_provider->name; - enum lttng_ust_jni_type jni_type; - char sel_char; - - jctx = lookup_ctx_by_name(ctx_name); - if (!jctx) { - jni_type = JNI_TYPE_NULL; - } else { - jni_type = jctx->type; - } - - switch (jni_type) { - case JNI_TYPE_NULL: - sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE; - lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); - break; - case JNI_TYPE_INTEGER: - { - int32_t v = jctx->value._integer; - - sel_char = LTTNG_UST_DYNAMIC_TYPE_S32; - lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); - lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); - break; - } - case JNI_TYPE_LONG: - { - int64_t v = jctx->value._long; - - sel_char = LTTNG_UST_DYNAMIC_TYPE_S64; - lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); - lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); - break; - } - case JNI_TYPE_DOUBLE: - { - double v = jctx->value._double; - - sel_char = LTTNG_UST_DYNAMIC_TYPE_DOUBLE; - lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); - lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); - break; - } - case JNI_TYPE_FLOAT: - { - float v = jctx->value._float; - - sel_char = LTTNG_UST_DYNAMIC_TYPE_FLOAT; - lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); - lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); - break; - } - case JNI_TYPE_SHORT: - { - int16_t v = jctx->value._short; - - sel_char = LTTNG_UST_DYNAMIC_TYPE_S16; - lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); - lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); - break; - } - case JNI_TYPE_BYTE: - { - char v = jctx->value._byte; - - sel_char = LTTNG_UST_DYNAMIC_TYPE_S8; - lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); - lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); - break; - } - case JNI_TYPE_BOOLEAN: - { - char v = jctx->value._boolean; - - sel_char = LTTNG_UST_DYNAMIC_TYPE_S8; - lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); - lttng_chan_buf->ops->event_write(ctx, &v, sizeof(v), lttng_ust_rb_alignof(v)); - break; - } - case JNI_TYPE_STRING: - { - int32_t offset = jctx->value._string_offset; - const char *str = get_ctx_string_at_offset(offset); - - if (str) { - sel_char = LTTNG_UST_DYNAMIC_TYPE_STRING; - } else { - sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE; - } - lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char)); - if (str) { - lttng_chan_buf->ops->event_write(ctx, str, strlen(str) + 1, 1); - } - break; - } - default: - abort(); - } -} - -static void get_value_cb(void *priv, struct lttng_ust_ctx_value *value) -{ - struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv; - struct lttng_ust_jni_ctx_entry *jctx; - const char *ctx_name = jni_provider->name; - enum lttng_ust_jni_type jni_type; - - jctx = lookup_ctx_by_name(ctx_name); - if (!jctx) { - jni_type = JNI_TYPE_NULL; - } else { - jni_type = jctx->type; - } - - switch (jni_type) { - case JNI_TYPE_NULL: - value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE; - break; - case JNI_TYPE_INTEGER: - value->sel = LTTNG_UST_DYNAMIC_TYPE_S64; - value->u.s64 = (int64_t) jctx->value._integer; - break; - case JNI_TYPE_LONG: - value->sel = LTTNG_UST_DYNAMIC_TYPE_S64; - value->u.s64 = jctx->value._long; - break; - case JNI_TYPE_DOUBLE: - value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE; - value->u.d = jctx->value._double; - break; - case JNI_TYPE_FLOAT: - value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE; - value->u.d = (double) jctx->value._float; - break; - case JNI_TYPE_SHORT: - value->sel = LTTNG_UST_DYNAMIC_TYPE_S64; - value->u.s64 = (int64_t) jctx->value._short; - break; - case JNI_TYPE_BYTE: - value->sel = LTTNG_UST_DYNAMIC_TYPE_S64; - value->u.s64 = (int64_t) jctx->value._byte; - break; - case JNI_TYPE_BOOLEAN: - value->sel = LTTNG_UST_DYNAMIC_TYPE_S64; - value->u.s64 = (int64_t) jctx->value._boolean; - break; - case JNI_TYPE_STRING: - { - int32_t offset = jctx->value._string_offset; - const char *str = get_ctx_string_at_offset(offset); - - if (str) { - value->sel = LTTNG_UST_DYNAMIC_TYPE_STRING; - value->u.str = str; - } else { - value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE; - } - break; - } - default: - abort(); - } -} - -/* - * Register a context provider to UST. - * - * Called from the Java side when an application registers a context retriever, - * so we create and register a corresponding provider on the C side. - */ -JNIEXPORT jlong JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv *env, - jobject jobj __attribute__((unused)), - jstring provider_name) -{ - jboolean iscopy; - const char *provider_name_jstr; - char *provider_name_cstr; - struct lttng_ust_context_provider *provider; - struct lttng_ust_jni_provider *jni_provider; - /* - * Note: a "jlong" is 8 bytes on all architectures, whereas a - * C "long" varies. - */ - jlong provider_ref; - - provider_name_jstr = (*env)->GetStringUTFChars(env, provider_name, &iscopy); - if (!provider_name_jstr) { - goto error_jstr; - } - /* Keep our own copy of the string so UST can use it. */ - provider_name_cstr = strdup(provider_name_jstr); - (*env)->ReleaseStringUTFChars(env, provider_name, provider_name_jstr); - if (!provider_name_cstr) { - goto error_strdup; - } - jni_provider = zmalloc(sizeof(*jni_provider)); - if (!jni_provider) { - goto error_provider; - } - provider = &jni_provider->provider; - provider->struct_size = sizeof(*provider); - jni_provider->name = provider_name_cstr; - provider->name = jni_provider->name; - provider->get_size = get_size_cb; - provider->record = record_cb; - provider->get_value = get_value_cb; - provider->priv = jni_provider; - - jni_provider->reg_provider = lttng_ust_context_provider_register(provider); - if (!jni_provider->reg_provider) { - goto error_register; - } - - provider_ref = (jlong) (long) jni_provider; - return provider_ref; - - /* Error handling. */ -error_register: - free(jni_provider); -error_provider: - free(provider_name_cstr); -error_strdup: -error_jstr: - return 0; -} - -/* - * Unregister a previously-registered context provider. - * - * Called from the Java side when an application unregisters a context retriever, - * so we unregister and delete the corresponding provider on the C side. - */ -JNIEXPORT void JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv *env __attribute__((unused)), - jobject jobj __attribute__((unused)), - jlong provider_ref) -{ - struct lttng_ust_jni_provider *jni_provider = - (struct lttng_ust_jni_provider *) (unsigned long) provider_ref; - - if (!jni_provider) { - return; - } - - lttng_ust_context_provider_unregister(jni_provider->reg_provider); - - free(jni_provider->name); - free(jni_provider); -} diff --git a/src/liblttng-ust-java-agent/jni/common/lttng_ust_context.h b/src/liblttng-ust-java-agent/jni/common/lttng_ust_context.h deleted file mode 100644 index ab003c89..00000000 --- a/src/liblttng-ust-java-agent/jni/common/lttng_ust_context.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - */ - -#ifndef LIBLTTNG_UST_JAVA_AGENT_JNI_COMMON_LTTNG_UST_CONTEXT_H_ -#define LIBLTTNG_UST_JAVA_AGENT_JNI_COMMON_LTTNG_UST_CONTEXT_H_ - -struct lttng_ust_jni_ctx_entry; - -struct lttng_ust_jni_tls { - struct lttng_ust_jni_ctx_entry *ctx_entries; - int32_t ctx_entries_len; - signed char *ctx_strings; - int32_t ctx_strings_len; -}; - -extern __thread struct lttng_ust_jni_tls lttng_ust_context_info_tls; - -#endif /* LIBLTTNG_UST_JAVA_AGENT_JNI_COMMON_LTTNG_UST_CONTEXT_H_ */ diff --git a/src/liblttng-ust-java-agent/jni/jul/Makefile.am b/src/liblttng-ust-java-agent/jni/jul/Makefile.am deleted file mode 100644 index 32089ae3..00000000 --- a/src/liblttng-ust-java-agent/jni/jul/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-only - -AM_CPPFLAGS += -I$(builddir) -I$(srcdir) $(JNI_CPPFLAGS) - -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_LttngJulApi.h - -liblttng_ust_jul_jni_la_LIBADD = -lc \ - $(top_builddir)/src/liblttng-ust/liblttng-ust.la \ - $(top_builddir)/src/liblttng-ust-java-agent/jni/common/liblttng-ust-context-jni.la diff --git a/src/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.c b/src/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.c deleted file mode 100644 index afc9f111..00000000 --- a/src/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - * Copyright (C) 2011-2012 Mathieu Desnoyers - */ - -#define _LGPL_SOURCE -#include "org_lttng_ust_agent_jul_LttngJulApi.h" - -#define TRACEPOINT_DEFINE -#define TRACEPOINT_CREATE_PROBES -#include "lttng_ust_jul.h" -#include "../common/lttng_ust_context.h" - -/* - * Deprecated function from before the context information was passed. - */ -JNIEXPORT void JNICALL Java_org_lttng_ust_agent_jul_LttngJulApi_tracepoint(JNIEnv *env, - jobject jobj __attribute__((unused)), - 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, 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); -} - -/* - * Tracepoint used by Java applications using the JUL handler. - */ -JNIEXPORT void JNICALL Java_org_lttng_ust_agent_jul_LttngJulApi_tracepointWithContext(JNIEnv *env, - jobject jobj __attribute__((unused)), - jstring msg, - jstring logger_name, - jstring class_name, - jstring method_name, - jlong millis, - jint log_level, - jint thread_id, - jbyteArray context_info_entries, - jbyteArray context_info_strings) -{ - 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); - signed char *context_info_entries_array; - signed char *context_info_strings_array; - - /* - * Write these to the TLS variables, so that the UST callbacks in - * lttng_ust_context.c can access them. - */ - context_info_entries_array = (*env)->GetByteArrayElements(env, context_info_entries, &iscopy); - lttng_ust_context_info_tls.ctx_entries = (struct lttng_ust_jni_ctx_entry *) context_info_entries_array; - lttng_ust_context_info_tls.ctx_entries_len = (*env)->GetArrayLength(env, context_info_entries); - context_info_strings_array = (*env)->GetByteArrayElements(env, context_info_strings, &iscopy); - lttng_ust_context_info_tls.ctx_strings = context_info_strings_array; - lttng_ust_context_info_tls.ctx_strings_len = (*env)->GetArrayLength(env, context_info_strings); - - tracepoint(lttng_jul, event, msg_cstr, logger_name_cstr, - class_name_cstr, method_name_cstr, millis, log_level, thread_id); - - lttng_ust_context_info_tls.ctx_entries = NULL; - lttng_ust_context_info_tls.ctx_entries_len = 0; - lttng_ust_context_info_tls.ctx_strings = NULL; - lttng_ust_context_info_tls.ctx_strings_len = 0; - (*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)->ReleaseByteArrayElements(env, context_info_entries, context_info_entries_array, 0); - (*env)->ReleaseByteArrayElements(env, context_info_strings, context_info_strings_array, 0); -} diff --git a/src/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.h b/src/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.h deleted file mode 100644 index 13003bf2..00000000 --- a/src/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2011 Mathieu Desnoyers - */ - -#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 - -#include - -/* - * Tracepoint used by Java applications using the JUL handler. - */ -TRACEPOINT_EVENT(lttng_jul, 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/src/liblttng-ust-java-agent/jni/log4j/Makefile.am b/src/liblttng-ust-java-agent/jni/log4j/Makefile.am deleted file mode 100644 index 383bb9cb..00000000 --- a/src/liblttng-ust-java-agent/jni/log4j/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-only - -AM_CPPFLAGS += -I$(builddir) -I$(srcdir) $(JNI_CPPFLAGS) - -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_LttngLog4jApi.h - -liblttng_ust_log4j_jni_la_LIBADD = -lc \ - $(top_builddir)/src/liblttng-ust/liblttng-ust.la \ - $(top_builddir)/src/liblttng-ust-java-agent/jni/common/liblttng-ust-context-jni.la diff --git a/src/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c b/src/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c deleted file mode 100644 index e88235a6..00000000 --- a/src/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - * Copyright (C) 2011-2012 Mathieu Desnoyers - */ - -#define _LGPL_SOURCE -#include "org_lttng_ust_agent_log4j_LttngLog4jApi.h" - -#define TRACEPOINT_DEFINE -#define TRACEPOINT_CREATE_PROBES -#include "lttng_ust_log4j.h" -#include "../common/lttng_ust_context.h" - -/* - * Deprecated function from before the context information was passed. - */ -JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j_LttngLog4jApi_tracepoint(JNIEnv *env, - jobject jobj __attribute__((unused)), - 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, 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); -} - -/* - * Tracepoint used by Java applications using the log4j handler. - */ -JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j_LttngLog4jApi_tracepointWithContext(JNIEnv *env, - jobject jobj __attribute__((unused)), - jstring msg, - jstring logger_name, - jstring class_name, - jstring method_name, - jstring file_name, - jint line_number, - jlong timestamp, - jint loglevel, - jstring thread_name, - jbyteArray context_info_entries, - jbyteArray context_info_strings) -{ - 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); - signed char *context_info_entries_array; - signed char *context_info_strings_array; - - /* - * Write these to the TLS variables, so that the UST callbacks in - * lttng_ust_context.c can access them. - */ - context_info_entries_array = (*env)->GetByteArrayElements(env, context_info_entries, &iscopy); - lttng_ust_context_info_tls.ctx_entries = (struct lttng_ust_jni_ctx_entry *) context_info_entries_array; - lttng_ust_context_info_tls.ctx_entries_len = (*env)->GetArrayLength(env, context_info_entries); - context_info_strings_array = (*env)->GetByteArrayElements(env, context_info_strings, &iscopy); - lttng_ust_context_info_tls.ctx_strings = context_info_strings_array; - lttng_ust_context_info_tls.ctx_strings_len = (*env)->GetArrayLength(env, context_info_strings); - - tracepoint(lttng_log4j, event, msg_cstr, logger_name_cstr, - class_name_cstr, method_name_cstr, file_name_cstr, - line_number, timestamp, loglevel, thread_name_cstr); - - lttng_ust_context_info_tls.ctx_entries = NULL; - lttng_ust_context_info_tls.ctx_entries_len = 0; - lttng_ust_context_info_tls.ctx_strings = NULL; - lttng_ust_context_info_tls.ctx_strings_len = 0; - (*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); - (*env)->ReleaseByteArrayElements(env, context_info_entries, context_info_entries_array, 0); - (*env)->ReleaseByteArrayElements(env, context_info_strings, context_info_strings_array, 0); -} diff --git a/src/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h b/src/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h deleted file mode 100644 index c7d7d525..00000000 --- a/src/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2011 Mathieu Desnoyers - */ - -#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 - -#include - -/* - * Tracepoint used by Java applications using the log4j log appender. - */ -TRACEPOINT_EVENT(lttng_log4j, 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/src/liblttng-ust-java/.gitignore b/src/liblttng-ust-java/.gitignore deleted file mode 100644 index e07ee503..00000000 --- a/src/liblttng-ust-java/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -org_lttng_ust_LTTngUst.h -org/ -liblttng-ust-java.jar diff --git a/src/liblttng-ust-java/LTTngUst.c b/src/liblttng-ust-java/LTTngUst.c deleted file mode 100644 index f5e0c96b..00000000 --- a/src/liblttng-ust-java/LTTngUst.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2011-2012 Mathieu Desnoyers - */ - -#define _LGPL_SOURCE -#include "org_lttng_ust_LTTngUst.h" - -#define TRACEPOINT_DEFINE -#define TRACEPOINT_CREATE_PROBES -#include "lttng_ust_java.h" - -JNIEXPORT void JNICALL Java_org_lttng_ust_LTTngUst_tracepointInt(JNIEnv *env, - jobject jobj __attribute__((unused)), - jstring ev_name, - jint payload) -{ - jboolean iscopy; - const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, &iscopy); - - tracepoint(lttng_ust_java, int_event, ev_name_cstr, payload); - - (*env)->ReleaseStringUTFChars(env, ev_name, ev_name_cstr); -} - -JNIEXPORT void JNICALL Java_org_lttng_ust_LTTngUst_tracepointIntInt(JNIEnv *env, - jobject jobj __attribute__((unused)), - jstring ev_name, - jint payload1, - jint payload2) -{ - jboolean iscopy; - const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, &iscopy); - - tracepoint(lttng_ust_java, int_int_event, ev_name_cstr, payload1, payload2); - - (*env)->ReleaseStringUTFChars(env, ev_name, ev_name_cstr); -} - -JNIEXPORT void JNICALL Java_org_lttng_ust_LTTngUst_tracepointLong(JNIEnv *env, - jobject jobj __attribute__((unused)), - jstring ev_name, - jlong payload) -{ - jboolean iscopy; - const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, &iscopy); - - tracepoint(lttng_ust_java, long_event, ev_name_cstr, payload); - - (*env)->ReleaseStringUTFChars(env, ev_name, ev_name_cstr); -} - -JNIEXPORT void JNICALL Java_org_lttng_ust_LTTngUst_tracepointLongLong(JNIEnv *env, - jobject jobj __attribute__((unused)), - jstring ev_name, - jlong payload1, - jlong payload2) -{ - jboolean iscopy; - const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, &iscopy); - - tracepoint(lttng_ust_java, long_long_event, ev_name_cstr, payload1, payload2); - - (*env)->ReleaseStringUTFChars(env, ev_name, ev_name_cstr); -} - -JNIEXPORT void JNICALL Java_org_lttng_ust_LTTngUst_tracepointString(JNIEnv *env, - jobject jobj __attribute__((unused)), - jstring ev_name, - jstring payload) -{ - jboolean iscopy; - const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, &iscopy); - const char *payload_cstr = (*env)->GetStringUTFChars(env, payload, &iscopy); - - tracepoint(lttng_ust_java, string_event, ev_name_cstr, payload_cstr); - - (*env)->ReleaseStringUTFChars(env, ev_name, ev_name_cstr); - (*env)->ReleaseStringUTFChars(env, payload, payload_cstr); -} - diff --git a/src/liblttng-ust-java/Makefile.am b/src/liblttng-ust-java/Makefile.am deleted file mode 100644 index 55252fbb..00000000 --- a/src/liblttng-ust-java/Makefile.am +++ /dev/null @@ -1,41 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-only - -JAVAROOT = . -jarfile = liblttng-ust-java.jar -jardir = $(datadir)/java -pkgpath = org/lttng/ust - -dist_noinst_JAVA = $(pkgpath)/LTTngUst.java -jar_DATA = $(jarfile) -BUILT_SOURCES = org_lttng_ust_LTTngUst.h - -AM_CPPFLAGS += -I$(builddir) -I$(srcdir) $(JNI_CPPFLAGS) -lib_LTLIBRARIES = liblttng-ust-java.la -liblttng_ust_java_la_SOURCES = LTTngUst.c lttng_ust_java.h -nodist_liblttng_ust_java_la_SOURCES = org_lttng_ust_LTTngUst.h - -liblttng_ust_java_la_LIBADD = -lc \ - $(top_builddir)/src/liblttng-ust/liblttng-ust.la - -$(jarfile): classnoinst.stamp - $(JAR) cf $(JARFLAGS) $@ $(pkgpath)/*.class - -if !HAVE_JAVAH -# If we don't have javah, assume we are running openjdk >= 10 and use javac -# to generate the jni header file. -AM_JAVACFLAGS = -h . - -org_lttng_ust_LTTngUst.h: $(jarfile) -else -org_lttng_ust_LTTngUst.h: jni-header.stamp - -jni-header.stamp: $(dist_noinst_JAVA) - $(JAVAH) -classpath $(srcdir) $(JAVAHFLAGS) org.lttng.ust.LTTngUst && \ - echo "JNI header generated" > jni-header.stamp -endif - -all-local: org_lttng_ust_LTTngUst.h - -EXTRA_DIST = README - -CLEANFILES = $(jarfile) $(pkgpath)/*.class jni-header.stamp org_lttng_ust_LTTngUst.h diff --git a/src/liblttng-ust-java/README b/src/liblttng-ust-java/README deleted file mode 100644 index d2ca4781..00000000 --- a/src/liblttng-ust-java/README +++ /dev/null @@ -1,15 +0,0 @@ -This directory contains a simple API for instrumenting java applications. - -Configuration examples to build this library: - -dependency: openjdk-7-jdk -./configure --enable-jni-interface - -Note that the OpenJDK 7 is used for development and continuous integration thus -we directly support that version for this library. However, it has been tested -with OpenJDK 6 also. Please let us know if other Java version (commercial or -not) work with this library. - -After building, you can use the liblttng-ust-java.jar file in a Java project. -It requires the liblttng-ust-java.so* files (which get installed when doing -`make install') so make sure those are in the linker's library path. diff --git a/src/liblttng-ust-java/lttng_ust_java.h b/src/liblttng-ust-java/lttng_ust_java.h deleted file mode 100644 index ea515a84..00000000 --- a/src/liblttng-ust-java/lttng_ust_java.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2011 Mathieu Desnoyers - */ - -#undef TRACEPOINT_PROVIDER -#define TRACEPOINT_PROVIDER lttng_ust_java - -#if !defined(_TRACEPOINT_LTTNG_UST_JAVA_H) || defined(TRACEPOINT_HEADER_MULTI_READ) -#define _TRACEPOINT_LTTNG_UST_JAVA_H - -#include - -TRACEPOINT_EVENT(lttng_ust_java, int_event, - TP_ARGS(const char *, name, int, payload), - TP_FIELDS( - ctf_string(name, name) - ctf_integer(int, int_payload, payload) - ) -) - -TRACEPOINT_EVENT(lttng_ust_java, int_int_event, - TP_ARGS(const char *, name, int, payload1, int, payload2), - TP_FIELDS( - ctf_string(name, name) - ctf_integer(int, int_payload1, payload1) - ctf_integer(int, int_payload2, payload2) - ) -) - -TRACEPOINT_EVENT(lttng_ust_java, long_event, - TP_ARGS(const char *, name, long, payload), - TP_FIELDS( - ctf_string(name, name) - ctf_integer(long, long_payload, payload) - ) -) - -TRACEPOINT_EVENT(lttng_ust_java, long_long_event, - TP_ARGS(const char *, name, long, payload1, long, payload2), - TP_FIELDS( - ctf_string(name, name) - ctf_integer(long, long_payload1, payload1) - ctf_integer(long, long_payload2, payload2) - ) -) - -TRACEPOINT_EVENT(lttng_ust_java, string_event, - TP_ARGS(const char *, name, const char *, payload), - TP_FIELDS( - ctf_string(name, name) - ctf_string(string_payload, payload) - ) -) - -#endif /* _TRACEPOINT_LTTNG_UST_JAVA_H */ - -#undef TRACEPOINT_INCLUDE -#define TRACEPOINT_INCLUDE "./lttng_ust_java.h" - -/* This part must be outside protection */ -#include diff --git a/src/liblttng-ust-java/org/lttng/ust/LTTngUst.java b/src/liblttng-ust-java/org/lttng/ust/LTTngUst.java deleted file mode 100644 index cc14a729..00000000 --- a/src/liblttng-ust-java/org/lttng/ust/LTTngUst.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2011-2012 Mathieu Desnoyers - * Copyright (C) 2012 Alexandre Montplaisir - */ - -package org.lttng.ust; - -/** - * 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 - * - */ -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-java"); //$NON-NLS-1$ - } - - /** - * Insert a tracepoint with a payload of type Integer. - * - * @param name - * The name assigned to this event. For best performance, this - * should be a statically-defined String, or a literal. - * @param payload - * The int payload - */ - public static native void tracepointInt(String name, int payload); - - /** - * Insert a tracepoint with a payload consisting of two integers. - * - * @param name - * The name assigned to this event. For best performance, this - * should be a statically-defined String, or a literal. - * @param payload1 - * The first int payload - * @param payload2 - * The second int payload - */ - public static native void - tracepointIntInt(String name, int payload1, int payload2); - - /** - * Insert a tracepoint with a payload of type Long - * - * @param name - * The name assigned to this event. For best performance, this - * should be a statically-defined String, or a literal. - * @param payload - * The long payload - */ - public static native void tracepointLong(String name, long payload); - - /** - * Insert a tracepoint with a payload consisting of two longs. - * - * @param name - * The name assigned to this event. For best performance, this - * should be a statically-defined String, or a literal. - * @param payload1 - * The first long payload - * @param payload2 - * The second long payload - */ - public static native void - tracepointLongLong(String name, long payload1, long payload2); - - /** - * Insert a tracepoint with a String payload. - * - * @param name - * The name assigned to this event. For best performance, this - * should be a statically-defined String, or a literal. - * @param payload - * The String payload - */ - public static native void tracepointString(String name, String payload); - -} -