]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/log/Log.java
Importing upstream Jetty jetty-9.2.1.v20140609
[gigi.git] / lib / jetty / org / eclipse / jetty / util / log / Log.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2014 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.management.ManagementFactory;
24 import java.lang.reflect.Method;
25 import java.net.URL;
26 import java.security.AccessController;
27 import java.security.PrivilegedAction;
28 import java.util.Collections;
29 import java.util.Enumeration;
30 import java.util.Locale;
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.Loader;
37 import org.eclipse.jetty.util.annotation.ManagedAttribute;
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 final Properties __props;
64     /**
65      * The {@link Logger} implementation class name
66      */
67     public static String __logClass;
68     /**
69      * Legacy flag indicating if {@link Logger#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<>();
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                 loadProperties("jetty-logging.properties",__props);
95
96                 /*
97                  * Next see if an OS specific jetty-logging.properties object exists in the classpath. 
98                  * This really for setting up test specific logging behavior based on OS.
99                  */
100                 String osName = System.getProperty("os.name");
101                 // NOTE: cannot use jetty-util's StringUtil as that initializes logging itself.
102                 if (osName != null && osName.length() > 0)
103                 {
104                     osName = osName.toLowerCase(Locale.ENGLISH).replace(' ','-');
105                     loadProperties("jetty-logging-" + osName + ".properties",__props);
106                 }
107
108                 /* Now load the System.properties as-is into the __props, these values will override
109                  * any key conflicts in __props.
110                  */
111                 @SuppressWarnings("unchecked")
112                 Enumeration<String> systemKeyEnum = (Enumeration<String>)System.getProperties().propertyNames();
113                 while (systemKeyEnum.hasMoreElements())
114                 {
115                     String key = systemKeyEnum.nextElement();
116                     String val = System.getProperty(key);
117                     // protect against application code insertion of non-String values (returned as null)
118                     if (val != null)
119                     {
120                         __props.setProperty(key,val);
121                     }
122                 }
123
124                 /* Now use the configuration properties to configure the Log statics
125                  */
126                 __logClass = __props.getProperty("org.eclipse.jetty.util.log.class","org.eclipse.jetty.util.log.Slf4jLog");
127                 __ignored = Boolean.parseBoolean(__props.getProperty("org.eclipse.jetty.util.log.IGNORED","false"));
128                 return null;
129             }
130         });
131     }
132     
133     private static void loadProperties(String resourceName, Properties props)
134     {
135         URL testProps = Loader.getResource(Log.class,resourceName);
136         if (testProps != null)
137         {
138             try (InputStream in = testProps.openStream())
139             {
140                 Properties p = new Properties();
141                 p.load(in);
142                 for (Object key : p.keySet())
143                 {
144                     Object value = p.get(key);
145                     if (value != null)
146                     {
147                         props.put(key,value);
148                     }
149                 }
150             }
151             catch (IOException e)
152             {
153                 System.err.println("[WARN] Error loading logging config: " + testProps);
154                 e.printStackTrace(System.err);
155             }
156         }
157     }
158
159     private static Logger LOG;
160     private static boolean __initialized=false;
161
162     public static void initialized()
163     {   
164         synchronized (Log.class)
165         {
166             if (__initialized)
167                 return;
168             __initialized = true;
169
170             final long uptime=ManagementFactory.getRuntimeMXBean().getUptime();
171
172             try
173             {
174                 Class<?> log_class = Loader.loadClass(Log.class, __logClass);
175                 if (LOG == null || !LOG.getClass().equals(log_class))
176                 {
177                     LOG = (Logger)log_class.newInstance();
178                     LOG.debug("Logging to {} via {}", LOG, log_class.getName());
179                 }
180             }
181             catch(Throwable e)
182             {
183                 // Unable to load specified Logger implementation, default to standard logging.
184                 initStandardLogging(e);
185             }
186
187             if (LOG!=null)
188                 LOG.info(String.format("Logging initialized @%dms",uptime));
189         }
190     }
191
192     private static void initStandardLogging(Throwable e)
193     {
194         Class<?> log_class;
195         if(e != null && __ignored)
196         {
197             e.printStackTrace(System.err);
198         }
199
200         if (LOG == null)
201         {
202             log_class = StdErrLog.class;
203             LOG = new StdErrLog();
204             LOG.debug("Logging to {} via {}", LOG, log_class.getName());
205         }
206     }
207     
208     public static Logger getLog()
209     {
210         initialized();
211         return LOG;
212     }
213
214     public static void setLog(Logger log)
215     {
216         Log.LOG = log;
217     }
218
219     /**
220      * Get the root logger.
221      * @return the root logger
222      */
223     public static Logger getRootLogger() {
224         initialized();
225         return LOG;
226     }
227
228     static boolean isIgnored()
229     {
230         return __ignored;
231     }
232
233     /**
234      * Set Log to parent Logger.
235      * <p>
236      * If there is a different Log class available from a parent classloader,
237      * call {@link #getLogger(String)} on it and construct a {@link LoggerLog} instance
238      * as this Log's Logger, so that logging is delegated to the parent Log.
239      * <p>
240      * This should be used if a webapp is using Log, but wishes the logging to be
241      * directed to the containers log.
242      * <p>
243      * If there is not parent Log, then this call is equivalent to<pre>
244      *   Log.setLog(Log.getLogger(name));
245      * </pre>
246      * @param name Logger name
247      */
248     public static void setLogToParent(String name)
249     {
250         ClassLoader loader = Log.class.getClassLoader();
251         if (loader!=null && loader.getParent()!=null)
252         {
253             try
254             {
255                 Class<?> uberlog = loader.getParent().loadClass("org.eclipse.jetty.util.log.Log");
256                 Method getLogger = uberlog.getMethod("getLogger", new Class[]{String.class});
257                 Object logger = getLogger.invoke(null,name);
258                 setLog(new LoggerLog(logger));
259             }
260             catch (Exception e)
261             {
262                 e.printStackTrace();
263             }
264         }
265         else
266         {
267             setLog(getLogger(name));
268         }
269     }
270
271     /**
272      * Obtain a named Logger based on the fully qualified class name.
273      *
274      * @param clazz
275      *            the class to base the Logger name off of
276      * @return the Logger with the given name
277      */
278     public static Logger getLogger(Class<?> clazz)
279     {
280         return getLogger(clazz.getName());
281     }
282
283     /**
284      * Obtain a named Logger or the default Logger if null is passed.
285      * @param name the Logger name
286      * @return the Logger with the given name
287      */
288     public static Logger getLogger(String name)
289     {
290         initialized();
291
292         if(name==null)
293             return LOG;
294
295         Logger logger = __loggers.get(name);
296         if(logger==null)
297             logger = LOG.getLogger(name);
298
299         return logger;
300     }
301
302     static ConcurrentMap<String, Logger> getMutableLoggers()
303     {
304         return __loggers;
305     }
306     
307     /**
308      * Get a map of all configured {@link Logger} instances.
309      *
310      * @return a map of all configured {@link Logger} instances
311      */
312     @ManagedAttribute("list of all instantiated loggers")
313     public static Map<String, Logger> getLoggers()
314     {
315         return Collections.unmodifiableMap(__loggers);
316     }
317 }