Add a Log4j 2.x Java agent
authorMichael Jeanson <mjeanson@efficios.com>
Thu, 6 Jan 2022 19:36:46 +0000 (14:36 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 21 Feb 2022 15:15:58 +0000 (10:15 -0500)
This adds a new agent to the LTTng-UST Java agents suite supporting the
Log4j 2.x logging backend.

This new agent can be enabled with the following configure options :

  $ export CLASSPATH=/path/to/log4j-core.jar:/path/to/log4j-api.jar
  $ ./configure --enable-java-agent-log4j2

This backport differs from the master branch for the
'--enable-java-agent-all' option won't select this new agent since we
wanted to avoid introducing a new dependency in existing configurations.

The name of the new agent jar file is "lttng-ust-agent-log4j2.jar".
It will be installed in the arch-agnostic "$prefix/share/java" path
e.g: "/usr/share/java".

It uses the same jni library "liblttng-ust-log4j-jni.so" as the Log4j 1.x agent.

The agent was designed as a mostly drop-in replacement for applications
upgrading from Log4j 1.x to 2.x. It requires no modification to the
tracing configuration as it uses the same domain "-l / LOG4J" and the
loglevels integer representations are converted to the Log4j 1.x values
(excluding custom loglevels).

The recommended way to use this agent with Log4j 2.x is to add an
"Lttng" Appender with an arbiraty name and associate it with one or more
Logger using an AppenderRef.

For example, here is a basic log4j2 xml configuration that would send
all logging statements exlusively to an lttng appender:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="WARN">
      <Appenders>
        <Lttng name="LTTNG"/>
      </Appenders>
      <Loggers>
        <Root level="all">
          <AppenderRef ref="LTTNG"/>
        </Root>
      </Loggers>
    </Configuration>

More examples can be found in the 'doc/examples' directory.

The implementation of the appender is based on this[1] great guide by
Keith D. Gregory which is so much more detailed than the official
documentation, my thanks to him.

[1] https://www.kdgregory.com/index.php?page=logging.log4j2Plugins

Change-Id: I34593c9a4c3140c8839cef8b58cc85745fe9f47f
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
37 files changed:
.gitignore
README.md
configure.ac
doc/examples/Makefile.am
doc/examples/java-jul/Makefile
doc/examples/java-log4j/Hello.java [deleted file]
doc/examples/java-log4j/HelloLog4j.java [new file with mode: 0644]
doc/examples/java-log4j/Makefile
doc/examples/java-log4j/run
doc/examples/java-log4j2-basic/.intree [new file with mode: 0644]
doc/examples/java-log4j2-basic/HelloLog4j2.java [new file with mode: 0644]
doc/examples/java-log4j2-basic/Makefile [new file with mode: 0644]
doc/examples/java-log4j2-basic/log4j2.xml [new file with mode: 0644]
doc/examples/java-log4j2-basic/run [new file with mode: 0755]
doc/examples/java-log4j2-ctx/HelloLog4j2Ctx.java [new file with mode: 0644]
doc/examples/java-log4j2-ctx/Makefile [new file with mode: 0644]
doc/examples/java-log4j2-ctx/log4j2.ctx1.xml [new file with mode: 0644]
doc/examples/java-log4j2-ctx/log4j2.ctx2.xml [new file with mode: 0644]
doc/examples/java-log4j2-ctx/run [new file with mode: 0755]
doc/examples/java-log4j2-prog/.intree [new file with mode: 0644]
doc/examples/java-log4j2-prog/HelloLog4j2Prog.java [new file with mode: 0644]
doc/examples/java-log4j2-prog/Makefile [new file with mode: 0644]
doc/examples/java-log4j2-prog/run [new file with mode: 0755]
doc/java-agent.txt
liblttng-ust-java-agent/java/Makefile.am
liblttng-ust-java-agent/java/lttng-ust-agent-all/Manifest.txt
liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/Makefile.am [new file with mode: 0644]
liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/Manifest.txt [new file with mode: 0644]
liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLog4j2Agent.java [new file with mode: 0644]
liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLog4j2Api.java [new file with mode: 0644]
liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLogAppender.java [new file with mode: 0644]
liblttng-ust-java-agent/jni/Makefile.am
liblttng-ust-java-agent/jni/log4j/Makefile.am
liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c
liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j2.c [new file with mode: 0644]
liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.c [new file with mode: 0644]
liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.h [new file with mode: 0644]

index 2050e04fab2ab2a246ceae8832752fefee4c813f..00361c4b5269ae2402a8ab2f97480232440a9779 100644 (file)
@@ -88,6 +88,7 @@ tests/gcc-weak-hidden/test_gcc_weak_hidden
 
 # Java agent library
 *.class
+META-INF
 lttng-ust-agent*.jar
 liblttng-ust-agent.jar
 classnoinst.stamp
@@ -98,6 +99,7 @@ log4j-jni-header.stamp
 org_lttng_ust_agent_context_LttngContextApi.h
 org_lttng_ust_agent_jul_LttngJulApi.h
 org_lttng_ust_agent_log4j_LttngLog4jApi.h
+org_lttng_ust_agent_log4j2_LttngLog4j2Api.h
 
 # Python agent
 python-lttngust/lttngust/__init__.py
index fc2cc6c057bb49755079097786b64054f3998bfe..e611826ab4ae3fc11a4af1a1702e7cfdca02d953 100644 (file)
--- a/README.md
+++ b/README.md
@@ -230,7 +230,7 @@ This package contains the following elements:
     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
index 8a16ec76d7208409a218f9ba03b580e67ef557e6..019d9753effd82a383c2e3e0f4c501b104314fa4 100644 (file)
@@ -337,25 +337,39 @@ AS_HELP_STRING([--enable-java-agent-jul], [build the LTTng UST Java agent with J
 ])
 
 AC_ARG_ENABLE([java-agent-log4j], [
-AS_HELP_STRING([--enable-java-agent-log4j], [build the LTTng UST Java agent with Log4j support [default=no]])
+AS_HELP_STRING([--enable-java-agent-log4j], [build the LTTng UST Java agent with Log4j 1.x support [default=no]])
 ], [
        java_agent_log4j=$enableval
 ], [
        java_agent_log4j=no
 ])
 
+AC_ARG_ENABLE([java-agent-log4j2], [
+AS_HELP_STRING([--enable-java-agent-log4j2], [build the LTTng UST Java agent with Log4j 2.x support [default=no]])
+], [
+       java_agent_log4j2=$enableval
+], [
+       java_agent_log4j2=no
+])
+
 AC_ARG_ENABLE([java-agent-all], [
 AS_HELP_STRING([--enable-java-agent-all], [build the LTTng UST Java agent with all supported backends [default=no]])
 ], [
        java_agent_jul=$enableval
        java_agent_log4j=$enableval
+       # This backport to a stable branch requires the explicit use of
+       # '--enable-java-agent-log4j2' to avoid introducing a new dependency in
+       # an existing configuration.
+       #java_agent_log4j2=$enableval
 ], [:])
 
 AM_CONDITIONAL([BUILD_JAVA_AGENT], [test "x$java_agent_jul" = "xyes" || test "x$java_agent_log4j" = "xyes"])
 AM_CONDITIONAL([BUILD_JAVA_AGENT_WITH_JUL], [test "x$java_agent_jul" = "xyes"])
 AM_CONDITIONAL([BUILD_JAVA_AGENT_WITH_LOG4J], [test "x$java_agent_log4j" = "xyes"])
+AM_CONDITIONAL([BUILD_JAVA_AGENT_WITH_LOG4J2], [test "x$java_agent_log4j2" = "xyes"])
+AM_CONDITIONAL([BUILD_JAVA_AGENT_WITH_LOG4J_COMMON], [test "x$java_agent_log4j" = "xyes" || test "x$java_agent_log4j2" = "xyes"])
 
-AS_IF([test "x$jni_interface" = "xyes" || test "x$java_agent_jul" = "xyes" || test "x$java_agent_log4j" = "xyes"], [
+AS_IF([test "x$jni_interface" = "xyes" || test "x$java_agent_jul" = "xyes" || test "x$java_agent_log4j" = "xyes" || test "x$java_agent_log4j2" = "xyes"], [
        AX_JAVA_OPTIONS
        AX_PROG_JAVAC
        AX_PROG_JAVA
@@ -384,6 +398,21 @@ AS_IF([test "x$java_agent_log4j" = "xyes"], [
        ])
 ])
 
+# The log4j 2.x agent requires the log4j core and api jars in the classpath
+AS_IF([test "x$java_agent_log4j2" = "xyes"], [
+  AX_CHECK_CLASSPATH
+  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"
+    ])
+  ])
+])
+
 # Option to build the python agent
 AC_ARG_ENABLE([python-agent], [
 AS_HELP_STRING([--enable-python-agent], [build the LTTng UST Python agent [default=no]])
@@ -534,6 +563,7 @@ AC_CONFIG_FILES([
        liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile
        liblttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile
        liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile
+       liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/Makefile
        liblttng-ust-java-agent/jni/Makefile
        liblttng-ust-java-agent/jni/common/Makefile
        liblttng-ust-java-agent/jni/jul/Makefile
@@ -612,7 +642,10 @@ test "x$java_agent_jul" = xyes && value=1 || value=0
 PPRINT_PROP_BOOL_CUSTOM([Java agent (JUL support)], $value, [use --enable-java-agent-jul])
 
 test "x$java_agent_log4j" = xyes && 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)], $value, [use --enable-java-agent-log4j])
+
+test "x$java_agent_log4j2" = xyes && value=1 || value=0
+PPRINT_PROP_BOOL_CUSTOM([Java agent (Log4j 2.x support)], $value, [use --enable-java-agent-log4j2])
 
 test "x$jni_interface" = xyes && value=1 || value=0
 PPRINT_PROP_BOOL_CUSTOM([JNI interface (JNI)], $value, [use --enable-jni-interface])
index dc18d650ada80b802dd0864b678cf2fbee75ec67..23f28e8546b43b6b7766e6380e7e171ae82b2b3e 100644 (file)
@@ -23,11 +23,36 @@ endif
 if BUILD_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/HelloLog4j.java \
                                  java-log4j/run
 SUBDIRS_LOG4J = java-log4j
 endif
 
+if BUILD_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 BUILD_PYTHON_AGENT
 doc_examples_pythondir = ${docdir}/examples/python
 dist_doc_examples_python_DATA = python/hello.py
@@ -107,7 +132,7 @@ endif
 
 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; \
@@ -166,6 +191,18 @@ all-local:
                        ) || 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="../../../liblttng-ust-java-agent/java/lttng-ust-agent-log4j2" \
