2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, version 2.1 only,
6 * as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 package org
.lttng
.ust
.agent
;
20 import java
.lang
.reflect
.Constructor
;
21 import java
.lang
.reflect
.InvocationTargetException
;
22 import java
.lang
.reflect
.Method
;
23 import java
.util
.logging
.Handler
;
24 import java
.util
.logging
.Logger
;
27 * The central agent managing the JUL and Log4j handlers.
29 * @author David Goulet
30 * @deprecated Applications are now expected to manage their Logger and Handler
34 public class LTTngAgent
{
36 private static LTTngAgent instance
= null;
39 * Public getter to acquire a reference to this singleton object.
41 * @return The agent instance
43 public static synchronized LTTngAgent
getLTTngAgent() {
44 if (instance
== null) {
45 instance
= new LTTngAgent();
51 * Dispose the agent. Applications should call this once they are done
52 * logging. This dispose function is non-static for backwards
53 * compatibility purposes.
55 public synchronized void dispose() {
56 if (instance
!= null) {
57 instance
.disposeInstance();
63 private ILttngHandler julHandler
= null;
64 private ILttngHandler log4jAppender
= null;
67 * Private constructor. This is a singleton and a reference should be
68 * acquired using {@link #getLTTngAgent()}.
70 private LTTngAgent() {
76 * "Destructor" method.
78 private void disposeInstance() {
80 disposeLog4jAppender();
84 * Create a LTTng-JUL handler, and attach it to the JUL root logger.
86 private void initJulHandler() {
88 Class
<?
> julHandlerClass
= Class
.forName("org.lttng.ust.agent.jul.LttngLogHandler");
90 * It is safer to use Constructor.newInstance() rather than
91 * Class.newInstance(), because it will catch the exceptions thrown
92 * by the constructor below (which happens if the Java library is
93 * present, but the matching JNI one is not).
95 Constructor
<?
> julHandlerCtor
= julHandlerClass
.getConstructor();
96 julHandler
= (ILttngHandler
) julHandlerCtor
.newInstance();
98 /* Attach the handler to the root JUL logger */
99 Logger
.getLogger("").addHandler((Handler
) julHandler
);
102 * If any of the following exceptions happen, it means we could not
103 * find or initialize LTTng JUL classes. We will not setup LTTng JUL
104 * tracing in this case.
106 } catch (SecurityException e
) {
107 } catch (IllegalAccessException e
) {
108 } catch (IllegalArgumentException e
) {
109 } catch (ClassNotFoundException e
) {
110 } catch (NoSuchMethodException e
) {
111 } catch (InstantiationException e
) {
112 } catch (InvocationTargetException e
) {
117 * Create a LTTng-logj4 appender, and attach it to the log4j root logger.
119 private void initLog4jAppender() {
121 * Since Log4j is a 3rd party library, we first need to check if we can
122 * load any of its classes.
124 if (!testLog4jClasses()) {
129 Class
<?
> log4jAppenderClass
= Class
.forName("org.lttng.ust.agent.log4j.LttngLogAppender");
130 Constructor
<?
> log4jAppendCtor
= log4jAppenderClass
.getConstructor();
131 log4jAppender
= (ILttngHandler
) log4jAppendCtor
.newInstance();
134 * If any of the following exceptions happen, it means we could not
135 * find or initialize LTTng log4j classes. We will not setup LTTng
136 * log4j tracing in this case.
138 } catch (SecurityException e
) {
140 } catch (ClassNotFoundException e
) {
142 } catch (NoSuchMethodException e
) {
144 } catch (IllegalArgumentException e
) {
146 } catch (InstantiationException e
) {
148 } catch (IllegalAccessException e
) {
150 } catch (InvocationTargetException e
) {
155 * Attach the appender to the root Log4j logger. Slightly more tricky
156 * here, as log4j.Logger is not in the base Java library, and we do not
157 * want the "common" package to depend on log4j. So we have to obtain it
158 * through reflection too.
161 Class
<?
> loggerClass
= Class
.forName("org.apache.log4j.Logger");
162 Class
<?
> appenderClass
= Class
.forName("org.apache.log4j.Appender");
164 Method getRootLoggerMethod
= loggerClass
.getMethod("getRootLogger", (Class
<?
>[]) null);
165 Method addAppenderMethod
= loggerClass
.getMethod("addAppender", appenderClass
);
167 Object rootLogger
= getRootLoggerMethod
.invoke(null, (Object
[]) null);
168 addAppenderMethod
.invoke(rootLogger
, log4jAppender
);
171 * We have checked for the log4j library version previously, none of
172 * the following exceptions should happen.
174 } catch (SecurityException e
) {
175 throw new IllegalStateException(e
);
176 } catch (ClassNotFoundException e
) {
177 throw new IllegalStateException(e
);
178 } catch (NoSuchMethodException e
) {
179 throw new IllegalStateException(e
);
180 } catch (IllegalArgumentException e
) {
181 throw new IllegalStateException(e
);
182 } catch (IllegalAccessException e
) {
183 throw new IllegalStateException(e
);
184 } catch (InvocationTargetException e
) {
185 throw new IllegalStateException(e
);
190 * Check if log4j >= 1.2.15 library is present.
192 private static boolean testLog4jClasses() {
193 Class
<?
> loggingEventClass
;
196 loggingEventClass
= Class
.forName("org.apache.log4j.spi.LoggingEvent");
197 } catch (ClassNotFoundException e
) {
199 * Log4j classes not found, no need to create the relevant objects
205 * Detect capabilities of the log4j library. We only support log4j >=
206 * 1.2.15. The getTimeStamp() method was introduced in log4j 1.2.15, so
207 * verify that it is available.
209 * We can't rely on the getPackage().getImplementationVersion() call
210 * that would retrieves information from the manifest file found in the
211 * JAR since the manifest file shipped from upstream is known to be
212 * broken in several versions of the library.
214 * More info: https://issues.apache.org/bugzilla/show_bug.cgi?id=44370
217 loggingEventClass
.getDeclaredMethod("getTimeStamp");
218 } catch (NoSuchMethodException e
) {
220 "Warning: The loaded log4j library is too old. Log4j tracing with LTTng will be disabled.");
222 } catch (SecurityException e
) {
230 * Detach the JUL handler from its logger and close it.
232 private void disposeJulHandler() {
233 if (julHandler
== null) {
234 /* The JUL handler was not activated, we have nothing to do */
237 Logger
.getLogger("").removeHandler((Handler
) julHandler
);
243 * Detach the log4j appender from its logger and close it.
245 private void disposeLog4jAppender() {
246 if (log4jAppender
== null) {
247 /* The log4j appender was not active, we have nothing to do */
252 * Detach the appender from the log4j root logger. Again, we have to do
253 * this via reflection.
256 Class
<?
> loggerClass
= Class
.forName("org.apache.log4j.Logger");
257 Class
<?
> appenderClass
= Class
.forName("org.apache.log4j.Appender");
259 Method getRootLoggerMethod
= loggerClass
.getMethod("getRootLogger", (Class
<?
>[]) null);
260 Method removeAppenderMethod
= loggerClass
.getMethod("removeAppender", appenderClass
);
262 Object rootLogger
= getRootLoggerMethod
.invoke(null, (Object
[]) null);
263 removeAppenderMethod
.invoke(rootLogger
, log4jAppender
);
266 * We were able to attach the appender previously, we should not
267 * have problems here either!
269 } catch (SecurityException e
) {
270 throw new IllegalStateException(e
);
271 } catch (ClassNotFoundException e
) {
272 throw new IllegalStateException(e
);
273 } catch (NoSuchMethodException e
) {
274 throw new IllegalStateException(e
);
275 } catch (IllegalArgumentException e
) {
276 throw new IllegalStateException(e
);
277 } catch (IllegalAccessException e
) {
278 throw new IllegalStateException(e
);
279 } catch (InvocationTargetException e
) {
280 throw new IllegalStateException(e
);
283 /* Close the appender */
284 log4jAppender
.close();
285 log4jAppender
= null;