Move to kernel style SPDX license identifiers
[lttng-ust.git] / liblttng-ust-java-agent / java / lttng-ust-agent-common / org / lttng / ust / agent / LTTngAgent.java
CommitLineData
501f6777 1/*
c0c0989a 2 * SPDX-License-Identifier: LGPL-2.1-only
501f6777 3 *
c0c0989a 4 * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
501f6777
CB
5 */
6
7package org.lttng.ust.agent;
8
d60dfbe4 9import java.lang.reflect.Constructor;
01a00a70 10import java.lang.reflect.InvocationTargetException;
d60dfbe4
AM
11import java.lang.reflect.Method;
12import java.util.logging.Handler;
13import java.util.logging.Logger;
501f6777 14
5bfeaeca
AM
15/**
16 * The central agent managing the JUL and Log4j handlers.
17 *
18 * @author David Goulet
d60dfbe4
AM
19 * @deprecated Applications are now expected to manage their Logger and Handler
20 * objects.
5bfeaeca 21 */
d60dfbe4 22@Deprecated
501f6777 23public class LTTngAgent {
08284556 24
d60dfbe4 25 private static LTTngAgent instance = null;
501f6777 26
d60dfbe4
AM
27 /**
28 * Public getter to acquire a reference to this singleton object.
29 *
30 * @return The agent instance
31 */
32 public static synchronized LTTngAgent getLTTngAgent() {
33 if (instance == null) {
34 instance = new LTTngAgent();
501f6777 35 }
d60dfbe4
AM
36 return instance;
37 }
501f6777 38
d60dfbe4
AM
39 /**
40 * Dispose the agent. Applications should call this once they are done
9355f049
MD
41 * logging. This dispose function is non-static for backwards
42 * compatibility purposes.
d60dfbe4 43 */
41f8fda3 44 @SuppressWarnings("static-method")
6b4fc51e
AM
45 public void dispose() {
46 synchronized (LTTngAgent.class) {
47 if (instance != null) {
48 instance.disposeInstance();
49 instance = null;
50 }
501f6777 51 }
d60dfbe4 52 return;
501f6777
CB
53 }
54
d60dfbe4
AM
55 private ILttngHandler julHandler = null;
56 private ILttngHandler log4jAppender = null;
08284556 57
d60dfbe4
AM
58 /**
59 * Private constructor. This is a singleton and a reference should be
60 * acquired using {@link #getLTTngAgent()}.
61 */
62 private LTTngAgent() {
63 initJulHandler();
64 initLog4jAppender();
65 }
501f6777 66
d60dfbe4
AM
67 /**
68 * "Destructor" method.
69 */
70 private void disposeInstance() {
71 disposeJulHandler();
72 disposeLog4jAppender();
73 }
501f6777 74
d60dfbe4
AM
75 /**
76 * Create a LTTng-JUL handler, and attach it to the JUL root logger.
77 */
78 private void initJulHandler() {
79 try {
80 Class<?> julHandlerClass = Class.forName("org.lttng.ust.agent.jul.LttngLogHandler");
81 /*
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).
86 */
87 Constructor<?> julHandlerCtor = julHandlerClass.getConstructor();
88 julHandler = (ILttngHandler) julHandlerCtor.newInstance();
89
90 /* Attach the handler to the root JUL logger */
91 Logger.getLogger("").addHandler((Handler) julHandler);
01a00a70 92
d60dfbe4 93 /*
01a00a70
AM
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.
d60dfbe4 97 */
01a00a70
AM
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) {
d60dfbe4
AM
105 }
106 }
501f6777 107
d60dfbe4
AM
108 /**
109 * Create a LTTng-logj4 appender, and attach it to the log4j root logger.
110 */
111 private void initLog4jAppender() {
112 /*
113 * Since Log4j is a 3rd party library, we first need to check if we can
114 * load any of its classes.
115 */
116 if (!testLog4jClasses()) {
117 return;
118 }
501f6777 119
d60dfbe4
AM
120 try {
121 Class<?> log4jAppenderClass = Class.forName("org.lttng.ust.agent.log4j.LttngLogAppender");
122 Constructor<?> log4jAppendCtor = log4jAppenderClass.getConstructor();
123 log4jAppender = (ILttngHandler) log4jAppendCtor.newInstance();
01a00a70 124
d60dfbe4 125 /*
01a00a70
AM
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.
d60dfbe4 129 */
01a00a70
AM
130 } catch (SecurityException e) {
131 return;
132 } catch (ClassNotFoundException e) {
133 return;
134 } catch (NoSuchMethodException e) {
135 return;
136 } catch (IllegalArgumentException e) {
137 return;
138 } catch (InstantiationException e) {
139 return;
140 } catch (IllegalAccessException e) {
141 return;
142 } catch (InvocationTargetException e) {
d60dfbe4
AM
143 return;
144 }
501f6777 145
d60dfbe4
AM
146 /*
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.
151 */
152 try {
153 Class<?> loggerClass = Class.forName("org.apache.log4j.Logger");
154 Class<?> appenderClass = Class.forName("org.apache.log4j.Appender");
501f6777 155
d60dfbe4
AM
156 Method getRootLoggerMethod = loggerClass.getMethod("getRootLogger", (Class<?>[]) null);
157 Method addAppenderMethod = loggerClass.getMethod("addAppender", appenderClass);
501f6777 158
d60dfbe4
AM
159 Object rootLogger = getRootLoggerMethod.invoke(null, (Object[]) null);
160 addAppenderMethod.invoke(rootLogger, log4jAppender);
501f6777 161
d60dfbe4 162 /*
01a00a70
AM
163 * We have checked for the log4j library version previously, none of
164 * the following exceptions should happen.
d60dfbe4 165 */
01a00a70
AM
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);
501f6777 178 }
501f6777
CB
179 }
180
d60dfbe4
AM
181 /**
182 * Check if log4j >= 1.2.15 library is present.
183 */
184 private static boolean testLog4jClasses() {
185 Class<?> loggingEventClass;
17be0b58 186
501f6777 187 try {
d60dfbe4 188 loggingEventClass = Class.forName("org.apache.log4j.spi.LoggingEvent");
501f6777 189 } catch (ClassNotFoundException e) {
d60dfbe4
AM
190 /*
191 * Log4j classes not found, no need to create the relevant objects
192 */
17be0b58
CB
193 return false;
194 }
195
196 /*
d60dfbe4
AM
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.
17be0b58 200 *
d60dfbe4
AM
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.
17be0b58 205 *
d60dfbe4 206 * More info: https://issues.apache.org/bugzilla/show_bug.cgi?id=44370
17be0b58 207 */
17be0b58 208 try {
d60dfbe4 209 loggingEventClass.getDeclaredMethod("getTimeStamp");
17be0b58 210 } catch (NoSuchMethodException e) {
d60dfbe4
AM
211 System.err.println(
212 "Warning: The loaded log4j library is too old. Log4j tracing with LTTng will be disabled.");
17be0b58
CB
213 return false;
214 } catch (SecurityException e) {
215 return false;
501f6777
CB
216 }
217
17be0b58 218 return true;
501f6777
CB
219 }
220
5bfeaeca 221 /**
d60dfbe4 222 * Detach the JUL handler from its logger and close it.
501f6777 223 */
d60dfbe4
AM
224 private void disposeJulHandler() {
225 if (julHandler == null) {
226 /* The JUL handler was not activated, we have nothing to do */
501f6777
CB
227 return;
228 }
d60dfbe4
AM
229 Logger.getLogger("").removeHandler((Handler) julHandler);
230 julHandler.close();
231 julHandler = null;
501f6777
CB
232 }
233
5bfeaeca 234 /**
d60dfbe4 235 * Detach the log4j appender from its logger and close it.
5bfeaeca 236 */
d60dfbe4
AM
237 private void disposeLog4jAppender() {
238 if (log4jAppender == null) {
239 /* The log4j appender was not active, we have nothing to do */
240 return;
501f6777
CB
241 }
242
d60dfbe4
AM
243 /*
244 * Detach the appender from the log4j root logger. Again, we have to do
245 * this via reflection.
246 */
501f6777 247 try {
d60dfbe4
AM
248 Class<?> loggerClass = Class.forName("org.apache.log4j.Logger");
249 Class<?> appenderClass = Class.forName("org.apache.log4j.Appender");
501f6777 250
d60dfbe4
AM
251 Method getRootLoggerMethod = loggerClass.getMethod("getRootLogger", (Class<?>[]) null);
252 Method removeAppenderMethod = loggerClass.getMethod("removeAppender", appenderClass);
501f6777 253
d60dfbe4
AM
254 Object rootLogger = getRootLoggerMethod.invoke(null, (Object[]) null);
255 removeAppenderMethod.invoke(rootLogger, log4jAppender);
256
d60dfbe4 257 /*
01a00a70
AM
258 * We were able to attach the appender previously, we should not
259 * have problems here either!
d60dfbe4 260 */
01a00a70
AM
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);
501f6777 273 }
d60dfbe4
AM
274
275 /* Close the appender */
276 log4jAppender.close();
277 log4jAppender = null;
501f6777 278 }
d60dfbe4 279
501f6777 280}
This page took 0.039769 seconds and 4 git commands to generate.