/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/java/lttng-ust-agent-log4j2/classnoinst.stamp
+/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/log4j-jni-header.stamp
+/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/*.jar
+/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/META-INF
/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-agent/jni/log4j/org_lttng_ust_agent_log4j2_LttngLog4j2Api.h
/src/lib/lttng-ust-java/classnoinst.stamp
/src/lib/lttng-ust-java/jni-header.stamp
/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/lttng-ust-agent-log4j2/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-agent/jni/log4j2/Makefile
/src/lib/lttng-ust-java/Makefile
/src/lib/lttng-ust-libc-wrapper/Makefile
/src/lib/lttng-ust-pthread-wrapper/Makefile
JAR library to provide an LTTng-UST logging back-end for Java
applications using Java Util Logging or Log4j. (Configure with
`--enable-java-agent-jul` or `--enable-java-agent-log4j` or
- `--enable-java-agent-all`).
+ `--enable-java-agent-log4j2` or `--enable-java-agent-all`).
- `liblttng-ust-libc-wrapper`: an example library that can be
preloaded to instrument some calls to libc (currently `malloc()` and
`free()`) and to POSIX threads (mutexes currently instrumented) in
AE_FEATURE_DEFAULT_DISABLE
AE_FEATURE([java-agent-jul],[build the LTTng UST Java agent with JUL support])
-# Build the Java Log4j agent
+# Build the Java Log4j 1.x agent
# Disabled by default
AE_FEATURE_DEFAULT_DISABLE
-AE_FEATURE([java-agent-log4j],[build the LTTng UST Java agent with Log4j support])
+AE_FEATURE([java-agent-log4j],[build the LTTng UST Java agent with Log4j 1.x support (deprecated)])
+
+# Build the Java Log4j 2.x agent
+# Disabled by default
+AE_FEATURE_DEFAULT_DISABLE
+AE_FEATURE([java-agent-log4j2],[build the LTTng UST Java agent with Log4j 2.x support])
# Build both Java agents
# Disabled by default
AE_IF_FEATURE_ENABLED([java-agent-all], [
AE_FEATURE_ENABLE([java-agent-jul])
AE_FEATURE_ENABLE([java-agent-log4j])
+ AE_FEATURE_ENABLE([java-agent-log4j2])
])
])
# The JNI interface and Java Agents require a working Java JDK
-AS_IF([AE_IS_FEATURE_ENABLED([jni-interface]) || AE_IS_FEATURE_ENABLED([java-agent-jul]) || AE_IS_FEATURE_ENABLED([java-agent-log4j])], [
+AS_IF([AE_IS_FEATURE_ENABLED([jni-interface]) || AE_IS_FEATURE_ENABLED([java-agent-jul]) || \
+ AE_IS_FEATURE_ENABLED([java-agent-log4j]) || AE_IS_FEATURE_ENABLED([java-agent-log4j2])], [
AX_PROG_JAVAC
AX_PROG_JAVA
AX_PROG_JAR
CPPFLAGS="$saved_CPPFLAGS"
])
-# The log4j agent requires the log4j jar in the classpath
+# The log4j 1.x agent requires the log4j jar in the classpath
AE_IF_FEATURE_ENABLED([java-agent-log4j], [
AX_CHECK_CLASS([org.apache.log4j.Logger])
AS_IF([test "x$ac_cv_class_org_apache_log4j_Logger" = "xno"], [
])
])
+# The log4j 2.x agent requires the log4j core and api jars in the classpath
+AE_IF_FEATURE_ENABLED([java-agent-log4j2], [
+ AX_CHECK_CLASS([org.apache.logging.log4j.Logger])
+ AX_CHECK_CLASS([org.apache.logging.log4j.core.Core])
+ AS_IF([test "x$ac_cv_class_org_apache_logging_log4j_Logger" = "xno" || test "x$ac_cv_class_org_apache_logging_log4j_core_Core" = "xno"], [
+ AC_MSG_ERROR([dnl
+The UST Java agent support for log4j was requested but the Log4j classes were
+not found. Please specify the location of the Log4j API and core 2.x jars via the Java CLASSPATH
+environment variable, e.g. ./configure CLASSPATH="/path/to/log4j-core.jar:/path/to/log4j-api.jar"
+
+Current CLASSPATH: "$CLASSPATH"
+ ])
+ ])
+])
+
# The python agent requires a python interpreter
AE_IF_FEATURE_ENABLED([python-agent], [
AS_IF([test "x$PYTHON" = "x"], [
AM_CONDITIONAL([ENABLE_EXAMPLES], AE_IS_FEATURE_ENABLED([examples]))
AM_CONDITIONAL([ENABLE_GEN_TP_EXAMPLES], [test "x$PYTHON" != "x"])
-AM_CONDITIONAL([ENABLE_JAVA_AGENT], AE_IS_FEATURE_ENABLED([java-agent-jul]) || AE_IS_FEATURE_ENABLED([java-agent-log4j]))
+AM_CONDITIONAL([ENABLE_JAVA_AGENT], AE_IS_FEATURE_ENABLED([java-agent-jul]) || AE_IS_FEATURE_ENABLED([java-agent-log4j]) || AE_IS_FEATURE_ENABLED([java-agent-log4j2]))
AM_CONDITIONAL([ENABLE_JAVA_AGENT_WITH_JUL], AE_IS_FEATURE_ENABLED([java-agent-jul]))
AM_CONDITIONAL([ENABLE_JAVA_AGENT_WITH_LOG4J], AE_IS_FEATURE_ENABLED([java-agent-log4j]))
+AM_CONDITIONAL([ENABLE_JAVA_AGENT_WITH_LOG4J2], AE_IS_FEATURE_ENABLED([java-agent-log4j2]))
+AM_CONDITIONAL([ENABLE_JAVA_AGENT_WITH_LOG4J_COMMON], AE_IS_FEATURE_ENABLED([java-agent-log4j]) || AE_IS_FEATURE_ENABLED([java-agent-log4j2]))
AM_CONDITIONAL([ENABLE_JNI_INTERFACE], AE_IS_FEATURE_ENABLED([jni-interface]))
AM_CONDITIONAL([ENABLE_MAN_PAGES], AE_IS_FEATURE_ENABLED([man-pages]))
AM_CONDITIONAL([ENABLE_NUMA], AE_IS_FEATURE_ENABLED([numa]))
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/lttng-ust-agent-log4j2/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
PPRINT_PROP_BOOL_CUSTOM([Java agent (JUL support)], $value, [use --enable-java-agent-jul])
AE_IS_FEATURE_ENABLED([java-agent-log4j]) && value=1 || value=0
-PPRINT_PROP_BOOL_CUSTOM([Java agent (Log4j support)], $value, [use --enable-java-agent-log4j])
+PPRINT_PROP_BOOL_CUSTOM([Java agent (Log4j 1.x support (deprecated))], $value, [use --enable-java-agent-log4j])
+
+AE_IS_FEATURE_ENABLED([java-agent-log4j2]) && value=1 || value=0
+PPRINT_PROP_BOOL_CUSTOM([Java agent (Log4j 2.x support)], $value, [use --enable-java-agent-log4j2])
AE_IS_FEATURE_ENABLED([jni-interface]) && value=1 || value=0
PPRINT_PROP_BOOL_CUSTOM([JNI interface (JNI)], $value, [use --enable-jni-interface])
if ENABLE_JAVA_AGENT_WITH_LOG4J
doc_examples_java_log4jdir = ${docdir}/examples/java-log4j
dist_doc_examples_java_log4j_DATA = java-log4j/Makefile \
- java-log4j/Hello.java \
- java-log4j/run
+ java-log4j/HelloLog4j.java \
+ java-log4j/run
SUBDIRS_LOG4J = java-log4j
endif
+if ENABLE_JAVA_AGENT_WITH_LOG4J2
+doc_examples_java_log4j2_basicdir = ${docdir}/examples/java-log4j2-basic
+dist_doc_examples_java_log4j2_basic_DATA = \
+ java-log4j2-basic/Makefile \
+ java-log4j2-basic/HelloLog4j2.java \
+ java-log4j2-basic/log4j2.xml \
+ java-log4j2-basic/run
+
+doc_examples_java_log4j2_ctxdir = ${docdir}/examples/java-log4j2-ctx
+dist_doc_examples_java_log4j2_ctx_DATA = \
+ java-log4j2-ctx/Makefile \
+ java-log4j2-ctx/HelloLog4j2Ctx.java \
+ java-log4j2-ctx/log4j2.ctx1.xml \
+ java-log4j2-ctx/log4j2.ctx2.xml \
+ java-log4j2-ctx/run
+
+doc_examples_java_log4j2_progdir = ${docdir}/examples/java-log4j2-prog
+dist_doc_examples_java_log4j2_prog_DATA = \
+ java-log4j2-prog/Makefile \
+ java-log4j2-prog/HelloLog4j2Prog.java \
+ java-log4j2-prog/run
+
+SUBDIRS_LOG4J2 = java-log4j2-basic java-log4j2-prog
+endif
+
if ENABLE_PYTHON_AGENT
doc_examples_pythondir = ${docdir}/examples/python
dist_doc_examples_python_DATA = python/hello.py
all-local:
$(AM_V_at)if [ x"$(srcdir)" != x"$(builddir)" ]; then \
- for subdir in $(SUBDIRS_PROXY) $(SUBDIRS_JUL) $(SUBDIRS_LOG4J) $(SUBDIRS_CMAKE); do \
+ for subdir in $(SUBDIRS_PROXY) $(SUBDIRS_JUL) $(SUBDIRS_LOG4J) $(SUBDIRS_LOG4J2) $(SUBDIRS_CMAKE); do \
cp -pfR $(srcdir)/$$subdir $(builddir); \
chmod -R u+w $(builddir)/$$subdir; \
done; \
) || exit 1; \
done; \
fi; \
+ if [ x"$(SUBDIRS_LOG4J2)" != x"" ]; then \
+ for subdir in $(SUBDIRS_LOG4J2); do \
+ ( \
+ cd $$subdir && \
+ $(MAKE) all \
+ CLASSPATH="$(CLASSPATH)" \
+ JAVA_CLASSPATH_OVERRIDE_LOG4J2="../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2" \
+ JAVA_CLASSPATH_OVERRIDE_COMMON="../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common" \
+ $(AM_MAKEFLAGS) \
+ ) || exit 1; \
+ done; \
+ fi; \
if [ x"$(SUBDIRS_CMAKE)" != x"" ]; then \
for subdir in $(SUBDIRS_CMAKE); do \
( \
fi; \
done; \
fi; \
+ if [ x"$(SUBDIRS_LOG4J2)" != x"" ]; then \
+ for subdir in $(SUBDIRS_LOG4J2); do \
+ if [ -d $$subdir ]; then \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) clean && cd ..) || exit 1; \
+ fi; \
+ done; \
+ fi; \
if [ x"$(SUBDIRS_CMAKE)" != x"" ]; then \
for subdir in $(SUBDIRS_CMAKE); do \
if [ -d $$subdir ]; then \
done; \
fi; \
if [ x"$(srcdir)" != x"$(builddir)" ]; then \
- for subdir in $(SUBDIRS_PROXY) $(SUBDIRS_JUL) $(SUBDIRS_LOG4J) $(SUBDIRS_CMAKE); do \
+ for subdir in $(SUBDIRS_PROXY) $(SUBDIRS_JUL) $(SUBDIRS_LOG4J) $(SUBDIRS_LOG4J2) $(SUBDIRS_CMAKE); do \
rm -rf $(builddir)/$$subdir; \
done; \
fi;
.PHONY: clean
clean:
- $(RM) *.class
+ $(RM) $(CLASSES:.java=.class)
+++ /dev/null
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright (C) 2015 EfficiOS Inc.
- * Copyright (C) 2015 Alexandre Montplaisir <alexmonthy@efficios.com>
- * Copyright (C) 2014 Christian Babeux <christian.babeux@efficios.com>
- */
-
-import java.io.IOException;
-
-import org.apache.log4j.Appender;
-import org.apache.log4j.BasicConfigurator;
-import org.apache.log4j.Logger;
-import org.apache.log4j.Level;
-import org.lttng.ust.agent.log4j.LttngLogAppender;
-
-/**
- * Example application using the LTTng-UST Java log4j agent.
- *
- * <p>
- * To obtain LTTng trace events, you should run the following sequence of
- * commands:
- * </p>
- *
- * <ul>
- * <li>$ lttng create</li>
- * <li>$ lttng enable-event -l -a</li>
- * <li>$ lttng start</li>
- * <li>(run this program)</li>
- * <li>$ lttng stop</li>
- * <li>$ lttng view</li>
- * <li>$ lttng destroy</li>
- * </ul>
- *
- * @author Alexandre Montplaisir
- * @author Christian Babeux
- */
-public class Hello {
-
- private static final Logger HELLO_LOG = Logger.getLogger(Hello.class);
-
- /**
- * Application start
- *
- * @param args
- * Command-line arguments
- * @throws IOException
- * If the required native libraries cannot be found. You may
- * have to specify "-Djava.library.path=..." on the "java"
- * command line.
- */
- public static void main(String args[]) throws IOException {
-
- /*
- * Set lowest level to make sure all event levels are logged.
- * Any jar can override the default log4j rootLogger level
- * and a logger with no explicit level defaults to the non-null
- * parent level. Events could be ignored if the inherited value
- * is to low.
- * e.g BSF -> https://issues.apache.org/jira/browse/BSF-24
- */
- HELLO_LOG.setLevel(Level.ALL);
-
- /* Start with the default Log4j configuration, which logs to console */
- BasicConfigurator.configure();
-
- /*
- * Instantiate a LTTng log appender and attach it to the logger, which
- * will now send the logged events to UST.
- */
- Appender lttngAppender = new LttngLogAppender();
- HELLO_LOG.addAppender(lttngAppender);
-
- /*
- * Here we've set up the appender programmatically, but it could also be
- * defined at runtime, by reading a configuration file for example:
- */
- // PropertyConfigurator.configure(fileName);
-
- /* Trigger some tracing events using the Log4j Logger created before. */
- HELLO_LOG.info("Hello World, the answer is " + 42);
- HELLO_LOG.info("Another info event");
- HELLO_LOG.error("An error event");
-
- /* Cleanup */
- HELLO_LOG.removeAppender(lttngAppender);
- lttngAppender.close();
- }
-}
--- /dev/null
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2015 EfficiOS Inc.
+ * Copyright (C) 2015 Alexandre Montplaisir <alexmonthy@efficios.com>
+ * Copyright (C) 2014 Christian Babeux <christian.babeux@efficios.com>
+ */
+
+import java.io.IOException;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.BasicConfigurator;
+import org.apache.log4j.Logger;
+import org.apache.log4j.Level;
+import org.lttng.ust.agent.log4j.LttngLogAppender;
+
+/**
+ * Example application using the LTTng-UST Java log4j agent.
+ *
+ * <p>
+ * To obtain LTTng trace events, you should run the following sequence of
+ * commands:
+ * </p>
+ *
+ * <ul>
+ * <li>$ lttng create</li>
+ * <li>$ lttng enable-event -l -a</li>
+ * <li>$ lttng start</li>
+ * <li>(run this program)</li>
+ * <li>$ lttng stop</li>
+ * <li>$ lttng view</li>
+ * <li>$ lttng destroy</li>
+ * </ul>
+ *
+ * @author Alexandre Montplaisir
+ * @author Christian Babeux
+ */
+public class HelloLog4j {
+
+ private static final Logger HELLO_LOG = Logger.getLogger(HelloLog4j.class);
+
+ /**
+ * Application start
+ *
+ * @param args
+ * Command-line arguments
+ * @throws IOException
+ * If the required native libraries cannot be found. You may
+ * have to specify "-Djava.library.path=..." on the "java"
+ * command line.
+ */
+ public static void main(String args[]) throws IOException {
+
+ /*
+ * Set lowest level to make sure all event levels are logged.
+ * Any jar can override the default log4j rootLogger level
+ * and a logger with no explicit level defaults to the non-null
+ * parent level. Events could be ignored if the inherited value
+ * is to low.
+ * e.g BSF -> https://issues.apache.org/jira/browse/BSF-24
+ */
+ HELLO_LOG.setLevel(Level.ALL);
+
+ /* Start with the default Log4j configuration, which logs to console */
+ BasicConfigurator.configure();
+
+ /*
+ * Instantiate a LTTng log appender and attach it to the logger, which
+ * will now send the logged events to UST.
+ */
+ Appender lttngAppender = new LttngLogAppender();
+ HELLO_LOG.addAppender(lttngAppender);
+
+ /*
+ * Here we've set up the appender programmatically, but it could also be
+ * defined at runtime, by reading a configuration file for example:
+ */
+ // PropertyConfigurator.configure(fileName);
+
+ /* Trigger some tracing events using the Log4j Logger created before. */
+ HELLO_LOG.info("Hello World, the answer is " + 42);
+ HELLO_LOG.info("Another info event");
+ HELLO_LOG.error("An error event");
+
+ /* Cleanup */
+ HELLO_LOG.removeAppender(lttngAppender);
+ lttngAppender.close();
+ }
+}
.java.class:
$(JC) $(JFLAGS) $*.java
-CLASSES = Hello.java
+CLASSES = HelloLog4j.java
all: classes
.PHONY: clean
clean:
- $(RM) *.class
+ $(RM) $(CLASSES:.java=.class)
# find the JNI Log4j library.
#
-DIR=`dirname $0`
+DIR=$(dirname "$0")
JARFILE_COMMON="lttng-ust-agent-common.jar"
JARFILE_LOG4J="lttng-ust-agent-log4j.jar"
JAVA_OPTIONS=""
CLASSPATH="/usr/local/share/java/log4j.jar:/usr/share/java/log4j.jar"
fi
-cd $DIR
+cd "$DIR" || exit 1
if [ -f "$DIR/.intree" ]; then
CLASSPATH="$CLASSPATH:../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON"
JAVA_OPTIONS="$JAVA_OPTIONS -Djava.library.path=$LIBPATH"
fi
-java -classpath "$CLASSPATH:." $JAVA_OPTIONS Hello
-
-cd -
+java -classpath "$CLASSPATH:." $JAVA_OPTIONS HelloLog4j
--- /dev/null
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2022 EfficiOS Inc.
+ */
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * Example application using the LTTng-UST Java log4j agent.
+ *
+ * <p>
+ * To obtain LTTng trace events, you should run the following sequence of
+ * commands:
+ * </p>
+ *
+ * <ul>
+ * <li>$ lttng create</li>
+ * <li>$ lttng enable-event -l -a</li>
+ * <li>$ lttng start</li>
+ * <li>(run this program)</li>
+ * <li>$ lttng stop</li>
+ * <li>$ lttng view</li>
+ * <li>$ lttng destroy</li>
+ * </ul>
+ *
+ */
+public class HelloLog4j2 {
+
+ private static final Logger logger = LogManager.getLogger(HelloLog4j2.class);
+
+ /**
+ * Application start
+ *
+ * @param args Command-line arguments
+ */
+ public static void main(String args[]) {
+
+ /* Trigger some tracing events using the Log4j Logger created before. */
+ logger.info("Basic config: Hello World, the answer is " + 42);
+ logger.info("Basic config: Another info event");
+ logger.error("Basic config: An error event");
+ }
+}
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# Copyright (C) 2014 Christian Babeux <christian.babeux@efficios.com>
+#
+# This Makefile is not using automake so that users may see how to build a
+# program with tracepoint provider probes as stand-alone shared objects.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+#
+
+# Required JAR files for Log4j 2.x
+JARFILE_LOG4J2=lttng-ust-agent-log4j2.jar
+JARFILE_COMMON=lttng-ust-agent-common.jar
+
+# If system classpath is empty, try to guess log4j location
+ifeq "$(CLASSPATH)" ""
+ CLASSPATH=/usr/local/share/java/log4j.jar:/usr/share/java/log4j.jar
+endif
+
+# Check if the top level makefile overrides the Log4j Jar file's path.
+ifeq "$(JAVA_CLASSPATH_OVERRIDE_LOG4J2)" ""
+ LOG4J2_CP = /usr/local/share/java/$(JARFILE_LOG4J2):/usr/share/java/$(JARFILE_LOG4J2)
+else
+ LOG4J2_CP = $(JAVA_CLASSPATH_OVERRIDE_LOG4J2)/$(JARFILE_LOG4J2)
+endif
+
+# Check if the top level makefile overrides the Common Jar file's path.
+ifeq "$(JAVA_CLASSPATH_OVERRIDE_COMMON)" ""
+ COMMON_CP = /usr/local/share/java/$(JARFILE_COMMON):/usr/share/java/$(JARFILE_COMMON)
+else
+ COMMON_CP = $(JAVA_CLASSPATH_OVERRIDE_COMMON)/$(JARFILE_COMMON)
+endif
+
+JFLAGS = -g
+JC = javac -classpath "$(CLASSPATH):$(LOG4J2_CP):$(COMMON_CP):."
+.SUFFIXES: .java .class
+.java.class:
+ $(JC) $(JFLAGS) $*.java
+
+CLASSES = HelloLog4j2.java
+
+all: classes
+
+classes: $(CLASSES:.java=.class)
+
+.PHONY: clean
+clean:
+ $(RM) $(CLASSES:.java=.class)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="WARN">
+ <Appenders>
+ <Console name="Console" target="SYSTEM_OUT">
+ <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
+ </Console>
+ <Lttng name="Lttng">
+ </Lttng>
+ </Appenders>
+ <Loggers>
+ <Root level="debug">
+ <AppenderRef ref="Console"/>
+ <AppenderRef ref="Lttng"/>
+ </Root>
+ </Loggers>
+</Configuration>
--- /dev/null
+#!/bin/bash
+#
+# SPDX-License-Identifier: MIT
+
+#
+# The -cp path should be changed to the lttng ust agent jar file on your system
+# or locally to the project. Same goes for the Java library path in order to
+# find the JNI Log4j library.
+#
+
+DIR=$(dirname "$0")
+JARFILE_COMMON="lttng-ust-agent-common.jar"
+JARFILE_LOG4J2="lttng-ust-agent-log4j2.jar"
+JAVA_OPTIONS=""
+
+# If system classpath is empty, try to guess log4j location
+if [ "x$CLASSPATH" = "x" ]; then
+ CLASSPATH="/usr/local/share/java/log4j-core.jar:/usr/share/java/log4j-core.jar:/usr/local/share/java/log4j-api.jar:/usr/share/java/log4j-api.jar"
+fi
+
+cd "$DIR" || exit 1
+
+if [ -f "$DIR/.intree" ]; then
+ CLASSPATH="$CLASSPATH:../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON"
+ CLASSPATH="$CLASSPATH:../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/$JARFILE_LOG4J2"
+ LIBPATH="../../../src/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_LOG4J2:/usr/share/java/$JARFILE_LOG4J2"
+ # Use system defined java.library.path
+ #LIBPATH="/usr/local/lib:/usr/lib"
+fi
+
+if [ "x$LIBPATH" != "x" ]; then
+ JAVA_OPTIONS="$JAVA_OPTIONS -Djava.library.path=$LIBPATH"
+fi
+
+java -classpath "$CLASSPATH:." $JAVA_OPTIONS HelloLog4j2
--- /dev/null
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2022 EfficiOS Inc.
+ */
+
+import java.net.URI;
+import java.util.ArrayList;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+
+/**
+ * Example application using the LTTng-UST Java log4j agent.
+ *
+ * <p>
+ * To obtain LTTng trace events, you should run the following sequence of
+ * commands:
+ * </p>
+ *
+ * <ul>
+ * <li>$ lttng create</li>
+ * <li>$ lttng enable-event -l -a</li>
+ * <li>$ lttng start</li>
+ * <li>(run this program)</li>
+ * <li>$ lttng stop</li>
+ * <li>$ lttng view</li>
+ * <li>$ lttng destroy</li>
+ * </ul>
+ *
+ */
+public class HelloLog4j2Ctx {
+
+ /**
+ * Application start
+ *
+ * @param args Command-line arguments
+ */
+ public static void main(String args[]) {
+
+ URI configFileUri1 = URI.create("./log4j2.ctx1.xml");
+ URI configFileUri2 = URI.create("./log4j2.ctx2.xml");
+
+ LoggerContext loggerContext1 = (LoggerContext) LogManager.getContext(ClassLoader.getSystemClassLoader(), false,
+ configFileUri1);
+ LoggerContext loggerContext2 = (LoggerContext) LogManager.getContext(ClassLoader.getSystemClassLoader(), false,
+ configFileUri2);
+
+ /* Loggers in different contexts with the same name. */
+ Logger logger1ctx1 = loggerContext1.getLogger(HelloLog4j2Ctx.class);
+ Logger logger1ctx2 = loggerContext2.getLogger(HelloLog4j2Ctx.class);
+
+ Logger logger2ctx1 = loggerContext1.getLogger("Logger2");
+ Logger logger3ctx2 = loggerContext2.getLogger("Logger3");
+
+ ArrayList<Logger> loggers = new ArrayList<Logger>();
+
+ loggers.add(logger1ctx1);
+ loggers.add(logger1ctx2);
+ loggers.add(logger2ctx1);
+ loggers.add(logger3ctx2);
+
+ for (Logger logger : loggers) {
+ /* Trigger some tracing events using the Log4j Logger created before. */
+ logger.info("Context config: Hello World, the answer is " + 42);
+ logger.info("Context config: Another info event");
+ logger.error("Context config: An error event");
+ }
+ }
+}
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# Copyright (C) 2014 Christian Babeux <christian.babeux@efficios.com>
+#
+# This Makefile is not using automake so that users may see how to build a
+# program with tracepoint provider probes as stand-alone shared objects.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+#
+
+# Required JAR files for Log4j 2.x
+JARFILE_LOG4J2=lttng-ust-agent-log4j2.jar
+JARFILE_COMMON=lttng-ust-agent-common.jar
+
+# If system classpath is empty, try to guess log4j location
+ifeq "$(CLASSPATH)" ""
+ CLASSPATH=/usr/local/share/java/log4j.jar:/usr/share/java/log4j.jar
+endif
+
+# Check if the top level makefile overrides the Log4j Jar file's path.
+ifeq "$(JAVA_CLASSPATH_OVERRIDE_LOG4J2)" ""
+ LOG4J2_CP = /usr/local/share/java/$(JARFILE_LOG4J2):/usr/share/java/$(JARFILE_LOG4J2)
+else
+ LOG4J2_CP = $(JAVA_CLASSPATH_OVERRIDE_LOG4J2)/$(JARFILE_LOG4J2)
+endif
+
+# Check if the top level makefile overrides the Common Jar file's path.
+ifeq "$(JAVA_CLASSPATH_OVERRIDE_COMMON)" ""
+ COMMON_CP = /usr/local/share/java/$(JARFILE_COMMON):/usr/share/java/$(JARFILE_COMMON)
+else
+ COMMON_CP = $(JAVA_CLASSPATH_OVERRIDE_COMMON)/$(JARFILE_COMMON)
+endif
+
+JFLAGS = -g
+JC = javac -classpath "$(CLASSPATH):$(LOG4J2_CP):$(COMMON_CP):."
+.SUFFIXES: .java .class
+.java.class:
+ $(JC) $(JFLAGS) $*.java
+
+CLASSES = HelloLog4j2Ctx.java
+
+all: classes
+
+classes: $(CLASSES:.java=.class)
+
+.PHONY: clean
+clean:
+ $(RM) $(CLASSES:.java=.class)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration name="Context1" status="WARN">
+ <Appenders>
+ <Console name="Console" target="SYSTEM_OUT">
+ <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
+ </Console>
+ <Lttng name="Lttng">
+ </Lttng>
+ </Appenders>
+ <Loggers>
+ <Root level="debug">
+ <AppenderRef ref="Console"/>
+ <AppenderRef ref="Lttng"/>
+ </Root>
+ </Loggers>
+</Configuration>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration name="Context2" status="WARN">
+ <Appenders>
+ <Console name="Console" target="SYSTEM_OUT">
+ <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
+ </Console>
+ <Lttng name="Lttng">
+ </Lttng>
+ </Appenders>
+ <Loggers>
+ <Root level="debug">
+ <AppenderRef ref="Console"/>
+ <AppenderRef ref="Lttng"/>
+ </Root>
+ </Loggers>
+</Configuration>
--- /dev/null
+#!/bin/bash
+#
+# SPDX-License-Identifier: MIT
+
+#
+# The -cp path should be changed to the lttng ust agent jar file on your system
+# or locally to the project. Same goes for the Java library path in order to
+# find the JNI Log4j library.
+#
+
+DIR=$(dirname "$0")
+JARFILE_COMMON="lttng-ust-agent-common.jar"
+JARFILE_LOG4J2="lttng-ust-agent-log4j2.jar"
+JAVA_OPTIONS=""
+
+# If system classpath is empty, try to guess log4j location
+if [ "x$CLASSPATH" = "x" ]; then
+ CLASSPATH="/usr/local/share/java/log4j.jar:/usr/share/java/log4j.jar"
+fi
+
+cd "$DIR" || exit 1
+
+if [ -f "$DIR/.intree" ]; then
+ CLASSPATH="$CLASSPATH:../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON"
+ CLASSPATH="$CLASSPATH:../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/$JARFILE_LOG4J2"
+ LIBPATH="../../../src/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_LOG4J2:/usr/share/java/$JARFILE_LOG4J2"
+ # Use system defined java.library.path
+ #LIBPATH="/usr/local/lib:/usr/lib"
+fi
+
+if [ "x$LIBPATH" != "x" ]; then
+ JAVA_OPTIONS="$JAVA_OPTIONS -Djava.library.path=$LIBPATH"
+fi
+
+java -classpath "$CLASSPATH:." $JAVA_OPTIONS HelloLog4j2Ctx
--- /dev/null
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2022 EfficiOS Inc.
+ */
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
+import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
+
+/**
+ * Example application using the LTTng-UST Java log4j agent.
+ *
+ * <p>
+ * To obtain LTTng trace events, you should run the following sequence of
+ * commands:
+ * </p>
+ *
+ * <ul>
+ * <li>$ lttng create</li>
+ * <li>$ lttng enable-event -l -a</li>
+ * <li>$ lttng start</li>
+ * <li>(run this program)</li>
+ * <li>$ lttng stop</li>
+ * <li>$ lttng view</li>
+ * <li>$ lttng destroy</li>
+ * </ul>
+ *
+ */
+public class HelloLog4j2Prog {
+
+ /**
+ * Application start
+ *
+ * @param args Command-line arguments
+ */
+ public static void main(String args[]) {
+
+ ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
+
+ /* Layout */
+ LayoutComponentBuilder standardLayout = builder.newLayout("PatternLayout");
+ standardLayout.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable");
+
+ /* Create a console appender */
+ AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE");
+ appenderBuilder.add(standardLayout);
+ builder.add(appenderBuilder);
+
+ /* Create an Lttng appender */
+ appenderBuilder = builder.newAppender("Lttng", "LTTNG");
+ builder.add(appenderBuilder);
+
+ /* Create a root logger with both appenders attached */
+ RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.DEBUG);
+ rootLogger.add(builder.newAppenderRef("Stdout"));
+ rootLogger.add(builder.newAppenderRef("Lttng"));
+ builder.add(rootLogger);
+
+ Configurator.initialize(builder.build());
+
+ Logger logger = LogManager.getLogger(HelloLog4j2Prog.class);
+
+ /* Trigger some tracing events using the Log4j Logger created before. */
+ logger.info("Prog config: Hello World, the answer is " + 42);
+ logger.info("Prog config: Another info event");
+ logger.error("Prog config: An error event");
+ }
+}
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# Copyright (C) 2014 Christian Babeux <christian.babeux@efficios.com>
+#
+# This Makefile is not using automake so that users may see how to build a
+# program with tracepoint provider probes as stand-alone shared objects.
+#
+# This makefile is purposefully kept simple to support GNU and BSD make.
+#
+
+# Required JAR files for Log4j 2.x
+JARFILE_LOG4J2=lttng-ust-agent-log4j2.jar
+JARFILE_COMMON=lttng-ust-agent-common.jar
+
+# If system classpath is empty, try to guess log4j location
+ifeq "$(CLASSPATH)" ""
+ CLASSPATH=/usr/local/share/java/log4j.jar:/usr/share/java/log4j.jar
+endif
+
+# Check if the top level makefile overrides the Log4j Jar file's path.
+ifeq "$(JAVA_CLASSPATH_OVERRIDE_LOG4J2)" ""
+ LOG4J2_CP = /usr/local/share/java/$(JARFILE_LOG4J2):/usr/share/java/$(JARFILE_LOG4J2)
+else
+ LOG4J2_CP = $(JAVA_CLASSPATH_OVERRIDE_LOG4J2)/$(JARFILE_LOG4J2)
+endif
+
+# Check if the top level makefile overrides the Common Jar file's path.
+ifeq "$(JAVA_CLASSPATH_OVERRIDE_COMMON)" ""
+ COMMON_CP = /usr/local/share/java/$(JARFILE_COMMON):/usr/share/java/$(JARFILE_COMMON)
+else
+ COMMON_CP = $(JAVA_CLASSPATH_OVERRIDE_COMMON)/$(JARFILE_COMMON)
+endif
+
+JFLAGS = -g
+JC = javac -classpath "$(CLASSPATH):$(LOG4J2_CP):$(COMMON_CP):."
+.SUFFIXES: .java .class
+.java.class:
+ $(JC) $(JFLAGS) $*.java
+
+CLASSES = HelloLog4j2Prog.java
+
+all: classes
+
+classes: $(CLASSES:.java=.class)
+
+.PHONY: clean
+clean:
+ $(RM) $(CLASSES:.java=.class)
--- /dev/null
+#!/bin/bash
+#
+# SPDX-License-Identifier: MIT
+
+#
+# The -cp path should be changed to the lttng ust agent jar file on your system
+# or locally to the project. Same goes for the Java library path in order to
+# find the JNI Log4j library.
+#
+
+DIR=$(dirname "$0")
+JARFILE_COMMON="lttng-ust-agent-common.jar"
+JARFILE_LOG4J2="lttng-ust-agent-log4j2.jar"
+JAVA_OPTIONS=""
+
+# If system classpath is empty, try to guess log4j location
+if [ "x$CLASSPATH" = "x" ]; then
+ CLASSPATH="/usr/local/share/java/log4j.jar:/usr/share/java/log4j.jar"
+fi
+
+cd "$DIR" || exit 1
+
+if [ -f "$DIR/.intree" ]; then
+ CLASSPATH="$CLASSPATH:../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON"
+ CLASSPATH="$CLASSPATH:../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/$JARFILE_LOG4J2"
+ LIBPATH="../../../src/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_LOG4J2:/usr/share/java/$JARFILE_LOG4J2"
+ # Use system defined java.library.path
+ #LIBPATH="/usr/local/lib:/usr/lib"
+fi
+
+if [ "x$LIBPATH" != "x" ]; then
+ JAVA_OPTIONS="$JAVA_OPTIONS -Djava.library.path=$LIBPATH"
+fi
+
+java -classpath "$CLASSPATH:." $JAVA_OPTIONS HelloLog4j2Prog
$ ./configure --enable-java-agent-jul
-2) Java agent with Log4j support:
+2) Java agent with Log4j 1.x support (deprecated):
$ export CLASSPATH=$CLASSPATH:/path/to/log4j.jar
$ ./configure --enable-java-agent-log4j
-3) Java agent with JUL + Log4j support
+3) Java agent with Log4j 2.x support:
-$ export CLASSPATH=$CLASSPATH:/path/to/log4j.jar
+$ export CLASSPATH=$CLASSPATH:/path/to/log4j-core.jar:/path/to/log4j-api.jar
+$ ./configure --enable-java-agent-log4j2
+
+4) Java agent with JUL + Log4j 1.x + Log4j 2.x support
+
+$ export CLASSPATH=$CLASSPATH:/path/to/log4j.jar:/path/to/log4j-core.jar:/path/to/log4j-api.jar
$ ./configure --enable-java-agent-all
To build the agent with log4j support, make sure that the log4j jar
binaries to use in order to build the Java agent.
Enabling the JUL support will build a "lttng-ust-agent-jul.jar" file. Enabling
-the log4j support will build a "lttng-ust-agent-log4j.jar". Both of these jars
+the log4j 1.x support will build a "lttng-ust-agent-log4j.jar" and enabling
+log4j 2.x support will build a "lttng-ust-agent-log4j2.jar". All of these jars
depend on a third "lttng-ust-agent-common.jar", which will always be built.
All these archives will be installed in the arch-agnostic "$prefix/share/java"
path, e.g: "/usr/share/java". You need to make sure the .jar for the logging
-API you want to use (either lttng-ust-agent-jul.jar or -log4j.jar) is on your
+API you want to use (either "lttng-ust-agent-jul.jar",
+"lttng-ust-agent-log4j.jar" or "lttng-ust-agent-log4j2.jar") is on your
application's classpath.
-Both logging libraries also require an architecture-specific shared object
-(e.g: "liblttng-ust-jul-jni.so"), which is installed by the build system when
-doing "make install". Make sure that your Java application can find this shared
-object, by using the "java.library.path" property if necessary.
+The logging libraries require an architecture-specific shared object,
+"liblttng-ust-jul-jni.so" for JUL and "liblttng-ust-jul-log4j.so" for both
+Log4j 1.x and 2.x, which are installed by the build system when doing "make
+install". Make sure that your Java application can find this shared object, by
+using the "java.library.path" property if necessary.
In order to use UST tracing in your Java application, you simply need to
instantiate a LttngLogHandler or a LttngLogAppender (for JUL or Log4j,
respectively), then attach it to a JUL or Log4j Logger class.
-Refer to the code examples in examples/java-jul/ and examples/java-log4j/.
+Refer to the code examples in "examples/java-jul/", "examples/java-log4j/" and
+"examples/java-log4j2-*/".
LTTng session daemon agents will be initialized as needed. If no session daemon
is available, the execution will continue and the agents will retry connecting
if ENABLE_JAVA_AGENT_WITH_LOG4J
SUBDIRS += lttng-ust-agent-log4j
endif
+
+if ENABLE_JAVA_AGENT_WITH_LOG4J2
+SUBDIRS += lttng-ust-agent-log4j2
+endif
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
+Class-Path: lttng-ust-agent-common.jar lttng-ust-agent-jul.jar lttng-ust-agent-log4j.jar lttng-ust-agent-log4j2.jar
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-only
+
+JAVAROOT = .
+
+# Add the UST agent common jar to the classpath
+AM_JAVACFLAGS = -classpath $(CLASSPATH):$(builddir)/../lttng-ust-agent-common/lttng-ust-agent-common.jar
+
+# Process the log4j2 annotations of our custom appender
+AM_JAVACFLAGS += -processor org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor
+
+pkgpath = org/lttng/ust/agent/log4j2
+
+jarfile_version = 1.0.0
+jarfile_manifest = $(srcdir)/Manifest.txt
+jarfile_symlink = lttng-ust-agent-log4j2.jar
+jarfile = lttng-ust-agent-log4j2-$(jarfile_version).jar
+
+jardir = $(datadir)/java
+
+log4jjniout = ../../jni/log4j
+
+dist_noinst_JAVA = \
+ $(pkgpath)/LttngLog4j2Agent.java \
+ $(pkgpath)/LttngLog4j2Api.java \
+ $(pkgpath)/LttngLogAppender.java
+
+dist_noinst_DATA = $(jarfile_manifest)
+
+jar_DATA = $(jarfile)
+
+classes = $(pkgpath)/*.class
+
+$(jarfile): classnoinst.stamp
+ $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) META-INF $(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.log4j2.LttngLog4j2Api && \
+ echo "Log4j JNI header generated" > log4j-jni-header.stamp
+
+all-local: log4j-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)
+
+clean-local:
+ rm -rf META-INF
+
+CLEANFILES = *.jar \
+ $(classes) \
+ log4j-jni-header.stamp \
+ $(log4jjniout)/org_lttng_ust_agent_log4j2_LttngLog4j2Api.h
--- /dev/null
+Name: org/lttng/ust/agent/log4j2/
+Specification-Title: LTTng UST Java Agent Log4J 2.x Integration
+Specification-Version: 1.0.0
+Specification-Vendor: LTTng Project
+Implementation-Title: org.lttng.ust.agent.log4j2
+Implementation-Version: 1.0.0
+Implementation-Vendor: LTTng Project
+Class-Path: lttng-ust-agent-common.jar
--- /dev/null
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2015-2022 EfficiOS Inc.
+ * Copyright (C) 2015 Alexandre Montplaisir <alexmonthy@efficios.com>
+ */
+
+package org.lttng.ust.agent.log4j2;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.impl.Log4jContextFactory;
+import org.apache.logging.log4j.core.selector.ContextSelector;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.lttng.ust.agent.AbstractLttngAgent;
+
+/**
+ * Agent implementation for Log4j 2.x.
+ */
+class LttngLog4j2Agent extends AbstractLttngAgent<LttngLogAppender> {
+
+ private static LttngLog4j2Agent instance = null;
+
+ private LttngLog4j2Agent() {
+ super(Domain.LOG4J);
+ }
+
+ public static synchronized LttngLog4j2Agent getInstance() {
+ if (instance == null) {
+ instance = new LttngLog4j2Agent();
+ }
+ return instance;
+ }
+
+ @Override
+ public Collection<String> listAvailableEvents() {
+ Set<String> eventNames = new TreeSet<>();
+
+ LoggerContextFactory contextFactory = LogManager.getFactory();
+ if (!(contextFactory instanceof Log4jContextFactory)) {
+ /* Using a custom ContextFactory is not supported. */
+ StatusLogger.getLogger().error("Can't list events with custom ContextFactory");
+ return eventNames;
+ }
+
+ ContextSelector selector = ((Log4jContextFactory) contextFactory).getSelector();
+
+ for (LoggerContext logContext : selector.getLoggerContexts()) {
+ Collection<? extends Logger> loggers = logContext.getLoggers();
+ for (Logger logger : loggers) {
+ /*
+ * Check if that logger has at least one LTTng log4j appender attached.
+ */
+ if (hasLttngAppenderAttached(logger)) {
+ eventNames.add(logger.getName());
+ }
+ }
+ }
+ return eventNames;
+ }
+
+ /*
+ * Check if a logger has an LttngLogAppender attached.
+ *
+ * @param logger the Logger to check, null returns false
+ * @return true if the logger or its parent has at least one LttngLogAppender attached
+ */
+ private static boolean hasLttngAppenderAttached(Logger logger) {
+
+ if (logger == null) {
+ return false;
+ }
+
+ /*
+ * Check all the appenders associated with the logger and return true if one of
+ * them is an LttngLogAppender.
+ */
+ Map<String, Appender> appenders = logger.getAppenders();
+ for (Map.Entry<String, Appender> appender : appenders.entrySet()) {
+ if (appender.getValue() 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.
+ *
+ * Despite the doc, getParent can return null based on the implementation as of
+ * log4j 2.17.1.
+ *
+ * The getParent function is there as a backward compat for 1.x. It is not clear
+ * in which context it should be used. The cost of doing the lookup is minimal
+ * and mimics what was done for the 1.x agent.
+ */
+ return hasLttngAppenderAttached(logger.getParent());
+
+ }
+}
--- /dev/null
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2016 EfficiOS Inc.
+ * Copyright (C) 2016 Alexandre Montplaisir <alexmonthy@efficios.com>
+ */
+
+package org.lttng.ust.agent.log4j2;
+
+/**
+ * Virtual class containing the Java side of the LTTng-log4j JNI API methods.
+ */
+final class LttngLog4j2Api {
+
+ private LttngLog4j2Api() {
+ }
+
+ static native void tracepointWithContext(String message, String loggerName, String className, String methodName,
+ String fileName, int lineNumber, long timeStamp, int logLevel, String threadName, byte[] contextEntries,
+ byte[] contextStrings);
+}
--- /dev/null
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2015-2022 EfficiOS Inc.
+ * Copyright (C) 2015 Alexandre Montplaisir <alexmonthy@efficios.com>
+ * Copyright (C) 2014 Christian Babeux <christian.babeux@efficios.com>
+ */
+
+package org.lttng.ust.agent.log4j2;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.lttng.ust.agent.ILttngHandler;
+import org.lttng.ust.agent.context.ContextInfoSerializer;
+
+/**
+ * LTTng-UST Log4j 2.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.
+ *
+ */
+@Plugin(name = LttngLogAppender.PLUGIN_NAME, category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = false)
+public final class LttngLogAppender extends AbstractAppender implements ILttngHandler {
+
+ /**
+ * The name of the appender in the configuration.
+ */
+ public static final String PLUGIN_NAME = "Lttng";
+
+ private static final String SHARED_OBJECT_NAME = "lttng-ust-log4j-jni";
+
+ /**
+ * Number of events logged (really sent through JNI) by this handler
+ */
+ private final AtomicLong eventCount = new AtomicLong(0);
+
+ private final LttngLog4j2Agent agent;
+
+ /**
+ * Constructor
+ *
+ * @param name The name of the Appender.
+ * @param filter The Filter or null.
+ * @param ignoreExceptions If {@code "true"} (default) exceptions encountered
+ * when appending events are logged; otherwise they are
+ * propagated to the caller.
+ *
+ * @throws IOException This handler requires the lttng-ust-log4j-jni.so
+ * native library, through which it will send the
+ * trace events. This exception is thrown if this
+ * library cannot be found.
+ * @throws SecurityException We will forward any SecurityExcepion that may be
+ * thrown when trying to load the JNI library.
+ */
+ protected LttngLogAppender(String name, Filter filter, boolean ignoreExceptions)
+ throws IOException, SecurityException {
+
+ super(name, filter, null, ignoreExceptions, Property.EMPTY_ARRAY);
+
+ /* 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 = LttngLog4j2Agent.getInstance();
+ agent.registerHandler(this);
+ }
+
+ /**
+ * Create an LttngLogAppender.
+ *
+ * @param name The name of the Appender, null returns null.
+ * @param ignoreExceptions If {@code "true"} (default) exceptions encountered
+ * when appending events are logged; otherwise they are
+ * propagated to the caller.
+ * @param filter The Filter or null.
+ *
+ * @return A new LttngLogAppender, null if the name was null.
+ *
+ * @throws IOException This handler requires the lttng-ust-log4j-jni.so
+ * native library, through which it will send the
+ * trace events. This exception is thrown if this
+ * library cannot be found.
+ * @throws SecurityException We will forward any SecurityExcepion that may be
+ * thrown when trying to load the JNI library.
+ */
+ @PluginFactory
+ public static LttngLogAppender createAppender(@PluginAttribute("name") String name,
+ @PluginAttribute("ignoreExceptions") Boolean ignoreExceptions, @PluginElement("Filters") Filter filter)
+ throws IOException, SecurityException {
+
+ if (name == null) {
+ LOGGER.error("No name provided for LttngLogAppender");
+ return null;
+ }
+
+ if (ignoreExceptions == null) {
+ ignoreExceptions = true;
+ }
+
+ return new LttngLogAppender(name, filter, ignoreExceptions);
+ }
+
+ @Override
+ public synchronized void close() {
+ agent.unregisterHandler(this);
+ }
+
+ @Override
+ public void stop() {
+ close();
+ super.stop();
+
+ getStatusLogger().debug("Appender Lttng stopped");
+ }
+
+ @Override
+ public boolean stop(final long timeout, final TimeUnit timeUnit) {
+ close();
+ boolean status = super.stop(timeout, timeUnit);
+
+ getStatusLogger().debug("Appender Lttng stopped with status " + status);
+
+ return status;
+ }
+
+ /**
+ * 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 append(LogEvent event) {
+ /*
+ * Check if the current message should be logged, according to the UST session
+ * settings.
+ */
+ if (!agent.isEventEnabled(event.getLoggerName())) {
+ return;
+ }
+
+ /*
+ * Default values if the StackTraceElement is null.
+ */
+ String classname = "";
+ String methodname = "";
+ String filename = "";
+ int line = -1;
+
+ StackTraceElement ste = event.getSource();
+ if (ste != null) {
+ classname = ste.getClassName();
+ methodname = ste.getMethodName();
+ filename = ste.getFileName();
+ line = ste.getLineNumber();
+ }
+
+ /* Retrieve all the requested context information we can find. */
+ Collection<Entry<String, Map<String, Integer>>> enabledContexts = agent.getEnabledAppContexts();
+ ContextInfoSerializer.SerializedContexts contextInfo = ContextInfoSerializer
+ .queryAndSerializeRequestedContexts(enabledContexts);
+
+ eventCount.incrementAndGet();
+
+ LttngLog4j2Api.tracepointWithContext(event.getMessage().getFormattedMessage(), event.getLoggerName(), classname,
+ methodname, filename, line, event.getTimeMillis(), event.getLevel().intLevel(), event.getThreadName(),
+ contextInfo.getEntriesArray(), contextInfo.getStringsArray());
+ }
+}
SUBDIRS += jul
endif
-if ENABLE_JAVA_AGENT_WITH_LOG4J
+if ENABLE_JAVA_AGENT_WITH_LOG4J_COMMON
SUBDIRS += log4j
endif
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
+liblttng_ust_log4j_jni_la_SOURCES = \
+ lttng_ust_log4j_tp.c \
+ lttng_ust_log4j_tp.h
+nodist_liblttng_ust_log4j_jni_la_SOURCES =
-nodist_liblttng_ust_log4j_jni_la_SOURCES = org_lttng_ust_agent_log4j_LttngLog4jApi.h
+if ENABLE_JAVA_AGENT_WITH_LOG4J
+liblttng_ust_log4j_jni_la_SOURCES += lttng_ust_log4j.c
+nodist_liblttng_ust_log4j_jni_la_SOURCES += org_lttng_ust_agent_log4j_LttngLog4jApi.h
+endif
+
+if ENABLE_JAVA_AGENT_WITH_LOG4J2
+liblttng_ust_log4j_jni_la_SOURCES += lttng_ust_log4j2.c
+nodist_liblttng_ust_log4j_jni_la_SOURCES += org_lttng_ust_agent_log4j2_LttngLog4j2Api.h
+endif
liblttng_ust_log4j_jni_la_LIBADD = -lc \
$(top_builddir)/src/lib/lttng-ust/liblttng-ust.la \
#define _LGPL_SOURCE
#include "org_lttng_ust_agent_log4j_LttngLog4jApi.h"
-
-#define LTTNG_UST_TRACEPOINT_HIDDEN_DEFINITION
-#define LTTNG_UST_TRACEPOINT_PROVIDER_HIDDEN_DEFINITION
-
-#define LTTNG_UST_TRACEPOINT_DEFINE
-#define LTTNG_UST_TRACEPOINT_CREATE_PROBES
-#include "lttng_ust_log4j.h"
+#include "lttng_ust_log4j_tp.h"
#include "../common/lttng_ust_context.h"
/*
+++ /dev/null
-/*
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- */
-
-#undef LTTNG_UST_TRACEPOINT_PROVIDER
-#define LTTNG_UST_TRACEPOINT_PROVIDER lttng_log4j
-
-#if !defined(_TRACEPOINT_LTTNG_UST_LOG4J_H) || defined(LTTNG_UST_TRACEPOINT_HEADER_MULTI_READ)
-#define _TRACEPOINT_LTTNG_UST_LOG4J_H
-
-#include <lttng/tracepoint.h>
-
-/*
- * Tracepoint used by Java applications using the log4j log appender.
- */
-LTTNG_UST_TRACEPOINT_EVENT(lttng_log4j, event,
- LTTNG_UST_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),
- LTTNG_UST_TP_FIELDS(
- lttng_ust_field_string(msg, msg)
- lttng_ust_field_string(logger_name, logger_name)
- lttng_ust_field_string(class_name, class_name)
- lttng_ust_field_string(method_name, method_name)
- lttng_ust_field_string(filename, file_name)
- lttng_ust_field_integer(int, line_number, line_number)
- lttng_ust_field_integer(long, timestamp, timestamp)
- lttng_ust_field_integer(int, int_loglevel, log_level)
- lttng_ust_field_string(thread_name, thread_name)
- )
-)
-
-#endif /* _TRACEPOINT_LTTNG_UST_LOG4J_H */
-
-#undef LTTNG_UST_TRACEPOINT_INCLUDE
-#define LTTNG_UST_TRACEPOINT_INCLUDE "./lttng_ust_log4j.h"
-
-/* This part must be outside protection */
-#include <lttng/tracepoint-event.h>
--- /dev/null
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2016-2022 EfficiOS Inc.
+ * Copyright (C) 2016 Alexandre Montplaisir <alexmonthy@efficios.com>
+ * Copyright (C) 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#define _LGPL_SOURCE
+#include "org_lttng_ust_agent_log4j2_LttngLog4j2Api.h"
+#include "lttng_ust_log4j_tp.h"
+#include "../common/lttng_ust_context.h"
+
+/*
+ * Those are an exact map from the class org.apache.log4j.Level.
+ */
+enum loglevel_log4j1 {
+ LOGLEVEL_LOG4J1_OFF = INT32_MAX,
+ LOGLEVEL_LOG4J1_FATAL = 50000,
+ LOGLEVEL_LOG4J1_ERROR = 40000,
+ LOGLEVEL_LOG4J1_WARN = 30000,
+ LOGLEVEL_LOG4J1_INFO = 20000,
+ LOGLEVEL_LOG4J1_DEBUG = 10000,
+ LOGLEVEL_LOG4J1_TRACE = 5000,
+ LOGLEVEL_LOG4J1_ALL = INT32_MIN,
+};
+
+/*
+ * Those are an exact map from the class
+ * org.apache.logging.log4j.spi.StandardLevel.
+ */
+enum loglevel_log4j2 {
+ LOGLEVEL_LOG4J2_OFF = 0,
+ LOGLEVEL_LOG4J2_FATAL = 100,
+ LOGLEVEL_LOG4J2_ERROR = 200,
+ LOGLEVEL_LOG4J2_WARN = 300,
+ LOGLEVEL_LOG4J2_INFO = 400,
+ LOGLEVEL_LOG4J2_DEBUG = 500,
+ LOGLEVEL_LOG4J2_TRACE = 600,
+ LOGLEVEL_LOG4J2_ALL = INT32_MAX,
+};
+
+/*
+ * The integer values of the loglevels has obviously changed in log4j2,
+ * translate them to the values of log4j1 since they are exposed in the API of
+ * lttng-tools.
+ *
+ * Custom loglevels might pose a problem when using ranges.
+ */
+static jint loglevel_2x_to_1x(jint loglevel)
+{
+ switch (loglevel) {
+ case LOGLEVEL_LOG4J2_OFF:
+ return LOGLEVEL_LOG4J1_OFF;
+ case LOGLEVEL_LOG4J2_FATAL:
+ return LOGLEVEL_LOG4J1_FATAL;
+ case LOGLEVEL_LOG4J2_ERROR:
+ return LOGLEVEL_LOG4J1_ERROR;
+ case LOGLEVEL_LOG4J2_WARN:
+ return LOGLEVEL_LOG4J1_WARN;
+ case LOGLEVEL_LOG4J2_INFO:
+ return LOGLEVEL_LOG4J1_INFO;
+ case LOGLEVEL_LOG4J2_DEBUG:
+ return LOGLEVEL_LOG4J1_DEBUG;
+ case LOGLEVEL_LOG4J2_TRACE:
+ return LOGLEVEL_LOG4J1_TRACE;
+ case LOGLEVEL_LOG4J2_ALL:
+ return LOGLEVEL_LOG4J1_ALL;
+ default:
+ /* Handle custom loglevels. */
+ return loglevel;
+ }
+}
+
+/*
+ * Tracepoint used by Java applications using the log4j 2.x handler.
+ */
+JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j2_LttngLog4j2Api_tracepointWithContext(JNIEnv *env,
+ jobject jobj __attribute__((unused)),
+ jstring message,
+ jstring loggerName,
+ jstring className,
+ jstring methodName,
+ jstring fileName,
+ jint lineNumber,
+ jlong timeStamp,
+ jint logLevel,
+ jstring threadName,
+ jbyteArray context_info_entries,
+ jbyteArray context_info_strings)
+{
+ jboolean iscopy;
+ const char *msg_cstr = (*env)->GetStringUTFChars(env, message, &iscopy);
+ const char *logger_name_cstr = (*env)->GetStringUTFChars(env, loggerName, &iscopy);
+ const char *class_name_cstr = (*env)->GetStringUTFChars(env, className, &iscopy);
+ const char *method_name_cstr = (*env)->GetStringUTFChars(env, methodName, &iscopy);
+ const char *file_name_cstr = (*env)->GetStringUTFChars(env, fileName, &iscopy);
+ const char *thread_name_cstr = (*env)->GetStringUTFChars(env, threadName, &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);
+
+ lttng_ust_tracepoint(lttng_log4j, event, msg_cstr, logger_name_cstr,
+ class_name_cstr, method_name_cstr, file_name_cstr,
+ lineNumber, timeStamp, loglevel_2x_to_1x(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, message, msg_cstr);
+ (*env)->ReleaseStringUTFChars(env, loggerName, logger_name_cstr);
+ (*env)->ReleaseStringUTFChars(env, className, class_name_cstr);
+ (*env)->ReleaseStringUTFChars(env, methodName, method_name_cstr);
+ (*env)->ReleaseStringUTFChars(env, fileName, file_name_cstr);
+ (*env)->ReleaseStringUTFChars(env, threadName, 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);
+}
--- /dev/null
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2016 EfficiOS Inc.
+ * Copyright (C) 2016 Alexandre Montplaisir <alexmonthy@efficios.com>
+ * Copyright (C) 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#define _LGPL_SOURCE
+
+#define LTTNG_UST_TRACEPOINT_HIDDEN_DEFINITION
+#define LTTNG_UST_TRACEPOINT_PROVIDER_HIDDEN_DEFINITION
+
+#define LTTNG_UST_TRACEPOINT_DEFINE
+#define LTTNG_UST_TRACEPOINT_CREATE_PROBES
+#include "lttng_ust_log4j_tp.h"
--- /dev/null
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#undef LTTNG_UST_TRACEPOINT_PROVIDER
+#define LTTNG_UST_TRACEPOINT_PROVIDER lttng_log4j
+
+#if !defined(_TRACEPOINT_LTTNG_UST_LOG4J_H) || defined(LTTNG_UST_TRACEPOINT_HEADER_MULTI_READ)
+#define _TRACEPOINT_LTTNG_UST_LOG4J_H
+
+#include <lttng/tracepoint.h>
+
+/*
+ * Tracepoint used by Java applications using the log4j log appender.
+ */
+LTTNG_UST_TRACEPOINT_EVENT(lttng_log4j, event,
+ LTTNG_UST_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),
+ LTTNG_UST_TP_FIELDS(
+ lttng_ust_field_string(msg, msg)
+ lttng_ust_field_string(logger_name, logger_name)
+ lttng_ust_field_string(class_name, class_name)
+ lttng_ust_field_string(method_name, method_name)
+ lttng_ust_field_string(filename, file_name)
+ lttng_ust_field_integer(int, line_number, line_number)
+ lttng_ust_field_integer(long, timestamp, timestamp)
+ lttng_ust_field_integer(int, int_loglevel, log_level)
+ lttng_ust_field_string(thread_name, thread_name)
+ )
+)
+
+#endif /* _TRACEPOINT_LTTNG_UST_LOG4J_H */
+
+#undef LTTNG_UST_TRACEPOINT_INCLUDE
+#define LTTNG_UST_TRACEPOINT_INCLUDE "./lttng_ust_log4j_tp.h"
+
+/* This part must be outside protection */
+#include <lttng/tracepoint-event.h>