+                                       JAVA_CLASSPATH_OVERRIDE_COMMON="../../../liblttng-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 \
                        ( \
@@ -208,6 +245,13 @@ clean-local:
                        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 \
@@ -216,7 +260,7 @@ clean-local:
                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;
index 5a594ff3e2f200ef3d62f5cfa25d2c78fa5826e2..8e3b4e59d0d48a18a6cb12f461133971557e1843 100644 (file)
@@ -48,4 +48,4 @@ classes: $(CLASSES:.java=.class)
 
 .PHONY: clean
 clean:
-       $(RM) *.class
+       $(RM) $(CLASSES:.java=.class)
diff --git a/doc/examples/java-log4j/Hello.java b/doc/examples/java-log4j/Hello.java
deleted file mode 100644 (file)
index 2f1119c..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2015 - EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
- * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-import java.io.IOException;
-
-import org.apache.log4j.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();
-       }
-}
diff --git a/doc/examples/java-log4j/HelloLog4j.java b/doc/examples/java-log4j/HelloLog4j.java
new file mode 100644 (file)
index 0000000..1870ef4
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 - EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
+ * Copyright (C) 2014 - Christian Babeux <christian.babeux@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+import java.io.IOException;
+
+import org.apache.log4j.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();
+       }
+}
index 39c2e788bf66a50964d6d610195be1a4f965e88d..75df0986bebc2ab09eae76ea4d54199707c5a587 100644 (file)
@@ -45,7 +45,7 @@ JC = javac -classpath "$(CLASSPATH):$(LOG4J_CP):$(COMMON_CP):."
 .java.class:
        $(JC) $(JFLAGS) $*.java
 
