| 1 | <!-- |
| 2 | SPDX-FileCopyrightText: 2014 Christian Babeux <christian.babeux@efficios.com> |
| 3 | SPDX-FileCopyrightText: 2015 Alexandre Montplaisir <alexmonthy@efficios.com> |
| 4 | SPDX-FileCopyrightText: 2022 Michael Jeanson <mjeanson@efficios.com> |
| 5 | |
| 6 | SPDX-License-Identifier: CC-BY-4.0 |
| 7 | --> |
| 8 | |
| 9 | # Using the Java agent |
| 10 | |
| 11 | The agent can be built in three different configurations: |
| 12 | |
| 13 | 1) Java agent with JUL support: |
| 14 | |
| 15 | $ ./configure --enable-java-agent-jul |
| 16 | |
| 17 | 2) Java agent with Log4j 1.x support (deprecated): |
| 18 | |
| 19 | $ export CLASSPATH=$CLASSPATH:/path/to/log4j.jar |
| 20 | $ ./configure --enable-java-agent-log4j |
| 21 | |
| 22 | 3) Java agent with Log4j 2.x support: |
| 23 | |
| 24 | $ export CLASSPATH=$CLASSPATH:/path/to/log4j-core.jar:/path/to/log4j-api.jar |
| 25 | $ ./configure --enable-java-agent-log4j2 |
| 26 | |
| 27 | 4) Java agent with JUL + Log4j 1.x + Log4j 2.x support |
| 28 | |
| 29 | $ export CLASSPATH=$CLASSPATH:/path/to/log4j.jar:/path/to/log4j-core.jar:/path/to/log4j-api.jar |
| 30 | $ ./configure --enable-java-agent-all |
| 31 | |
| 32 | To build the agent with log4j support, make sure that the log4j jar |
| 33 | is in your Java classpath. |
| 34 | |
| 35 | The configure script will automatically detect the appropriate Java |
| 36 | binaries to use in order to build the Java agent. |
| 37 | |
| 38 | Enabling the JUL support will build a `lttng-ust-agent-jul.jar` file. Enabling |
| 39 | the log4j 1.x support will build a `lttng-ust-agent-log4j.jar` and enabling |
| 40 | log4j 2.x support will build a `lttng-ust-agent-log4j2.jar`. All of these jars |
| 41 | depend on a fourth `lttng-ust-agent-common.jar`, which will always be built. |
| 42 | |
| 43 | All these archives will be installed in the arch-agnostic `$prefix/share/java` |
| 44 | path, e.g: `/usr/share/java`. You need to make sure the .jar for the logging |
| 45 | API you want to use (either `lttng-ust-agent-jul.jar`, |
| 46 | `lttng-ust-agent-log4j.jar` or `lttng-ust-agent-log4j2.jar`) is on your |
| 47 | application's classpath. |
| 48 | |
| 49 | The logging libraries require an architecture-specific shared object, |
| 50 | `liblttng-ust-jul-jni.so` for JUL and `liblttng-ust-jul-log4j.so` for both |
| 51 | Log4j 1.x and 2.x, which are installed by the build system when doing `make |
| 52 | install`. Make sure that your Java application can find this shared object, by |
| 53 | using the `java.library.path` property if necessary. |
| 54 | |
| 55 | In order to use UST tracing in your Java application, you simply need to |
| 56 | instantiate a `LttngLogHandler` or a `LttngLogAppender` (for JUL or Log4j, |
| 57 | respectively), then attach it to a JUL or Log4j Logger class. |
| 58 | |
| 59 | Refer to the code examples in `examples/java-jul/`, `examples/java-log4j/` and |
| 60 | `examples/java-log4j2-*/`. |
| 61 | |
| 62 | LTTng session daemon agents will be initialized as needed. If no session daemon |
| 63 | is available, the execution will continue and the agents will retry connecting |
| 64 | every 3 seconds. |
| 65 | |
| 66 | |
| 67 | # Object model |
| 68 | |
| 69 | The object model of the Java agent implementation is as follows: |
| 70 | |
| 71 | ## Ownership |
| 72 | |
| 73 | Log Handlers: LttngLogHandler, LttngLogAppender |
| 74 | n handlers/appenders, managed by the application. |
| 75 | Can be created programmatically, or via a configuration file, |
| 76 | Each one registers to a specific agent singleton (one per logging API) that is loaded on-demand |
| 77 | |
| 78 | Agent singletons: LttngJulAgent, LttngLog4jAgent |
| 79 | Keep track of all handlers/appenders registered to them. |
| 80 | Are disposed when last handler deregisters. |
| 81 | Each agent instantiates 2 TCP clients, one for the root session daemon, one for the user one. |
| 82 | One type of TCP client class for now. TCP client may become a singleton in the future. |
| 83 | |
| 84 | ## Control |
| 85 | |
| 86 | Messages come from the session daemon through the socket connection. |
| 87 | Agent passes back-reference to itself to the TCP clients. |
| 88 | Clients use this reference to invoke callbacks, which modify the state of the agent (enabling/disabling events, etc.) |
| 89 | |
| 90 | ## Data path |
| 91 | |
| 92 | Log messages are generated by the application and sent to the Logger objects, |
| 93 | which then send them to the Handlers. |
| 94 | |
| 95 | When a log event is received by a Handler (publish(LogRecord)), the handler |
| 96 | checks with the agent if it should log it or not, via |
| 97 | ILttngAgent#isEventEnabled() for example. |
| 98 | |
| 99 | Events that are logged call the native tracepoint through JNI, which generates |
| 100 | a UST event. There is one type of tracepoint per domain (Jul or Logj4). |
| 101 | |
| 102 | ## Filtering notifications |
| 103 | |
| 104 | FilterChangeNotifier is the singleton notifier class. |
| 105 | Applications implement an IFilterChangeListener, and register it to the notifier. |
| 106 | |
| 107 | Whenever new event rules are enabled or disabled, the relevant agent informs the |
| 108 | notifier, which then sends notifications to all registered listeners by invoking |
| 109 | their callbacks. |
| 110 | |
| 111 | Upon registration, a new listener will receive notifications for all currently |
| 112 | active rules. |
| 113 | |
| 114 | The notifier keeps track of its own event rule refcounting, to handle the case |
| 115 | of multiple sessions or multiple agents enabling identical event rules. |
| 116 | |
| 117 | The FilterChangeNotifier does not have threads of its own. The listeners's |
| 118 | callbacks will be invoked by these threads: |
| 119 | * In the case of a notification being received while a listener is already |
| 120 | registered, the callback is executed by the TCP client's thread. This |
| 121 | effectively blocks the "lttng" command line until all callbacks are processed |
| 122 | (assuming no timeouts). |
| 123 | * In the case of a listener registering and receiving the currently-active |
| 124 | rules, the callbacks will be executed by the application's thread doing the |
| 125 | registerListener() call. |
| 126 | |
| 127 | The notifier is entirely synchronized. This ensure that if a rule is enabled |
| 128 | at the same time a listener is registered, that listener does not miss or |
| 129 | receive duplicate notifications. |