Fix: Warn when log4j version is too old
[lttng-ust.git] / liblttng-ust-java-agent / java / org / lttng / ust / agent / LTTngAgent.java
CommitLineData
501f6777
CB
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
18package org.lttng.ust.agent;
19
20import org.lttng.ust.agent.jul.LTTngJUL;
21
22import java.io.IOException;
23import java.io.InputStream;
24import java.io.BufferedReader;
25import java.io.FileReader;
26import java.util.concurrent.Semaphore;
27import java.util.concurrent.TimeUnit;
28import java.util.Enumeration;
29import java.lang.reflect.InvocationTargetException;
30
31import java.util.logging.Logger;
501f6777
CB
32import java.util.logging.SimpleFormatter;
33
34public class LTTngAgent {
35 /* Domains */
36 static enum Domain {
37 JUL(3), LOG4J(4);
38 private int value;
39
40 private Domain(int value) {
41 this.value = value;
42 }
43
44 public int value() {
45 return value;
46 }
47 }
48
49 private static LogFramework julUser;
50 private static LogFramework julRoot;
51 private static LogFramework log4jUser;
52 private static LogFramework log4jRoot;
53
54 /* Sessiond clients */
55 private static LTTngTCPSessiondClient julUserClient;
56 private static LTTngTCPSessiondClient julRootClient;
57 private static LTTngTCPSessiondClient log4jUserClient;
58 private static LTTngTCPSessiondClient log4jRootClient;
59
60 private static Thread sessiondThreadJULUser;
61 private static Thread sessiondThreadJULRoot;
62 private static Thread sessiondThreadLog4jUser;
63 private static Thread sessiondThreadLog4jRoot;
64
65 private boolean useJUL = false;
66 private boolean useLog4j = false;
67
68 /* Singleton agent object */
69 private static LTTngAgent curAgent = null;
70
71 /* Indicate if this object has been initialized. */
72 private static boolean initialized = false;
73
74 private static Semaphore registerSem;
75 private final static int semTimeout = 3; /* Seconds */
76
77 /*
78 * Constructor is private. This is a singleton and a reference should be
79 * acquired using getLTTngAgent().
80 */
81 private LTTngAgent() throws IOException {
82 initAgentJULClasses();
83
84 /* Since Log4j is a 3rd party JAR, we need to check if we can load any of its classes */
85 Boolean log4jLoaded = loadLog4jClasses();
86 if (log4jLoaded) {
87 initAgentLog4jClasses();
88 }
89
90 this.registerSem = new Semaphore(0, true);
91 }
92
93 private Boolean loadLog4jClasses() {
17be0b58
CB
94 Class<?> logging;
95
501f6777 96 try {
15c78a9e 97 logging = loadClass("org.apache.log4j.spi.LoggingEvent");
501f6777
CB
98 } catch (ClassNotFoundException e) {
99 /* Log4j classes not found, no need to create the relevant objects */
17be0b58
CB
100 return false;
101 }
102
103 /*
104 * Detect capabilities of the log4j library. We only
105 * support log4j >= 1.2.15. The getTimeStamp() method
106 * was introduced in log4j 1.2.15, so verify that it
107 * is available.
108 *
109 * We can't rely on the getPackage().getImplementationVersion()
110 * call that would retrieves information from the manifest file
111 * found in the JAR since the manifest file shipped
112 * from upstream is known to be broken in several
113 * versions of the library.
114 *
115 * More info:
116 * https://issues.apache.org/bugzilla/show_bug.cgi?id=44370
117 */
118
119 try {
120 logging.getDeclaredMethod("getTimeStamp");
121 } catch (NoSuchMethodException e) {
8b067666 122 System.err.println("Warning: The loaded log4j library is too old. Log4j tracing with LTTng will be disabled.");
17be0b58
CB
123 return false;
124 } catch (NullPointerException e) {
125 /* Should never happen */
126 return false;
127 } catch (SecurityException e) {
128 return false;
501f6777
CB
129 }
130
17be0b58 131 return true;
501f6777
CB
132 }
133
15c78a9e
JG
134 private Class<?> loadClass(String className) throws ClassNotFoundException {
135 ClassLoader loader;
136 Class<?> loadedClass;
137
138 try {
139 /* Try to load class using the current thread's context class loader */
140 loader = Thread.currentThread().getContextClassLoader();
141 loadedClass = loader.loadClass(className);
142 } catch (ClassNotFoundException e) {
143 /* Loading failed, try using the system class loader */
144 loader = ClassLoader.getSystemClassLoader();
145 loadedClass = loader.loadClass(className);
146 }
147
148 return loadedClass;
149 }
150
501f6777
CB
151 private void initAgentJULClasses() {
152 try {
15c78a9e 153 Class<?> lttngJUL = loadClass("org.lttng.ust.agent.jul.LTTngJUL");
501f6777
CB
154 this.julUser = (LogFramework)lttngJUL.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(false);
155 this.julRoot = (LogFramework)lttngJUL.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(true);
156 this.useJUL = true;
157 } catch (ClassNotFoundException e) {
158 /* LTTng JUL classes not found, no need to create the relevant objects */
159 this.useJUL = false;
160 } catch (InstantiationException e) {
161 this.useJUL = false;
162 } catch (NoSuchMethodException e) {
163 this.useJUL = false;
164 } catch (IllegalAccessException e) {
165 this.useJUL = false;
166 } catch (InvocationTargetException e) {
167 this.useJUL = false;
168 }
169 }
170
171 private void initAgentLog4jClasses() {
172 try {
15c78a9e 173 Class<?> lttngLog4j = loadClass("org.lttng.ust.agent.log4j.LTTngLog4j");
501f6777
CB
174 this.log4jUser = (LogFramework)lttngLog4j.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(false);
175 this.log4jRoot = (LogFramework)lttngLog4j.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(true);
176 this.useLog4j = true;
177 } catch (ClassNotFoundException e) {
178 /* LTTng Log4j classes not found, no need to create the relevant objects */
179 this.useLog4j = false;
180 } catch (InstantiationException e) {
181 this.useLog4j = false;
182 } catch (NoSuchMethodException e) {
183 this.useLog4j = false;
184 } catch (IllegalAccessException e) {
185 this.useLog4j = false;
186 } catch (InvocationTargetException e) {
187 this.useLog4j = false;
188 }
189 }
190
191 /*
192 * Public getter to acquire a reference to this singleton object.
193 */
194 public static synchronized LTTngAgent getLTTngAgent() throws IOException {
195 if (curAgent == null) {
196 curAgent = new LTTngAgent();
197 curAgent.init();
198 }
199
200 return curAgent;
201 }
202
203 private synchronized void init() throws SecurityException, IOException {
204 if (this.initialized) {
205 return;
206 }
207
208 Integer numJULThreads = 0;
209 Integer numLog4jThreads = 0;
210
211 if (this.useJUL) {
212 numJULThreads = initJULClientThreads();
213 }
214
215 if (this.useLog4j) {
216 numLog4jThreads = initLog4jClientThreads();
217 }
218
219 Integer numThreads = numJULThreads + numLog4jThreads;
220
221 /* Wait for each registration to end. */
222 try {
223 this.registerSem.tryAcquire(numThreads,
224 semTimeout,
225 TimeUnit.SECONDS);
226 } catch (InterruptedException e) {
227 e.printStackTrace();
228 }
229
230 this.initialized = true;
231 }
232
233 private synchronized Integer initJULClientThreads() {
234 Integer numThreads = 2;
235
236 /* Handle user session daemon if any. */
237 this.julUserClient = new LTTngTCPSessiondClient(Domain.JUL,
238 this.julUser,
239 this.registerSem);
240
241 String userThreadName = "LTTng UST agent JUL user thread";
242 this.sessiondThreadJULUser = new Thread(julUserClient, userThreadName);
243 this.sessiondThreadJULUser.setDaemon(true);
244 this.sessiondThreadJULUser.start();
245
246 /* Handle root session daemon. */
247 this.julRootClient = new LTTngTCPSessiondClient(Domain.JUL,
248 this.julRoot,
249 this.registerSem);
250
251 String rootThreadName = "LTTng UST agent JUL root thread";
252 this.sessiondThreadJULRoot = new Thread(julRootClient, rootThreadName);
253 this.sessiondThreadJULRoot.setDaemon(true);
254 this.sessiondThreadJULRoot.start();
255
256 return numThreads;
257 }
258
259 private synchronized Integer initLog4jClientThreads() {
260 Integer numThreads = 2;
261
262 this.log4jUserClient = new LTTngTCPSessiondClient(Domain.LOG4J,
263 this.log4jUser,
264 this.registerSem);
265
266 String userThreadName = "LTTng UST agent Log4j user thread";
267 this.sessiondThreadLog4jUser = new Thread(log4jUserClient, userThreadName);
268 this.sessiondThreadLog4jUser.setDaemon(true);
269 this.sessiondThreadLog4jUser.start();
270
271 this.log4jRootClient = new LTTngTCPSessiondClient(Domain.LOG4J,
272 this.log4jRoot,
273 this.registerSem);
274
275 String rootThreadName = "LTTng UST agent Log4j root thread";
276 this.sessiondThreadLog4jRoot = new Thread(log4jRootClient,rootThreadName);
277 this.sessiondThreadLog4jRoot.setDaemon(true);
278 this.sessiondThreadLog4jRoot.start();
279
280 return numThreads;
281 }
282
283
284 public void dispose() throws IOException {
285 if (this.useJUL) {
286 this.julUserClient.destroy();
287 this.julRootClient.destroy();
288 this.julUser.reset();
289 this.julRoot.reset();
290 }
291
292 if (this.useLog4j) {
293 this.log4jUserClient.destroy();
294 this.log4jRootClient.destroy();
295 this.log4jUser.reset();
296 this.log4jRoot.reset();
297 }
298
299 try {
300 if (this.useJUL) {
301 this.sessiondThreadJULUser.join();
302 this.sessiondThreadJULRoot.join();
303 }
304
305 if (this.useLog4j) {
306 this.sessiondThreadLog4jUser.join();
307 this.sessiondThreadLog4jRoot.join();
308 }
309
310 } catch (InterruptedException e) {
311 e.printStackTrace();
312 }
313 }
314}
This page took 0.034984 seconds and 4 git commands to generate.