ebbe2357770b6c9b57e6f386fab1f89c22d0e140
[lttng-ust.git] / liblttng-ust-java-agent / java / lttng-ust-agent-common / org / lttng / ust / agent / LTTngAgent.java
1 /*
2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
3 *
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.
7 *
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
11 * for more details.
12 *
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
16 */
17
18 package org.lttng.ust.agent;
19
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;
25
26 /**
27 * The central agent managing the JUL and Log4j handlers.
28 *
29 * @author David Goulet
30 * @deprecated Applications are now expected to manage their Logger and Handler
31 * objects.
32 */
33 @Deprecated
34 public class LTTngAgent {
35
36 private static LTTngAgent instance = null;
37
38 /**
39 * Public getter to acquire a reference to this singleton object.
40 *
41 * @return The agent instance
42 */
43 public static synchronized LTTngAgent getLTTngAgent() {
44 if (instance == null) {
45 instance = new LTTngAgent();
46 }
47 return instance;
48 }
49
50 /**
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.
54 */
55 @SuppressWarnings("static-method")
56 public void dispose() {
57 synchronized (LTTngAgent.class) {
58 if (instance != null) {
59 instance.disposeInstance();
60 instance = null;
61 }
62 }
63 return;
64 }
65
66 private ILttngHandler julHandler = null;
67 private ILttngHandler log4jAppender = null;
68
69 /**
70 * Private constructor. This is a singleton and a reference should be
71 * acquired using {@link #getLTTngAgent()}.
72 */
73 private LTTngAgent() {
74 initJulHandler();
75 initLog4jAppender();
76 }
77
78 /**
79 * "Destructor" method.
80 */
81 private void disposeInstance() {
82 disposeJulHandler();
83 disposeLog4jAppender();
84 }
85
86 /**
87 * Create a LTTng-JUL handler, and attach it to the JUL root logger.
88 */
89 private void initJulHandler() {
90 try {
91 Class<?> julHandlerClass = Class.forName("org.lttng.ust.agent.jul.LttngLogHandler");
92 /*
93 * It is safer to use Constructor.newInstance() rather than
94 * Class.newInstance(), because it will catch the exceptions thrown
95 * by the constructor below (which happens if the Java library is
96 * present, but the matching JNI one is not).
97 */
98 Constructor<?> julHandlerCtor = julHandlerClass.getConstructor();
99 julHandler = (ILttngHandler) julHandlerCtor.newInstance();
100
101 /* Attach the handler to the root JUL logger */
102 Logger.getLogger("").addHandler((Handler) julHandler);
103
104 /*
105 * If any of the following exceptions happen, it means we could not
106 * find or initialize LTTng JUL classes. We will not setup LTTng JUL
107 * tracing in this case.
108 */
109 } catch (SecurityException e) {
110 } catch (IllegalAccessException e) {
111 } catch (IllegalArgumentException e) {
112 } catch (ClassNotFoundException e) {
113 } catch (NoSuchMethodException e) {
114 } catch (InstantiationException e) {
115 } catch (InvocationTargetException e) {
116 }
117 }
118
119 /**
120 * Create a LTTng-logj4 appender, and attach it to the log4j root logger.
121 */
122 private void initLog4jAppender() {
123 /*
124 * Since Log4j is a 3rd party library, we first need to check if we can
125 * load any of its classes.
126 */
127 if (!testLog4jClasses()) {
128 return;
129 }
130
131 try {
132 Class<?> log4jAppenderClass = Class.forName("org.lttng.ust.agent.log4j.LttngLogAppender");
133 Constructor<?> log4jAppendCtor = log4jAppenderClass.getConstructor();
134 log4jAppender = (ILttngHandler) log4jAppendCtor.newInstance();
135
136 /*
137 * If any of the following exceptions happen, it means we could not
138 * find or initialize LTTng log4j classes. We will not setup LTTng
139 * log4j tracing in this case.
140 */
141 } catch (SecurityException e) {
142 return;
143 } catch (ClassNotFoundException e) {
144 return;
145 } catch (NoSuchMethodException e) {
146 return;
147 } catch (IllegalArgumentException e) {
148 return;
149 } catch (InstantiationException e) {
150 return;
151 } catch (IllegalAccessException e) {
152 return;
153 } catch (InvocationTargetException e) {
154 return;
155 }
156
157 /*
158 * Attach the appender to the root Log4j logger. Slightly more tricky
159 * here, as log4j.Logger is not in the base Java library, and we do not
160 * want the "common" package to depend on log4j. So we have to obtain it
161 * through reflection too.
162 */
163 try {
164 Class<?> loggerClass = Class.forName("org.apache.log4j.Logger");
165 Class<?> appenderClass = Class.forName("org.apache.log4j.Appender");
166
167 Method getRootLoggerMethod = loggerClass.getMethod("getRootLogger", (Class<?>[]) null);
168 Method addAppenderMethod = loggerClass.getMethod("addAppender", appenderClass);
169
170 Object rootLogger = getRootLoggerMethod.invoke(null, (Object[]) null);
171 addAppenderMethod.invoke(rootLogger, log4jAppender);
172
173 /*
174 * We have checked for the log4j library version previously, none of
175 * the following exceptions should happen.
176 */
177 } catch (SecurityException e) {
178 throw new IllegalStateException(e);
179 } catch (ClassNotFoundException e) {
180 throw new IllegalStateException(e);
181 } catch (NoSuchMethodException e) {
182 throw new IllegalStateException(e);
183 } catch (IllegalArgumentException e) {
184 throw new IllegalStateException(e);
185 } catch (IllegalAccessException e) {
186 throw new IllegalStateException(e);
187 } catch (InvocationTargetException e) {
188 throw new IllegalStateException(e);
189 }
190 }
191
192 /**
193 * Check if log4j >= 1.2.15 library is present.
194 */
195 private static boolean testLog4jClasses() {
196 Class<?> loggingEventClass;
197
198 try {
199 loggingEventClass = Class.forName("org.apache.log4j.spi.LoggingEvent");
200 } catch (ClassNotFoundException e) {
201 /*
202 * Log4j classes not found, no need to create the relevant objects
203 */
204 return false;
205 }
206
207 /*
208 * Detect capabilities of the log4j library. We only support log4j >=
209 * 1.2.15. The getTimeStamp() method was introduced in log4j 1.2.15, so
210 * verify that it is available.
211 *
212 * We can't rely on the getPackage().getImplementationVersion() call
213 * that would retrieves information from the manifest file found in the
214 * JAR since the manifest file shipped from upstream is known to be
215 * broken in several versions of the library.
216 *
217 * More info: https://issues.apache.org/bugzilla/show_bug.cgi?id=44370
218 */
219 try {
220 loggingEventClass.getDeclaredMethod("getTimeStamp");
221 } catch (NoSuchMethodException e) {
222 System.err.println(
223 "Warning: The loaded log4j library is too old. Log4j tracing with LTTng will be disabled.");
224 return false;
225 } catch (SecurityException e) {
226 return false;
227 }
228
229 return true;
230 }
231
232 /**
233 * Detach the JUL handler from its logger and close it.
234 */
235 private void disposeJulHandler() {
236 if (julHandler == null) {
237 /* The JUL handler was not activated, we have nothing to do */
238 return;
239 }
240 Logger.getLogger("").removeHandler((Handler) julHandler);
241 julHandler.close();
242 julHandler = null;
243 }
244
245 /**
246 * Detach the log4j appender from its logger and close it.
247 */
248 private void disposeLog4jAppender() {
249 if (log4jAppender == null) {
250 /* The log4j appender was not active, we have nothing to do */
251 return;
252 }
253
254 /*
255 * Detach the appender from the log4j root logger. Again, we have to do
256 * this via reflection.
257 */
258 try {
259 Class<?> loggerClass = Class.forName("org.apache.log4j.Logger");
260 Class<?> appenderClass = Class.forName("org.apache.log4j.Appender");
261
262 Method getRootLoggerMethod = loggerClass.getMethod("getRootLogger", (Class<?>[]) null);
263 Method removeAppenderMethod = loggerClass.getMethod("removeAppender", appenderClass);
264
265 Object rootLogger = getRootLoggerMethod.invoke(null, (Object[]) null);
266 removeAppenderMethod.invoke(rootLogger, log4jAppender);
267
268 /*
269 * We were able to attach the appender previously, we should not
270 * have problems here either!
271 */
272 } catch (SecurityException e) {
273 throw new IllegalStateException(e);
274 } catch (ClassNotFoundException e) {
275 throw new IllegalStateException(e);
276 } catch (NoSuchMethodException e) {
277 throw new IllegalStateException(e);
278 } catch (IllegalArgumentException e) {
279 throw new IllegalStateException(e);
280 } catch (IllegalAccessException e) {
281 throw new IllegalStateException(e);
282 } catch (InvocationTargetException e) {
283 throw new IllegalStateException(e);
284 }
285
286 /* Close the appender */
287 log4jAppender.close();
288 log4jAppender = null;
289 }
290
291 }
This page took 0.034289 seconds and 3 git commands to generate.