47b45197ad8c1584594b01c69c24d700130972bf
[lttng-ust.git] / liblttng-ust-java-agent / java / 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 org.lttng.ust.agent.jul.LTTngJUL;
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.BufferedReader;
25 import java.io.FileReader;
26 import java.util.concurrent.Semaphore;
27 import java.util.concurrent.TimeUnit;
28 import java.util.Enumeration;
29 import java.lang.reflect.InvocationTargetException;
30
31 import java.util.logging.Logger;
32 import java.util.logging.SimpleFormatter;
33
34 public 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() {
94 Class<?> logging;
95
96 try {
97 logging = loadClass("org.apache.log4j.spi.LoggingEvent");
98 } catch (ClassNotFoundException e) {
99 /* Log4j classes not found, no need to create the relevant objects */
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) {
122 return false;
123 } catch (NullPointerException e) {
124 /* Should never happen */
125 return false;
126 } catch (SecurityException e) {
127 return false;
128 }
129
130 return true;
131 }
132
133 private Class<?> loadClass(String className) throws ClassNotFoundException {
134 ClassLoader loader;
135 Class<?> loadedClass;
136
137 try {
138 /* Try to load class using the current thread's context class loader */
139 loader = Thread.currentThread().getContextClassLoader();
140 loadedClass = loader.loadClass(className);
141 } catch (ClassNotFoundException e) {
142 /* Loading failed, try using the system class loader */
143 loader = ClassLoader.getSystemClassLoader();
144 loadedClass = loader.loadClass(className);
145 }
146
147 return loadedClass;
148 }
149
150 private void initAgentJULClasses() {
151 try {
152 Class<?> lttngJUL = loadClass("org.lttng.ust.agent.jul.LTTngJUL");
153 this.julUser = (LogFramework)lttngJUL.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(false);
154 this.julRoot = (LogFramework)lttngJUL.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(true);
155 this.useJUL = true;
156 } catch (ClassNotFoundException e) {
157 /* LTTng JUL classes not found, no need to create the relevant objects */
158 this.useJUL = false;
159 } catch (InstantiationException e) {
160 this.useJUL = false;
161 } catch (NoSuchMethodException e) {
162 this.useJUL = false;
163 } catch (IllegalAccessException e) {
164 this.useJUL = false;
165 } catch (InvocationTargetException e) {
166 this.useJUL = false;
167 }
168 }
169
170 private void initAgentLog4jClasses() {
171 try {
172 Class<?> lttngLog4j = loadClass("org.lttng.ust.agent.log4j.LTTngLog4j");
173 this.log4jUser = (LogFramework)lttngLog4j.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(false);
174 this.log4jRoot = (LogFramework)lttngLog4j.getDeclaredConstructor(new Class[] {Boolean.class}).newInstance(true);
175 this.useLog4j = true;
176 } catch (ClassNotFoundException e) {
177 /* LTTng Log4j classes not found, no need to create the relevant objects */
178 this.useLog4j = false;
179 } catch (InstantiationException e) {
180 this.useLog4j = false;
181 } catch (NoSuchMethodException e) {
182 this.useLog4j = false;
183 } catch (IllegalAccessException e) {
184 this.useLog4j = false;
185 } catch (InvocationTargetException e) {
186 this.useLog4j = false;
187 }
188 }
189
190 /*
191 * Public getter to acquire a reference to this singleton object.
192 */
193 public static synchronized LTTngAgent getLTTngAgent() throws IOException {
194 if (curAgent == null) {
195 curAgent = new LTTngAgent();
196 curAgent.init();
197 }
198
199 return curAgent;
200 }
201
202 private synchronized void init() throws SecurityException, IOException {
203 if (this.initialized) {
204 return;
205 }
206
207 Integer numJULThreads = 0;
208 Integer numLog4jThreads = 0;
209
210 if (this.useJUL) {
211 numJULThreads = initJULClientThreads();
212 }
213
214 if (this.useLog4j) {
215 numLog4jThreads = initLog4jClientThreads();
216 }
217
218 Integer numThreads = numJULThreads + numLog4jThreads;
219
220 /* Wait for each registration to end. */
221 try {
222 this.registerSem.tryAcquire(numThreads,
223 semTimeout,
224 TimeUnit.SECONDS);
225 } catch (InterruptedException e) {
226 e.printStackTrace();
227 }
228
229 this.initialized = true;
230 }
231
232 private synchronized Integer initJULClientThreads() {
233 Integer numThreads = 2;
234
235 /* Handle user session daemon if any. */
236 this.julUserClient = new LTTngTCPSessiondClient(Domain.JUL,
237 this.julUser,
238 this.registerSem);
239
240 String userThreadName = "LTTng UST agent JUL user thread";
241 this.sessiondThreadJULUser = new Thread(julUserClient, userThreadName);
242 this.sessiondThreadJULUser.setDaemon(true);
243 this.sessiondThreadJULUser.start();
244
245 /* Handle root session daemon. */
246 this.julRootClient = new LTTngTCPSessiondClient(Domain.JUL,
247 this.julRoot,
248 this.registerSem);
249
250 String rootThreadName = "LTTng UST agent JUL root thread";
251 this.sessiondThreadJULRoot = new Thread(julRootClient, rootThreadName);
252 this.sessiondThreadJULRoot.setDaemon(true);
253 this.sessiondThreadJULRoot.start();
254
255 return numThreads;
256 }
257
258 private synchronized Integer initLog4jClientThreads() {
259 Integer numThreads = 2;
260
261 this.log4jUserClient = new LTTngTCPSessiondClient(Domain.LOG4J,
262 this.log4jUser,
263 this.registerSem);
264
265 String userThreadName = "LTTng UST agent Log4j user thread";
266 this.sessiondThreadLog4jUser = new Thread(log4jUserClient, userThreadName);
267 this.sessiondThreadLog4jUser.setDaemon(true);
268 this.sessiondThreadLog4jUser.start();
269
270 this.log4jRootClient = new LTTngTCPSessiondClient(Domain.LOG4J,
271 this.log4jRoot,
272 this.registerSem);
273
274 String rootThreadName = "LTTng UST agent Log4j root thread";
275 this.sessiondThreadLog4jRoot = new Thread(log4jRootClient,rootThreadName);
276 this.sessiondThreadLog4jRoot.setDaemon(true);
277 this.sessiondThreadLog4jRoot.start();
278
279 return numThreads;
280 }
281
282
283 public void dispose() throws IOException {
284 if (this.useJUL) {
285 this.julUserClient.destroy();
286 this.julRootClient.destroy();
287 this.julUser.reset();
288 this.julRoot.reset();
289 }
290
291 if (this.useLog4j) {
292 this.log4jUserClient.destroy();
293 this.log4jRootClient.destroy();
294 this.log4jUser.reset();
295 this.log4jRoot.reset();
296 }
297
298 try {
299 if (this.useJUL) {
300 this.sessiondThreadJULUser.join();
301 this.sessiondThreadJULRoot.join();
302 }
303
304 if (this.useLog4j) {
305 this.sessiondThreadLog4jUser.join();
306 this.sessiondThreadLog4jRoot.join();
307 }
308
309 } catch (InterruptedException e) {
310 e.printStackTrace();
311 }
312 }
313 }
This page took 0.034735 seconds and 3 git commands to generate.