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
;
25 public class LTTngAgent
{
32 private Domain(int value
) {
41 private static final int SEM_TIMEOUT
= 3; /* Seconds */
43 private static LogFramework julUser
;
44 private static LogFramework julRoot
;
45 private static LogFramework log4jUser
;
46 private static LogFramework log4jRoot
;
48 /* Sessiond clients */
49 private static LTTngTCPSessiondClient julUserClient
;
50 private static LTTngTCPSessiondClient julRootClient
;
51 private static LTTngTCPSessiondClient log4jUserClient
;
52 private static LTTngTCPSessiondClient log4jRootClient
;
54 private static Thread sessiondThreadJULUser
;
55 private static Thread sessiondThreadJULRoot
;
56 private static Thread sessiondThreadLog4jUser
;
57 private static Thread sessiondThreadLog4jRoot
;
59 private boolean useJUL
= false;
60 private boolean useLog4j
= false;
62 /* Singleton agent object */
63 private static LTTngAgent curAgent
= null;
65 /* Indicate if this object has been initialized. */
66 private static boolean initialized
= false;
68 private static Semaphore registerSem
;
71 * Constructor is private. This is a singleton and a reference should be
72 * acquired using getLTTngAgent().
74 private LTTngAgent() {
75 initAgentJULClasses();
77 /* Since Log4j is a 3rd party JAR, we need to check if we can load any of its classes */
78 Boolean log4jLoaded
= loadLog4jClasses();
80 initAgentLog4jClasses();
83 registerSem
= new Semaphore(0, true);
86 private static Boolean
loadLog4jClasses() {
90 logging
= loadClass("org.apache.log4j.spi.LoggingEvent");
91 } catch (ClassNotFoundException e
) {
92 /* Log4j classes not found, no need to create the relevant objects */
97 * Detect capabilities of the log4j library. We only
98 * support log4j >= 1.2.15. The getTimeStamp() method
99 * was introduced in log4j 1.2.15, so verify that it
102 * We can't rely on the getPackage().getImplementationVersion()
103 * call that would retrieves information from the manifest file
104 * found in the JAR since the manifest file shipped
105 * from upstream is known to be broken in several
106 * versions of the library.
109 * https://issues.apache.org/bugzilla/show_bug.cgi?id=44370
113 logging
.getDeclaredMethod("getTimeStamp");
114 } catch (NoSuchMethodException e
) {
115 System
.err
.println("Warning: The loaded log4j library is too old. Log4j tracing with LTTng will be disabled.");
117 } catch (NullPointerException e
) {
118 /* Should never happen */
120 } catch (SecurityException e
) {
127 private static Class
<?
> loadClass(String className
) throws ClassNotFoundException
{
129 Class
<?
> loadedClass
;
132 /* Try to load class using the current thread's context class loader */
133 loader
= Thread
.currentThread().getContextClassLoader();
134 loadedClass
= loader
.loadClass(className
);
135 } catch (ClassNotFoundException e
) {
136 /* Loading failed, try using the system class loader */
137 loader
= ClassLoader
.getSystemClassLoader();
138 loadedClass
= loader
.loadClass(className
);
144 private void initAgentJULClasses() {
146 Class
<?
> lttngJUL
= loadClass("org.lttng.ust.agent.jul.LTTngJUL");
147 julUser
= (LogFramework
) lttngJUL
.getDeclaredConstructor(new Class
[] { Boolean
.class }).newInstance(false);
148 julRoot
= (LogFramework
) lttngJUL
.getDeclaredConstructor(new Class
[] { Boolean
.class }).newInstance(true);
150 } catch (ClassNotFoundException e
) {
151 /* LTTng JUL classes not found, no need to create the relevant objects */
153 } catch (InstantiationException e
) {
155 } catch (NoSuchMethodException e
) {
157 } catch (IllegalAccessException e
) {
159 } catch (InvocationTargetException e
) {
164 private void initAgentLog4jClasses() {
166 Class
<?
> lttngLog4j
= loadClass("org.lttng.ust.agent.log4j.LTTngLog4j");
167 log4jUser
= (LogFramework
)lttngLog4j
.getDeclaredConstructor(new Class
[] {Boolean
.class}).newInstance(false);
168 log4jRoot
= (LogFramework
)lttngLog4j
.getDeclaredConstructor(new Class
[] {Boolean
.class}).newInstance(true);
169 this.useLog4j
= true;
170 } catch (ClassNotFoundException e
) {
171 /* LTTng Log4j classes not found, no need to create the relevant objects */
172 this.useLog4j
= false;
173 } catch (InstantiationException e
) {
174 this.useLog4j
= false;
175 } catch (NoSuchMethodException e
) {
176 this.useLog4j
= false;
177 } catch (IllegalAccessException e
) {
178 this.useLog4j
= false;
179 } catch (InvocationTargetException e
) {
180 this.useLog4j
= false;
185 * Public getter to acquire a reference to this singleton object.
187 public static synchronized LTTngAgent
getLTTngAgent() throws IOException
{
188 if (curAgent
== null) {
189 curAgent
= new LTTngAgent();
196 private synchronized void init() throws SecurityException
{
201 Integer numJULThreads
= 0;
202 Integer numLog4jThreads
= 0;
205 numJULThreads
= initJULClientThreads();
209 numLog4jThreads
= initLog4jClientThreads();
212 Integer numThreads
= numJULThreads
+ numLog4jThreads
;
214 /* Wait for each registration to end. */
216 registerSem
.tryAcquire(numThreads
,
219 } catch (InterruptedException e
) {
226 private synchronized static Integer
initJULClientThreads() {
227 Integer numThreads
= 2;
229 /* Handle user session daemon if any. */
230 julUserClient
= new LTTngTCPSessiondClient(Domain
.JUL
,
234 String userThreadName
= "LTTng UST agent JUL user thread";
235 sessiondThreadJULUser
= new Thread(julUserClient
, userThreadName
);
236 sessiondThreadJULUser
.setDaemon(true);
237 sessiondThreadJULUser
.start();
239 /* Handle root session daemon. */
240 julRootClient
= new LTTngTCPSessiondClient(Domain
.JUL
,
244 String rootThreadName
= "LTTng UST agent JUL root thread";
245 sessiondThreadJULRoot
= new Thread(julRootClient
, rootThreadName
);
246 sessiondThreadJULRoot
.setDaemon(true);
247 sessiondThreadJULRoot
.start();
252 private synchronized static Integer
initLog4jClientThreads() {
253 Integer numThreads
= 2;
255 log4jUserClient
= new LTTngTCPSessiondClient(Domain
.LOG4J
,
259 String userThreadName
= "LTTng UST agent Log4j user thread";
260 sessiondThreadLog4jUser
= new Thread(log4jUserClient
, userThreadName
);
261 sessiondThreadLog4jUser
.setDaemon(true);
262 sessiondThreadLog4jUser
.start();
264 log4jRootClient
= new LTTngTCPSessiondClient(Domain
.LOG4J
,
268 String rootThreadName
= "LTTng UST agent Log4j root thread";
269 sessiondThreadLog4jRoot
= new Thread(log4jRootClient
,rootThreadName
);
270 sessiondThreadLog4jRoot
.setDaemon(true);
271 sessiondThreadLog4jRoot
.start();
277 public void dispose() throws IOException
{
279 julUserClient
.destroy();
280 julRootClient
.destroy();
286 log4jUserClient
.destroy();
287 log4jRootClient
.destroy();
294 sessiondThreadJULUser
.join();
295 sessiondThreadJULRoot
.join();
299 sessiondThreadLog4jUser
.join();
300 sessiondThreadLog4jRoot
.join();
303 } catch (InterruptedException e
) {