-CLASSES = Hello.java
+CLASSES = HelloLog4j.java
 
 all: classes
 
@@ -53,4 +53,4 @@ classes: $(CLASSES:.java=.class)
 
 .PHONY: clean
 clean:
-       $(RM) *.class
+       $(RM) $(CLASSES:.java=.class)
index 997d0bdcd529bdf5181143d0be5a655f8e833383..7624f514a338871d6286253e5c4d55dd90663e30 100755 (executable)
@@ -6,7 +6,7 @@
 # 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=""
@@ -16,7 +16,7 @@ if [ "x$CLASSPATH" = "x" ]; then
        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:../../../liblttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON"
@@ -33,6 +33,4 @@ if [ "x$LIBPATH" != "x" ]; then
        JAVA_OPTIONS="$JAVA_OPTIONS -Djava.library.path=$LIBPATH"
 fi
 
-java -classpath "$CLASSPATH:." $JAVA_OPTIONS Hello
-
-cd -
+java -classpath "$CLASSPATH:." $JAVA_OPTIONS HelloLog4j
diff --git a/doc/examples/java-log4j2-basic/.intree b/doc/examples/java-log4j2-basic/.intree
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/doc/examples/java-log4j2-basic/HelloLog4j2.java b/doc/examples/java-log4j2-basic/HelloLog4j2.java
new file mode 100644 (file)
index 0000000..2aa1026
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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");
+       }
+}
diff --git a/doc/examples/java-log4j2-basic/Makefile b/doc/examples/java-log4j2-basic/Makefile
new file mode 100644 (file)
index 0000000..a14b0a7
--- /dev/null
@@ -0,0 +1,48 @@
+# 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)
diff --git a/doc/examples/java-log4j2-basic/log4j2.xml b/doc/examples/java-log4j2-basic/log4j2.xml
new file mode 100644 (file)
index 0000000..2dc83dd
--- /dev/null
@@ -0,0 +1,16 @@
+<?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>
diff --git a/doc/examples/java-log4j2-basic/run b/doc/examples/java-log4j2-basic/run
new file mode 100755 (executable)
index 0000000..e365656
--- /dev/null
@@ -0,0 +1,38 @@
+#!/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:../../../lib/lttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON"
+       CLASSPATH="$CLASSPATH:../../../lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/$JARFILE_LOG4J2"
+       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_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
diff --git a/doc/examples/java-log4j2-ctx/HelloLog4j2Ctx.java b/doc/examples/java-log4j2-ctx/HelloLog4j2Ctx.java
new file mode 100644 (file)
index 0000000..b953223
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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");
+               }
+       }
+}
diff --git a/doc/examples/java-log4j2-ctx/Makefile b/doc/examples/java-log4j2-ctx/Makefile
new file mode 100644 (file)
index 0000000..931854e
--- /dev/null
@@ -0,0 +1,48 @@
+# 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)
diff --git a/doc/examples/java-log4j2-ctx/log4j2.ctx1.xml b/doc/examples/java-log4j2-ctx/log4j2.ctx1.xml
new file mode 100644 (file)
index 0000000..d59ce77
--- /dev/null
@@ -0,0 +1,16 @@
+<?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>
diff --git a/doc/examples/java-log4j2-ctx/log4j2.ctx2.xml b/doc/examples/java-log4j2-ctx/log4j2.ctx2.xml
new file mode 100644 (file)
index 0000000..c62af2e
--- /dev/null
@@ -0,0 +1,16 @@
+<?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>
diff --git a/doc/examples/java-log4j2-ctx/run b/doc/examples/java-log4j2-ctx/run
new file mode 100755 (executable)
index 0000000..319e3eb
--- /dev/null
@@ -0,0 +1,38 @@
+#!/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:../../../lib/lttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON"
+       CLASSPATH="$CLASSPATH:../../../lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/$JARFILE_LOG4J2"
+       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_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
diff --git a/doc/examples/java-log4j2-prog/.intree b/doc/examples/java-log4j2-prog/.intree
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/doc/examples/java-log4j2-prog/HelloLog4j2Prog.java b/doc/examples/java-log4j2-prog/HelloLog4j2Prog.java
new file mode 100644 (file)
index 0000000..685eebf
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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");
+       }
+}
diff --git a/doc/examples/java-log4j2-prog/Makefile b/doc/examples/java-log4j2-prog/Makefile
new file mode 100644 (file)
index 0000000..1e2c108
--- /dev/null
@@ -0,0 +1,48 @@
+# 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)
diff --git a/doc/examples/java-log4j2-prog/run b/doc/examples/java-log4j2-prog/run
new file mode 100755 (executable)
index 0000000..c6b8463
--- /dev/null
@@ -0,0 +1,38 @@
+#!/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:../../../lib/lttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON"
+       CLASSPATH="$CLASSPATH:../../../lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/$JARFILE_LOG4J2"
+       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_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
index ae653820ef5181c57604151879319c84d9c721bd..75ce336cbddbd42dbc4e709cff61466c57d184e3 100644 (file)
@@ -8,15 +8,20 @@ The agent can be built in three different configurations:
 
 $ ./configure --enable-java-agent-jul
 
