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 19package org.eclipse.jetty.util.log; 20 21import java.io.IOException; 22import java.io.InputStream; 23import java.lang.reflect.Method; 24import java.net.URL; 25import java.security.AccessController; 26import java.security.PrivilegedAction; 27import java.util.Collection; 28import java.util.Collections; 29import java.util.Enumeration; 30import java.util.HashMap; 31import java.util.Map; 32import java.util.Properties; 33import java.util.concurrent.ConcurrentHashMap; 34import java.util.concurrent.ConcurrentMap; 35 36import org.eclipse.jetty.util.IO; 37import 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 */ 55public 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} 463