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, 24 Jan 2022 20:28:46 +0000 (15:28 -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 2 different configure options :

  1) Java agent with Log4j 2.x support:
  $ export CLASSPATH=/path/to/log4j-core.jar:/path/to/log4j-api.jar
  $ ./configure --enable-java-agent-log4j2

  2) Java agent with JUL + Log4j + Log4j2 support
  $ export CLASSPATH=/path/to/log4j-core.jar:/path/to/log4j-api.jar:/path/to/log4j-1.2.jar
  $ ./configure --enable-java-agent-all

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>
38 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
src/lib/lttng-ust-java-agent/java/Makefile.am
src/lib/lttng-ust-java-agent/java/lttng-ust-agent-all/Manifest.txt
src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/Makefile.am [new file with mode: 0644]
src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/Manifest.txt [new file with mode: 0644]
src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLog4j2Agent.java [new file with mode: 0644]
src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLog4j2Api.java [new file with mode: 0644]
src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLogAppender.java [new file with mode: 0644]
src/lib/lttng-ust-java-agent/jni/Makefile.am
src/lib/lttng-ust-java-agent/jni/log4j/Makefile.am
src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c
src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h [deleted file]
src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j2.c [new file with mode: 0644]
src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.c [new file with mode: 0644]
src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.h [new file with mode: 0644]

index 7dbd41fd45b9e2bb456668243628bf175bb1fa66..acceec5ede434b8d1c42ce6b5f89dd0845efb66f 100644 (file)
@@ -133,9 +133,14 @@ cscope.*
 /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
 
@@ -168,10 +173,12 @@ cscope.*
 /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
index a101048622e42778d9c4e233e21a52fa3b3f6c65..286703baa2c4e90501f8d33b1ed825acd230fbf8 100644 (file)
--- a/README.md
+++ b/README.md
@@ -235,7 +235,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 7493f62be6a2541b2cce29ad830d4d925c36a36d..ba4c85559ad4037c0dd4d9da3c3ed361efcbddb5 100644 (file)
@@ -345,10 +345,15 @@ AE_FEATURE([jni-interface], [build JNI interface between C and Java])
 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
@@ -397,6 +402,7 @@ AE_IF_FEATURE_DISABLED([shared], [
 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])
 ])
 
 
@@ -418,7 +424,8 @@ argument to disable NUMA support.
 ])
 
 # 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
@@ -436,7 +443,7 @@ AS_IF([AE_IS_FEATURE_ENABLED([jni-interface]) || AE_IS_FEATURE_ENABLED([java-age
   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"], [
@@ -450,6 +457,21 @@ Current CLASSPATH: "$CLASSPATH"
   ])
 ])
 
+# 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"], [
@@ -528,9 +550,11 @@ AC_DEFINE([LTTNG_UST_CTL_LIB_SONAME_MAJOR], [ust_ctl_lib_version_current], [Majo
 
 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]))
@@ -592,6 +616,7 @@ AC_CONFIG_FILES([
   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
@@ -690,7 +715,10 @@ AE_IS_FEATURE_ENABLED([java-agent-jul]) && value=1 || value=0
 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])
index 8ee05646624940f1661d988000d669bee875cbfe..727aa7ceb5ab065651f69449834d87adaea50af6 100644 (file)
@@ -25,11 +25,36 @@ endif
 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
@@ -111,7 +136,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; \
@@ -173,6 +198,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="../../../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 \
                        ( \
@@ -215,6 +252,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 \
@@ -223,7 +267,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 aff2f8e8a975f77daff8f6da1a51f0474d2c7239..c981c76779b30c0946fbbc49aca84f3a911febd9 100644 (file)
@@ -40,4 +40,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 e90c756..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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();
-       }
-}
diff --git a/doc/examples/java-log4j/HelloLog4j.java b/doc/examples/java-log4j/HelloLog4j.java
new file mode 100644 (file)
index 0000000..11c96ab
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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();
+       }
+}
index 5d560493db859194d2b435c99149f50a04d4c300..9ef6b7963079c64f88628da0a7906d6e2dfa7c1a 100644 (file)
@@ -37,7 +37,7 @@ JC = javac -classpath "$(CLASSPATH):$(LOG4J_CP):$(COMMON_CP):."
 .java.class:
        $(JC) $(JFLAGS) $*.java
 
-CLASSES = Hello.java
+CLASSES = HelloLog4j.java
 
 all: classes
 
@@ -45,4 +45,4 @@ classes: $(CLASSES:.java=.class)
 
 .PHONY: clean
 clean:
-       $(RM) *.class
+       $(RM) $(CLASSES:.java=.class)
index ce23171737b2fd41ceaa8a0ef6d64a6fdf32105d..c153e7b848569dc713b53051ad93d7ecbfc59587 100755 (executable)
@@ -8,7 +8,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=""
@@ -18,7 +18,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:../../../src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/$JARFILE_COMMON"
@@ -35,6 +35,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..4d9f25f
--- /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:../../../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
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..5aae324
--- /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:../../../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
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..8f4e81d
--- /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:../../../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
index ae653820ef5181c57604151879319c84d9c721bd..a7612a6873e8835134650808316df0a79127dc75 100644 (file)
@@ -8,14 +8,19 @@ 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 (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
@@ -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 96d575aa52e1159b830aa475777c643d8a48f9a9..542650bfc8d4b884f056ff4d65e71700eb57ea84 100644 (file)
@@ -9,3 +9,7 @@ endif
 if ENABLE_JAVA_AGENT_WITH_LOG4J
 SUBDIRS += lttng-ust-agent-log4j
 endif
+
+if ENABLE_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/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/Makefile.am b/src/lib/lttng-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/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/Manifest.txt b/src/lib/lttng-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/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLog4j2Agent.java b/src/lib/lttng-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/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLog4j2Api.java b/src/lib/lttng-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/src/lib/lttng-ust-java-agent/java/lttng-ust-agent-log4j2/org/lttng/ust/agent/log4j2/LttngLogAppender.java b/src/lib/lttng-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 711fd4759662ae91bdcc78ebe56b53b727c43366..3149475705c05f0e16fd40a9d0442758e4ab5c75 100644 (file)
@@ -6,6 +6,6 @@ if ENABLE_JAVA_AGENT_WITH_JUL
 SUBDIRS += jul
 endif
 
-if ENABLE_JAVA_AGENT_WITH_LOG4J
+if ENABLE_JAVA_AGENT_WITH_LOG4J_COMMON
 SUBDIRS += log4j
 endif
index 8d95257418abc05db83ba05a0e551472cfc29b1b..bc1db2484a959659e1ee3c6441cbfb69feccb9da 100644 (file)
@@ -3,10 +3,20 @@
 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 \
index fac8285740a04877662c14f5384697764a158736..a5630a2a3fecf4fded199eab368a622a68a9511e 100644 (file)
@@ -8,13 +8,7 @@
 
 #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"
 
 /*
diff --git a/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h b/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j.h
deleted file mode 100644 (file)
index c10145a..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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>
diff --git a/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j2.c b/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j2.c
new file mode 100644 (file)
index 0000000..e89602f
--- /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);
+
+       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);
+}
diff --git a/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.c b/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.c
new file mode 100644 (file)
index 0000000..9e09067
--- /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 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"
diff --git a/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.h b/src/lib/lttng-ust-java-agent/jni/log4j/lttng_ust_log4j_tp.h
new file mode 100644 (file)
index 0000000..8fa8118
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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>
This page took 0.051836 seconds and 4 git commands to generate.