2 // ========================================================================
3 // Copyright (c) 1995-2016 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.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.util.log;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.lang.reflect.Method;
25 import java.security.AccessController;
26 import java.security.PrivilegedAction;
27 import java.util.Collections;
28 import java.util.Enumeration;
29 import java.util.Locale;
31 import java.util.Properties;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentMap;
35 import org.eclipse.jetty.util.Loader;
36 import org.eclipse.jetty.util.Uptime;
37 import org.eclipse.jetty.util.annotation.ManagedAttribute;
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.
46 * The "org.eclipse.jetty.util.log.class" system property can be used
47 * to select a specific logging implementation.
49 * If the system property org.eclipse.jetty.util.log.IGNORED is set,
50 * then ignored exceptions are logged in detail.
57 public final static String EXCEPTION= "EXCEPTION ";
58 public final static String IGNORED= "IGNORED ";
61 * Logging Configuration Properties
63 protected static final Properties __props;
65 * The {@link Logger} implementation class name
67 public static String __logClass;
69 * Legacy flag indicating if {@link Logger#ignore(Throwable)} methods produce any output in the {@link Logger}s
71 public static boolean __ignored;
76 private final static ConcurrentMap<String, Logger> __loggers = new ConcurrentHashMap<>();
81 /* Instantiate a default configuration properties (empty)
83 __props = new Properties();
85 AccessController.doPrivileged(new PrivilegedAction<Object>()
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.
94 loadProperties("jetty-logging.properties",__props);
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.
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)
104 osName = osName.toLowerCase(Locale.ENGLISH).replace(' ','-');
105 loadProperties("jetty-logging-" + osName + ".properties",__props);
108 /* Now load the System.properties as-is into the __props, these values will override
109 * any key conflicts in __props.
111 @SuppressWarnings("unchecked")
112 Enumeration<String> systemKeyEnum = (Enumeration<String>)System.getProperties().propertyNames();
113 while (systemKeyEnum.hasMoreElements())
115 String key = systemKeyEnum.nextElement();
116 String val = System.getProperty(key);
117 // protect against application code insertion of non-String values (returned as null)
120 __props.setProperty(key,val);
124 /* Now use the configuration properties to configure the Log statics
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"));
133 private static void loadProperties(String resourceName, Properties props)
135 URL testProps = Loader.getResource(Log.class,resourceName);
136 if (testProps != null)
138 try (InputStream in = testProps.openStream())
140 Properties p = new Properties();
142 for (Object key : p.keySet())
144 Object value = p.get(key);
147 props.put(key,value);
151 catch (IOException e)
153 System.err.println("[WARN] Error loading logging config: " + testProps);
154 e.printStackTrace(System.err);
159 private static Logger LOG;
160 private static boolean __initialized=false;
162 public static void initialized()
164 synchronized (Log.class)
168 __initialized = true;
172 Class<?> log_class = Loader.loadClass(Log.class, __logClass);
173 if (LOG == null || !LOG.getClass().equals(log_class))
175 LOG = (Logger)log_class.newInstance();
176 LOG.debug("Logging to {} via {}", LOG, log_class.getName());
181 // Unable to load specified Logger implementation, default to standard logging.
182 initStandardLogging(e);
186 LOG.info(String.format("Logging initialized @%dms",Uptime.getUptime()));
190 private static void initStandardLogging(Throwable e)
193 if(e != null && __ignored)
195 e.printStackTrace(System.err);
200 log_class = StdErrLog.class;
201 LOG = new StdErrLog();
202 LOG.debug("Logging to {} via {}", LOG, log_class.getName());
206 public static Logger getLog()
212 public static void setLog(Logger log)
218 * Get the root logger.
219 * @return the root logger
221 public static Logger getRootLogger() {
226 static boolean isIgnored()
232 * Set Log to parent Logger.
234 * If there is a different Log class available from a parent classloader,
235 * call {@link #getLogger(String)} on it and construct a {@link LoggerLog} instance
236 * as this Log's Logger, so that logging is delegated to the parent Log.
238 * This should be used if a webapp is using Log, but wishes the logging to be
239 * directed to the containers log.
241 * If there is not parent Log, then this call is equivalent to<pre>
242 * Log.setLog(Log.getLogger(name));
244 * @param name Logger name
246 public static void setLogToParent(String name)
248 ClassLoader loader = Log.class.getClassLoader();
249 if (loader!=null && loader.getParent()!=null)
253 Class<?> uberlog = loader.getParent().loadClass("org.eclipse.jetty.util.log.Log");
254 Method getLogger = uberlog.getMethod("getLogger", new Class[]{String.class});
255 Object logger = getLogger.invoke(null,name);
256 setLog(new LoggerLog(logger));
265 setLog(getLogger(name));
270 * Obtain a named Logger based on the fully qualified class name.
273 * the class to base the Logger name off of
274 * @return the Logger with the given name
276 public static Logger getLogger(Class<?> clazz)
278 return getLogger(clazz.getName());
282 * Obtain a named Logger or the default Logger if null is passed.
283 * @param name the Logger name
284 * @return the Logger with the given name
286 public static Logger getLogger(String name)
293 Logger logger = __loggers.get(name);
295 logger = LOG.getLogger(name);
300 static ConcurrentMap<String, Logger> getMutableLoggers()
306 * Get a map of all configured {@link Logger} instances.
308 * @return a map of all configured {@link Logger} instances
310 @ManagedAttribute("list of all instantiated loggers")
311 public static Map<String, Logger> getLoggers()
313 return Collections.unmodifiableMap(__loggers);