View Javadoc

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