1 // ========================================================================
2 // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // All rights reserved. This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v1.0
6 // and Apache License v2.0 which accompanies this distribution.
7 // The Eclipse Public License is available at
8 // http://www.eclipse.org/legal/epl-v10.html
9 // The Apache License v2.0 is available at
10 // http://www.opensource.org/licenses/apache2.0.php
11 // You may elect to redistribute this code under either of these licenses.
12 // ========================================================================
13
14 package org.eclipse.jetty.util.log;
15
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.lang.reflect.Method;
19 import java.net.URL;
20 import java.security.AccessController;
21 import java.security.PrivilegedAction;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Enumeration;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Properties;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap;
30
31 import org.eclipse.jetty.util.IO;
32 import org.eclipse.jetty.util.Loader;
33
34 /**
35 * Logging.
36 * This class provides a static logging interface. If an instance of the
37 * org.slf4j.Logger class is found on the classpath, the static log methods
38 * are directed to a slf4j logger for "org.eclipse.log". Otherwise the logs
39 * are directed to stderr.
40 * <p>
41 * The "org.eclipse.jetty.util.log.class" system property can be used
42 * to select a specific logging implementation.
43 * <p>
44 * If the system property org.eclipse.jetty.util.log.IGNORED is set,
45 * then ignored exceptions are logged in detail.
46 *
47 * @see StdErrLog
48 * @see Slf4jLog
49 */
50 public class Log
51 {
52 public final static String EXCEPTION= "EXCEPTION ";
53 public final static String IGNORED= "IGNORED ";
54
55 /**
56 * Logging Configuration Properties
57 */
58 protected static Properties __props;
59 /**
60 * The {@link Logger} implementation class name
61 */
62 public static String __logClass;
63 /**
64 * Legacy flag indicating if {@link Log#ignore(Throwable)} methods produce any output in the {@link Logger}s
65 */
66 public static boolean __ignored;
67
68 /**
69 * Hold loggers only.
70 */
71 private final static ConcurrentMap<String, Logger> __loggers = new ConcurrentHashMap<String, Logger>();
72
73
74 static
75 {
76 /* Instantiate a default configuration properties (empty)
77 */
78 __props = new Properties();
79
80 AccessController.doPrivileged(new PrivilegedAction<Object>()
81 {
82 public Object run()
83 {
84 /* First see if the jetty-logging.properties object exists in the classpath.
85 * This is an optional feature used by embedded mode use, and test cases to allow for early
86 * configuration of the Log class in situations where access to the System.properties are
87 * either too late or just impossible.
88 */
89 URL testProps = Log.class.getClassLoader().getResource("jetty-logging.properties");
90 if (testProps != null)
91 {
92 InputStream in = null;
93 try
94 {
95 in = testProps.openStream();
96 __props.load(in);
97 }
98 catch (IOException e)
99 {
100 System.err.println("Unable to load " + testProps);
101 e.printStackTrace(System.err);
102 }
103 finally
104 {
105 IO.close(in);
106 }
107 }
108
109 /* Now load the System.properties as-is into the __props, these values will override
110 * any key conflicts in __props.
111 */
112 @SuppressWarnings("unchecked")
113 Enumeration<String> systemKeyEnum = (Enumeration<String>)System.getProperties().propertyNames();
114 while (systemKeyEnum.hasMoreElements())
115 {
116 String key = systemKeyEnum.nextElement();
117 String val = System.getProperty(key);
118 //protect against application code insertion of non-String values (returned as null)
119 if (val != null)
120 __props.setProperty(key,val);
121 }
122
123 /* Now use the configuration properties to configure the Log statics
124 */
125 __logClass = __props.getProperty("org.eclipse.jetty.util.log.class","org.eclipse.jetty.util.log.Slf4jLog");
126 __ignored = Boolean.parseBoolean(__props.getProperty("org.eclipse.jetty.util.log.IGNORED","false"));
127 return null;
128 }
129 });
130 }
131
132 private static Logger LOG;
133 private static boolean __initialized;
134
135 public static boolean initialized()
136 {
137 if (LOG != null)
138 {
139 return true;
140 }
141
142 synchronized (Log.class)
143 {
144 if (__initialized)
145 {
146 return LOG != null;
147 }
148 __initialized = true;
149 }
150
151 try
152 {
153 Class<?> log_class = Loader.loadClass(Log.class, __logClass);
154 if (LOG == null || !LOG.getClass().equals(log_class))
155 {
156 LOG = (Logger)log_class.newInstance();
157 LOG.debug("Logging to {} via {}", LOG, log_class.getName());
158 }
159 }
160 catch(Throwable e)
161 {
162 // Unable to load specified Logger implementation, default to standard logging.
163 initStandardLogging(e);
164 }
165
166 return LOG != null;
167 }
168
169 private static void initStandardLogging(Throwable e)
170 {
171 Class<?> log_class;
172 if(e != null && __ignored)
173 {
174 e.printStackTrace();
175 }
176
177 if (LOG == null)
178 {
179 log_class = StdErrLog.class;
180 LOG = new StdErrLog();
181 LOG.debug("Logging to {} via {}", LOG, log_class.getName());
182 }
183 }
184
185 public static void setLog(Logger log)
186 {
187 Log.LOG = log;
188 }
189
190 /**
191 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
192 */
193 @Deprecated
194 public static Logger getLog()
195 {
196 initialized();
197 return LOG;
198 }
199
200 /**
201 * Get the root logger.
202 * @return the root logger
203 */
204 public static Logger getRootLogger() {
205 initialized();
206 return LOG;
207 }
208
209 static boolean isIgnored()
210 {
211 return __ignored;
212 }
213
214 /**
215 * Set Log to parent Logger.
216 * <p>
217 * If there is a different Log class available from a parent classloader,
218 * call {@link #getLogger(String)} on it and construct a {@link LoggerLog} instance
219 * as this Log's Logger, so that logging is delegated to the parent Log.
220 * <p>
221 * This should be used if a webapp is using Log, but wishes the logging to be
222 * directed to the containers log.
223 * <p>
224 * If there is not parent Log, then this call is equivalent to<pre>
225 * Log.setLog(Log.getLogger(name));
226 * </pre>
227 * @param name Logger name
228 */
229 public static void setLogToParent(String name)
230 {
231 ClassLoader loader = Log.class.getClassLoader();
232 if (loader.getParent()!=null)
233 {
234 try
235 {
236 Class<?> uberlog = loader.getParent().loadClass("org.eclipse.jetty.util.log.Log");
237 Method getLogger = uberlog.getMethod("getLogger", new Class[]{String.class});
238 Object logger = getLogger.invoke(null,name);
239 setLog(new LoggerLog(logger));
240 }
241 catch (Exception e)
242 {
243 e.printStackTrace();
244 }
245 }
246 else
247 {
248 setLog(getLogger(name));
249 }
250 }
251
252 /**
253 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
254 */
255 @Deprecated
256 public static void debug(Throwable th)
257 {
258 if (!isDebugEnabled())
259 return;
260 LOG.debug(EXCEPTION, th);
261 }
262
263 /**
264 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
265 */
266 @Deprecated
267 public static void debug(String msg)
268 {
269 if (!initialized())
270 return;
271 LOG.debug(msg);
272 }
273
274 /**
275 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
276 */
277 @Deprecated
278 public static void debug(String msg, Object arg)
279 {
280 if (!initialized())
281 return;
282 LOG.debug(msg, arg);
283 }
284
285 /**
286 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
287 */
288 @Deprecated
289 public static void debug(String msg, Object arg0, Object arg1)
290 {
291 if (!initialized())
292 return;
293 LOG.debug(msg, arg0, arg1);
294 }
295
296 /**
297 * Ignore an exception unless trace is enabled.
298 * This works around the problem that log4j does not support the trace level.
299 * @param thrown the Throwable to ignore
300 */
301 /**
302 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
303 */
304 @Deprecated
305 public static void ignore(Throwable thrown)
306 {
307 if (!initialized())
308 return;
309 LOG.ignore(thrown);
310 }
311
312 /**
313 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
314 */
315 @Deprecated
316 public static void info(String msg)
317 {
318 if (!initialized())
319 return;
320 LOG.info(msg);
321 }
322
323 /**
324 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
325 */
326 @Deprecated
327 public static void info(String msg, Object arg)
328 {
329 if (!initialized())
330 return;
331 LOG.info(msg, arg);
332 }
333
334 /**
335 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
336 */
337 @Deprecated
338 public static void info(String msg, Object arg0, Object arg1)
339 {
340 if (!initialized())
341 return;
342 LOG.info(msg, arg0, arg1);
343 }
344
345 /**
346 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
347 */
348 @Deprecated
349 public static boolean isDebugEnabled()
350 {
351 if (!initialized())
352 return false;
353 return LOG.isDebugEnabled();
354 }
355
356 /**
357 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
358 */
359 @Deprecated
360 public static void warn(String msg)
361 {
362 if (!initialized())
363 return;
364 LOG.warn(msg);
365 }
366
367 /**
368 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
369 */
370 @Deprecated
371 public static void warn(String msg, Object arg)
372 {
373 if (!initialized())
374 return;
375 LOG.warn(msg, arg);
376 }
377
378 /**
379 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
380 */
381 @Deprecated
382 public static void warn(String msg, Object arg0, Object arg1)
383 {
384 if (!initialized())
385 return;
386 LOG.warn(msg, arg0, arg1);
387 }
388
389 /**
390 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
391 */
392 @Deprecated
393 public static void warn(String msg, Throwable th)
394 {
395 if (!initialized())
396 return;
397 LOG.warn(msg, th);
398 }
399
400 /**
401 * @deprecated anonymous logging is deprecated, use a named {@link Logger} obtained from {@link #getLogger(String)}
402 */
403 @Deprecated
404 public static void warn(Throwable th)
405 {
406 if (!initialized())
407 return;
408 LOG.warn(EXCEPTION, th);
409 }
410
411 /**
412 * Obtain a named Logger based on the fully qualified class name.
413 *
414 * @param clazz
415 * the class to base the Logger name off of
416 * @return the Logger with the given name
417 */
418 public static Logger getLogger(Class<?> clazz)
419 {
420 return getLogger(clazz.getName());
421 }
422
423 /**
424 * Obtain a named Logger or the default Logger if null is passed.
425 * @param name the Logger name
426 * @return the Logger with the given name
427 */
428 public static Logger getLogger(String name)
429 {
430 if (!initialized())
431 return null;
432
433 if(name==null)
434 return LOG;
435
436 Logger logger = __loggers.get(name);
437 if(logger==null)
438 logger = LOG.getLogger(name);
439
440 return logger;
441 }
442
443 static ConcurrentMap<String, Logger> getMutableLoggers()
444 {
445 return __loggers;
446 }
447
448 /**
449 * Get a map of all configured {@link Logger} instances.
450 *
451 * @return a map of all configured {@link Logger} instances
452 */
453 public static Map<String, Logger> getLoggers()
454 {
455 return Collections.unmodifiableMap(__loggers);
456 }
457 }