-2) Java agent with Log4j support:
+2) Java agent with Log4j 1.x support:
 
 $ 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
-$ ./configure --enable-java-agent-all
+$ 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 --enable-java-agent-log4j2
 
 To build the agent with log4j support, make sure that the log4j jar
 is in your Java classpath.
@@ -25,24 +30,28 @@ The configure script will automatically detect the appropriate Java
 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
index 1720d313e368452ff516a1d17e1034cc011b7adf..b8c23992fbd8cb7523ee9f2a9c7915f515ab60e0 100644 (file)
@@ -7,3 +7,7 @@ endif
 if BUILD_JAVA_AGENT_WITH_LOG4J
 SUBDIRS += lttng-ust-agent-log4j
 endif
+
+if BUILD_JAVA_AGENT_WITH_LOG4J2
+SUBDIRS += lttng-ust-agent-log4j2
+endif
index e09c85ecdb92aa67f793a040240965b727a9162c..c752478cc8d32fcb3bd861150d0c544bdfd149bd 100644 (file)
@@ -5,4 +5,4 @@ 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
+Class-Path: lttng-ust-agent-common.jar lttng-ust-agent-jul.jar lttng-ust-agent-log4j.jar lttng-ust-agent-log4j2.jar
diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/Makefile.am b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/Makefile.am
new file mode 100644 (file)
index 0000000..639ae53
--- /dev/null
@@ -0,0 +1,60 @@
+# 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
diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/Manifest.txt b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/Manifest.txt
new file mode 100644 (file)
index 0000000..1cd1b74
--- /dev/null
@@ -0,0 +1,8 @@
+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
diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLog4j2Agent.java b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLog4j2Agent.java
new file mode 100644 (file)
index 0000000..cb7c35a
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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());
+
+       }
+}
diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLog4j2Api.java b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLog4j2Api.java
new file mode 100644 (file)
index 0000000..617d0d1
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * 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);
+}
diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLogAppender.java b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLogAppender.java
new file mode 100644 (file)
index 0000000..9c093fa
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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());
+       }
+}
index dae512001de532ff49301688a7e0ce8ef6bbc5fb..e481d84061a471901ec716e738c18aaf47943297 100644 (file)
@@ -4,6 +4,6 @@ if BUILD_JAVA_AGENT_WITH_JUL
 SUBDIRS += jul
 endif
 
