View Javadoc

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 }