2 * SPDX-License-Identifier: LGPL-2.1-only
4 * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
7 package org
.lttng
.ust
.agent
;
9 import java
.lang
.reflect
.Constructor
;
10 import java
.lang
.reflect
.InvocationTargetException
;
11 import java
.lang
.reflect
.Method
;
12 import java
.util
.logging
.Handler
;
13 import java
.util
.logging
.Logger
;
16 * The central agent managing the JUL and Log4j handlers.
18 * @author David Goulet
19 * @deprecated Applications are now expected to manage their Logger and Handler
23 public class LTTngAgent
{
25 private static LTTngAgent instance
= null;
28 * Public getter to acquire a reference to this singleton object.
30 * @return The agent instance
32 public static synchronized LTTngAgent
getLTTngAgent() {
33 if (instance
== null) {
34 instance
= new LTTngAgent();
40 * Dispose the agent. Applications should call this once they are done
41 * logging. This dispose function is non-static for backwards
42 * compatibility purposes.
44 @SuppressWarnings("static-method")
45 public void dispose() {
46 synchronized (LTTngAgent
.class) {
47 if (instance
!= null) {
48 instance
.disposeInstance();
55 private ILttngHandler julHandler
= null;
56 private ILttngHandler log4jAppender
= null;
59 * Private constructor. This is a singleton and a reference should be
60 * acquired using {@link #getLTTngAgent()}.
62 private LTTngAgent() {
68 * "Destructor" method.
70 private void disposeInstance() {
72 disposeLog4jAppender();
76 * Create a LTTng-JUL handler, and attach it to the JUL root logger.
78 private void initJulHandler() {
80 Class
<?
> julHandlerClass
= Class
.forName("org.lttng.ust.agent.jul.LttngLogHandler");
82 * It is safer to use Constructor.newInstance() rather than
83 * Class.newInstance(), because it will catch the exceptions thrown
84 * by the constructor below (which happens if the Java library is
85 * present, but the matching JNI one is not).
87 Constructor
<?
> julHandlerCtor
= julHandlerClass
.getConstructor();
88 julHandler
= (ILttngHandler
) julHandlerCtor
.newInstance();
90 /* Attach the handler to the root JUL logger */
91 Logger
.getLogger("").addHandler((Handler
) julHandler
);
94 * If any of the following exceptions happen, it means we could not
95 * find or initialize LTTng JUL classes. We will not setup LTTng JUL
96 * tracing in this case.
98 } catch (SecurityException e
) {
99 } catch (IllegalAccessException e
) {
100 } catch (IllegalArgumentException e
) {
101 } catch (ClassNotFoundException e
) {
102 } catch (NoSuchMethodException e
) {
103 } catch (InstantiationException e
) {
104 } catch (InvocationTargetException e
) {
109 * Create a LTTng-logj4 appender, and attach it to the log4j root logger.
111 private void initLog4jAppender() {
113 * Since Log4j is a 3rd party library, we first need to check if we can
114 * load any of its classes.
116 if (!testLog4jClasses()) {
121 Class
<?
> log4jAppenderClass
= Class
.forName("org.lttng.ust.agent.log4j.LttngLogAppender");
122 Constructor
<?
> log4jAppendCtor
= log4jAppenderClass
.getConstructor();
123 log4jAppender
= (ILttngHandler
) log4jAppendCtor
.newInstance();
126 * If any of the following exceptions happen, it means we could not
127 * find or initialize LTTng log4j classes. We will not setup LTTng
128 * log4j tracing in this case.
130 } catch (SecurityException e
) {
132 } catch (ClassNotFoundException e
) {
134 } catch (NoSuchMethodException e
) {
136 } catch (IllegalArgumentException e
) {
138 } catch (InstantiationException e
) {
140 } catch (IllegalAccessException e
) {
142 } catch (InvocationTargetException e
) {
147 * Attach the appender to the root Log4j logger. Slightly more tricky
148 * here, as log4j.Logger is not in the base Java library, and we do not
149 * want the "common" package to depend on log4j. So we have to obtain it
150 * through reflection too.
153 Class
<?
> loggerClass
= Class
.forName("org.apache.log4j.Logger");
154 Class
<?
> appenderClass
= Class
.forName("org.apache.log4j.Appender");
156 Method getRootLoggerMethod
= loggerClass
.getMethod("getRootLogger", (Class
<?
>[]) null);
157 Method addAppenderMethod
= loggerClass
.getMethod("addAppender", appenderClass
);
159 Object rootLogger
= getRootLoggerMethod
.invoke(null, (Object
[]) null);
160 addAppenderMethod
.invoke(rootLogger
, log4jAppender
);
163 * We have checked for the log4j library version previously, none of
164 * the following exceptions should happen.
166 } catch (SecurityException e
) {
167 throw new IllegalStateException(e
);
168 } catch (ClassNotFoundException e
) {
169 throw new IllegalStateException(e
);
170 } catch (NoSuchMethodException e
) {
171 throw new IllegalStateException(e
);
172 } catch (IllegalArgumentException e
) {
173 throw new IllegalStateException(e
);
174 } catch (IllegalAccessException e
) {
175 throw new IllegalStateException(e
);
176 } catch (InvocationTargetException e
) {
177 throw new IllegalStateException(e
);
182 * Check if log4j >= 1.2.15 library is present.
184 private static boolean testLog4jClasses() {
185 Class
<?
> loggingEventClass
;
188 loggingEventClass
= Class
.forName("org.apache.log4j.spi.LoggingEvent");
189 } catch (ClassNotFoundException e
) {
191 * Log4j classes not found, no need to create the relevant objects
197 * Detect capabilities of the log4j library. We only support log4j >=
198 * 1.2.15. The getTimeStamp() method was introduced in log4j 1.2.15, so
199 * verify that it is available.
201 * We can't rely on the getPackage().getImplementationVersion() call
202 * that would retrieves information from the manifest file found in the
203 * JAR since the manifest file shipped from upstream is known to be
204 * broken in several versions of the library.
206 * More info: https://issues.apache.org/bugzilla/show_bug.cgi?id=44370
209 loggingEventClass
.getDeclaredMethod("getTimeStamp");
210 } catch (NoSuchMethodException e
) {
212 "Warning: The loaded log4j library is too old. Log4j tracing with LTTng will be disabled.");
214 } catch (SecurityException e
) {
222 * Detach the JUL handler from its logger and close it.
224 private void disposeJulHandler() {
225 if (julHandler
== null) {
226 /* The JUL handler was not activated, we have nothing to do */
229 Logger
.getLogger("").removeHandler((Handler
) julHandler
);
235 * Detach the log4j appender from its logger and close it.
237 private void disposeLog4jAppender() {
238 if (log4jAppender
== null) {
239 /* The log4j appender was not active, we have nothing to do */
244 * Detach the appender from the log4j root logger. Again, we have to do
245 * this via reflection.
248 Class
<?
> loggerClass
= Class
.forName("org.apache.log4j.Logger");
249 Class
<?
> appenderClass
= Class
.forName("org.apache.log4j.Appender");
251 Method getRootLoggerMethod
= loggerClass
.getMethod("getRootLogger", (Class
<?
>[]) null);
252 Method removeAppenderMethod
= loggerClass
.getMethod("removeAppender", appenderClass
);
254 Object rootLogger
= getRootLoggerMethod
.invoke(null, (Object
[]) null);
255 removeAppenderMethod
.invoke(rootLogger
, log4jAppender
);
258 * We were able to attach the appender previously, we should not
259 * have problems here either!
261 } catch (SecurityException e
) {
262 throw new IllegalStateException(e
);
263 } catch (ClassNotFoundException e
) {
264 throw new IllegalStateException(e
);
265 } catch (NoSuchMethodException e
) {
266 throw new IllegalStateException(e
);
267 } catch (IllegalArgumentException e
) {
268 throw new IllegalStateException(e
);
269 } catch (IllegalAccessException e
) {
270 throw new IllegalStateException(e
);
271 } catch (InvocationTargetException e
) {
272 throw new IllegalStateException(e
);
275 /* Close the appender */
276 log4jAppender
.close();
277 log4jAppender
= null;