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
.io
.IOException
;
21 import java
.lang
.reflect
.InvocationTargetException
;
22 import java
.util
.concurrent
.Semaphore
;
23 import java
.util
.concurrent
.TimeUnit
;
26 * The central agent managing the JUL and Log4j handlers.
28 * @author David Goulet
30 public class LTTngAgent
{
37 private Domain(int value
) {
46 private static final int SEM_TIMEOUT
= 3; /* Seconds */
48 private static LogFramework julUser
;
49 private static LogFramework julRoot
;
50 private static LogFramework log4jUser
;
51 private static LogFramework log4jRoot
;
53 /* Sessiond clients */
54 private static LTTngTCPSessiondClient julUserClient
;
55 private static LTTngTCPSessiondClient julRootClient
;
56 private static LTTngTCPSessiondClient log4jUserClient
;
57 private static LTTngTCPSessiondClient log4jRootClient
;
59 private static Thread sessiondThreadJULUser
;
60 private static Thread sessiondThreadJULRoot
;
61 private static Thread sessiondThreadLog4jUser
;
62 private static Thread sessiondThreadLog4jRoot
;
64 private boolean useJUL
= false;
65 private boolean useLog4j
= false;
67 /* Singleton agent object */
68 private static LTTngAgent curAgent
= null;
70 /* Indicate if this object has been initialized. */
71 private static boolean initialized
= false;
73 private static Semaphore registerSem
;
76 * Constructor is private. This is a singleton and a reference should be
77 * acquired using getLTTngAgent().
79 private LTTngAgent() {
80 initAgentJULClasses();
82 /* Since Log4j is a 3rd party JAR, we need to check if we can load any of its classes */
83 Boolean log4jLoaded
= loadLog4jClasses();
85 initAgentLog4jClasses();
88 registerSem
= new Semaphore(0, true);
91 private static Boolean
loadLog4jClasses() {
95 logging
= loadClass("org.apache.log4j.spi.LoggingEvent");
96 } catch (ClassNotFoundException e
) {
97 /* Log4j classes not found, no need to create the relevant objects */
102 * Detect capabilities of the log4j library. We only
103 * support log4j >= 1.2.15. The getTimeStamp() method
104 * was introduced in log4j 1.2.15, so verify that it
107 * We can't rely on the getPackage().getImplementationVersion()
108 * call that would retrieves information from the manifest file
109 * found in the JAR since the manifest file shipped
110 * from upstream is known to be broken in several
111 * versions of the library.
114 * https://issues.apache.org/bugzilla/show_bug.cgi?id=44370
118 logging
.getDeclaredMethod("getTimeStamp");
119 } catch (NoSuchMethodException e
) {
120 System
.err
.println("Warning: The loaded log4j library is too old. Log4j tracing with LTTng will be disabled.");
122 } catch (NullPointerException e
) {
123 /* Should never happen */
125 } catch (SecurityException e
) {
132 private static Class
<?
> loadClass(String className
) throws ClassNotFoundException
{
134 Class
<?
> loadedClass
;
137 /* Try to load class using the current thread's context class loader */
138 loader
= Thread
.currentThread().getContextClassLoader();
139 loadedClass
= loader
.loadClass(className
);
140 } catch (ClassNotFoundException e
) {
141 /* Loading failed, try using the system class loader */
142 loader
= ClassLoader
.getSystemClassLoader();
143 loadedClass
= loader
.loadClass(className
);
149 private void initAgentJULClasses() {
151 Class
<?
> lttngJUL
= loadClass("org.lttng.ust.agent.jul.LTTngJUL");
152 julUser
= (LogFramework
) lttngJUL
.getDeclaredConstructor(new Class
[] { Boolean
.class }).newInstance(false);
153 julRoot
= (LogFramework
) lttngJUL
.getDeclaredConstructor(new Class
[] { Boolean
.class }).newInstance(true);
155 } catch (ClassNotFoundException e
) {
156 /* LTTng JUL classes not found, no need to create the relevant objects */
158 } catch (InstantiationException e
) {
160 } catch (NoSuchMethodException e
) {
162 } catch (IllegalAccessException e
) {
164 } catch (InvocationTargetException e
) {
169 private void initAgentLog4jClasses() {
171 Class
<?
> lttngLog4j
= loadClass("org.lttng.ust.agent.log4j.LTTngLog4j");
172 log4jUser
= (LogFramework
)lttngLog4j
.getDeclaredConstructor(new Class
[] {Boolean
.class}).newInstance(false);
173 log4jRoot
= (LogFramework
)lttngLog4j
.getDeclaredConstructor(new Class
[] {Boolean
.class}).newInstance(true);
174 this.useLog4j
= true;
175 } catch (ClassNotFoundException e
) {
176 /* LTTng Log4j classes not found, no need to create the relevant objects */
177 this.useLog4j
= false;
178 } catch (InstantiationException e
) {
179 this.useLog4j
= false;
180 } catch (NoSuchMethodException e
) {
181 this.useLog4j
= false;
182 } catch (IllegalAccessException e
) {
183 this.useLog4j
= false;
184 } catch (InvocationTargetException e
) {
185 this.useLog4j
= false;
190 * Public getter to acquire a reference to this singleton object.
192 * @return The agent instance
193 * @throws IOException
195 public static synchronized LTTngAgent
getLTTngAgent() throws IOException
{
196 if (curAgent
== null) {
197 curAgent
= new LTTngAgent();
204 private synchronized void init() throws SecurityException
{
209 Integer numJULThreads
= 0;
210 Integer numLog4jThreads
= 0;
213 numJULThreads
= initJULClientThreads();
217 numLog4jThreads
= initLog4jClientThreads();
220 Integer numThreads
= numJULThreads
+ numLog4jThreads
;
222 /* Wait for each registration to end. */
224 registerSem
.tryAcquire(numThreads
,
227 } catch (InterruptedException e
) {
234 private synchronized static Integer
initJULClientThreads() {
235 Integer numThreads
= 2;
237 /* Handle user session daemon if any. */
238 julUserClient
= new LTTngTCPSessiondClient(Domain
.JUL
,
242 String userThreadName
= "LTTng UST agent JUL user thread";
243 sessiondThreadJULUser
= new Thread(julUserClient
, userThreadName
);
244 sessiondThreadJULUser
.setDaemon(true);
245 sessiondThreadJULUser
.start();
247 /* Handle root session daemon. */
248 julRootClient
= new LTTngTCPSessiondClient(Domain
.JUL
,
252 String rootThreadName
= "LTTng UST agent JUL root thread";
253 sessiondThreadJULRoot
= new Thread(julRootClient
, rootThreadName
);
254 sessiondThreadJULRoot
.setDaemon(true);
255 sessiondThreadJULRoot
.start();
260 private synchronized static Integer
initLog4jClientThreads() {
261 Integer numThreads
= 2;
263 log4jUserClient
= new LTTngTCPSessiondClient(Domain
.LOG4J
,
267 String userThreadName
= "LTTng UST agent Log4j user thread";
268 sessiondThreadLog4jUser
= new Thread(log4jUserClient
, userThreadName
);
269 sessiondThreadLog4jUser
.setDaemon(true);
270 sessiondThreadLog4jUser
.start();
272 log4jRootClient
= new LTTngTCPSessiondClient(Domain
.LOG4J
,
276 String rootThreadName
= "LTTng UST agent Log4j root thread";
277 sessiondThreadLog4jRoot
= new Thread(log4jRootClient
,rootThreadName
);
278 sessiondThreadLog4jRoot
.setDaemon(true);
279 sessiondThreadLog4jRoot
.start();
285 * Dispose the agent. Applications should call this once they are done
288 public void dispose() {
290 julUserClient
.destroy();
291 julRootClient
.destroy();
297 log4jUserClient
.destroy();
298 log4jRootClient
.destroy();
305 sessiondThreadJULUser
.join();
306 sessiondThreadJULRoot
.join();
310 sessiondThreadLog4jUser
.join();
311 sessiondThreadLog4jRoot
.join();
314 } catch (InterruptedException e
) {