-if BUILD_JAVA_AGENT_WITH_LOG4J
+if BUILD_JAVA_AGENT_WITH_LOG4J_COMMON
 SUBDIRS += log4j
 endif
index 5e5fe0fcf1ffc238ea39ca802f3ce75b8f97c1a3..d3a88b45f6d3e5bfb3c8e1e8d26ea46152a97a88 100644 (file)
@@ -1,10 +1,20 @@
 AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include $(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 BUILD_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 BUILD_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 \
        -L$(top_builddir)/liblttng-ust/.libs \
index 72eca1d4a7c71be6fb3744d969d74b6352ee9766..f33dbc9c7d9bfa4c02a183d7219836d63945563c 100644 (file)
@@ -20,9 +20,7 @@
 #define _LGPL_SOURCE
 #include "org_lttng_ust_agent_log4j_LttngLog4jApi.h"
 
-#define TRACEPOINT_DEFINE
-#define TRACEPOINT_CREATE_PROBES
-#include "lttng_ust_log4j.h"
+#include "lttng_ust_log4j_tp.h"
 #include "../common/lttng_ust_context.h"
 
 /*
diff --git a/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j2.c b/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j2.c
new file mode 100644 (file)
index 0000000..68616bf
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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);
+
+       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);
+}
diff --git a/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.c b/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.c
new file mode 100644 (file)
index 0000000..ac31e2c
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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 TRACEPOINT_HIDDEN_DEFINITION
+#define TRACEPOINT_PROVIDER_HIDDEN_DEFINITION
+
+#define TRACEPOINT_DEFINE
+#define TRACEPOINT_CREATE_PROBES
+#include "lttng_ust_log4j_tp.h"
diff --git a/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.h b/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.h
new file mode 100644 (file)
index 0000000..5aab2d9
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#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 <lttng/tracepoint.h>
+
+/*
+ * 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_tp.h"
+
+/* This part must be outside protection */
+#include <lttng/tracepoint-event.h>
This page took 0.052124 seconds and 4 git commands to generate.