1 /* 2 * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27 package java.util.logging; 28 29 import java.io.*; 30 import java.util.*; 31 import java.security.*; 32 import java.lang.ref.ReferenceQueue; 33 import java.lang.ref.WeakReference; 34 import java.util.concurrent.ConcurrentHashMap; 35 import java.util.concurrent.CopyOnWriteArrayList; 36 import java.util.concurrent.locks.ReentrantLock; 37 import sun.misc.JavaAWTAccess; 38 import sun.misc.ManagedLocalsThread; 39 import sun.misc.SharedSecrets; 40 41 /** 42 * There is a single global LogManager object that is used to 43 * maintain a set of shared state about Loggers and log services. 44 * <p> 45 * This LogManager object: 46 * <ul> 47 * <li> Manages a hierarchical namespace of Logger objects. All 48 * named Loggers are stored in this namespace. 49 * <li> Manages a set of logging control properties. These are 50 * simple key-value pairs that can be used by Handlers and 51 * other logging objects to configure themselves. 52 * </ul> 53 * <p> 54 * The global LogManager object can be retrieved using LogManager.getLogManager(). 55 * The LogManager object is created during class initialization and 56 * cannot subsequently be changed. 57 * <p> 58 * At startup the LogManager class is located using the 59 * java.util.logging.manager system property. 60 * <p> 61 * The LogManager defines two optional system properties that allow control over 62 * the initial configuration: 63 * <ul> 64 * <li>"java.util.logging.config.class" 65 * <li>"java.util.logging.config.file" 66 * </ul> 67 * These two properties may be specified on the command line to the "java" 68 * command, or as system property definitions passed to JNI_CreateJavaVM. 69 * <p> 70 * If the "java.util.logging.config.class" property is set, then the 71 * property value is treated as a class name. The given class will be 72 * loaded, an object will be instantiated, and that object's constructor 73 * is responsible for reading in the initial configuration. (That object 74 * may use other system properties to control its configuration.) The 75 * alternate configuration class can use <tt>readConfiguration(InputStream)</tt> 76 * to define properties in the LogManager. 77 * <p> 78 * If "java.util.logging.config.class" property is <b>not</b> set, 79 * then the "java.util.logging.config.file" system property can be used 80 * to specify a properties file (in java.util.Properties format). The 81 * initial logging configuration will be read from this file. 82 * <p> 83 * If neither of these properties is defined then the LogManager uses its 84 * default configuration. The default configuration is typically loaded from the 85 * properties file "{@code conf/logging.properties}" in the Java installation 86 * directory. 87 * <p> 88 * The properties for loggers and Handlers will have names starting 89 * with the dot-separated name for the handler or logger. 90 * <p> 91 * The global logging properties may include: 92 * <ul> 93 * <li>A property "handlers". This defines a whitespace or comma separated 94 * list of class names for handler classes to load and register as 95 * handlers on the root Logger (the Logger named ""). Each class 96 * name must be for a Handler class which has a default constructor. 97 * Note that these Handlers may be created lazily, when they are 98 * first used. 99 * 100 * <li>A property "<logger>.handlers". This defines a whitespace or 101 * comma separated list of class names for handlers classes to 102 * load and register as handlers to the specified logger. Each class 103 * name must be for a Handler class which has a default constructor. 104 * Note that these Handlers may be created lazily, when they are 105 * first used. 106 * 107 * <li>A property "<logger>.handlers.ensureCloseOnReset". This defines a 108 * a boolean value. If "<logger>.handlers" is not defined or is empty, 109 * this property is ignored. Otherwise it defaults to {@code true}. When the 110 * value is {@code true}, the handlers associated with the logger are guaranteed 111 * to be closed on {@linkplain #reset} and shutdown. This can be turned off 112 * by explicitly setting "<logger>.handlers.ensureCloseOnReset=false" in 113 * the configuration. Note that turning this property off causes the risk of 114 * introducing a resource leak, as the logger may get garbage collected before 115 * {@code reset()} is called, thus preventing its handlers from being closed 116 * on {@code reset()}. In that case it is the responsibility of the application 117 * to ensure that the handlers are closed before the logger is garbage 118 * collected. 119 * 120 * <li>A property "<logger>.useParentHandlers". This defines a boolean 121 * value. By default every logger calls its parent in addition to 122 * handling the logging message itself, this often result in messages 123 * being handled by the root logger as well. When setting this property 124 * to false a Handler needs to be configured for this logger otherwise 125 * no logging messages are delivered. 126 * 127 * <li>A property "config". This property is intended to allow 128 * arbitrary configuration code to be run. The property defines a 129 * whitespace or comma separated list of class names. A new instance will be 130 * created for each named class. The default constructor of each class 131 * may execute arbitrary code to update the logging configuration, such as 132 * setting logger levels, adding handlers, adding filters, etc. 133 * </ul> 134 * <p> 135 * Note that all classes loaded during LogManager configuration are 136 * first searched on the system class path before any user class path. 137 * That includes the LogManager class, any config classes, and any 138 * handler classes. 139 * <p> 140 * Loggers are organized into a naming hierarchy based on their 141 * dot separated names. Thus "a.b.c" is a child of "a.b", but 142 * "a.b1" and a.b2" are peers. 143 * <p> 144 * All properties whose names end with ".level" are assumed to define 145 * log levels for Loggers. Thus "foo.level" defines a log level for 146 * the logger called "foo" and (recursively) for any of its children 147 * in the naming hierarchy. Log Levels are applied in the order they 148 * are defined in the properties file. Thus level settings for child 149 * nodes in the tree should come after settings for their parents. 150 * The property name ".level" can be used to set the level for the 151 * root of the tree. 152 * <p> 153 * All methods on the LogManager object are multi-thread safe. 154 * 155 * @since 1.4 156 */ 157 158 public class LogManager { 159 // The global LogManager object 160 private static final LogManager manager; 161 162 // 'props' is assigned within a lock but accessed without it. 163 // Declaring it volatile makes sure that another thread will not 164 // be able to see a partially constructed 'props' object. 165 // (seeing a partially constructed 'props' object can result in 166 // NPE being thrown in Hashtable.get(), because it leaves the door 167 // open for props.getProperties() to be called before the construcor 168 // of Hashtable is actually completed). 169 private volatile Properties props = new Properties(); 170 private final static Level defaultLevel = Level.INFO; 171 172 // LoggerContext for system loggers and user loggers 173 private final LoggerContext systemContext = new SystemLoggerContext(); 174 private final LoggerContext userContext = new LoggerContext(); 175 // non final field - make it volatile to make sure that other threads 176 // will see the new value once ensureLogManagerInitialized() has finished 177 // executing. 178 private volatile Logger rootLogger; 179 // Have we done the primordial reading of the configuration file? 180 // (Must be done after a suitable amount of java.lang.System 181 // initialization has been done) 182 private volatile boolean readPrimordialConfiguration; 183 // Have we initialized global (root) handlers yet? 184 // This gets set to STATE_UNINITIALIZED in readConfiguration 185 private static final int 186 STATE_INITIALIZED = 0, // initial state 187 STATE_INITIALIZING = 1, 188 STATE_READING_CONFIG = 2, 189 STATE_UNINITIALIZED = 3, 190 STATE_SHUTDOWN = 4; // terminal state 191 private volatile int globalHandlersState; // = STATE_INITIALIZED; 192 // A concurrency lock for reset(), readConfiguration() and Cleaner. 193 private final ReentrantLock configurationLock = new ReentrantLock(); 194 195 // This list contains the loggers for which some handlers have been 196 // explicitly configured in the configuration file. 197 // It prevents these loggers from being arbitrarily garbage collected. 198 private static final class CloseOnReset { 199 private final Logger logger; 200 private CloseOnReset(Logger ref) { 201 this.logger = Objects.requireNonNull(ref); 202 } 203 @Override 204 public boolean equals(Object other) { 205 return (other instanceof CloseOnReset) && ((CloseOnReset)other).logger == logger; 206 } 207 @Override 208 public int hashCode() { 209 return System.identityHashCode(logger); 210 } 211 public Logger get() { 212 return logger; 213 } 214 public static CloseOnReset create(Logger logger) { 215 return new CloseOnReset(logger); 216 } 217 } 218 private final CopyOnWriteArrayList<CloseOnReset> closeOnResetLoggers = 219 new CopyOnWriteArrayList<>(); 220 221 222 private final Map<Object, Runnable> listeners = 223 Collections.synchronizedMap(new IdentityHashMap<>()); 224 225 static { 226 manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() { 227 @Override 228 public LogManager run() { 229 LogManager mgr = null; 230 String cname = null; 231 try { 232 cname = System.getProperty("java.util.logging.manager"); 233 if (cname != null) { 234 try { 235 Class<?> clz = ClassLoader.getSystemClassLoader() 236 .loadClass(cname); 237 mgr = (LogManager) clz.newInstance(); 238 } catch (ClassNotFoundException ex) { 239 Class<?> clz = Thread.currentThread() 240 .getContextClassLoader().loadClass(cname); 241 mgr = (LogManager) clz.newInstance(); 242 } 243 } 244 } catch (Exception ex) { 245 System.err.println("Could not load Logmanager \"" + cname + "\""); 246 ex.printStackTrace(); 247 } 248 if (mgr == null) { 249 mgr = new LogManager(); 250 } 251 return mgr; 252 253 } 254 }); 255 } 256 257 // This private class is used as a shutdown hook. 258 // It does a "reset" to close all open handlers. 259 private class Cleaner extends ManagedLocalsThread { 260 261 private Cleaner() { 262 /* Set context class loader to null in order to avoid 263 * keeping a strong reference to an application classloader. 264 */ 265 this.setContextClassLoader(null); 266 } 267 268 @Override 269 public void run() { 270 // This is to ensure the LogManager.<clinit> is completed 271 // before synchronized block. Otherwise deadlocks are possible. 272 LogManager mgr = manager; 273 274 // set globalHandlersState to STATE_SHUTDOWN atomically so that 275 // no attempts are made to (re)initialize the handlers or (re)read 276 // the configuration again. This is terminal state. 277 configurationLock.lock(); 278 globalHandlersState = STATE_SHUTDOWN; 279 configurationLock.unlock(); 280 281 // Do a reset to close all active handlers. 282 reset(); 283 } 284 } 285 286 287 /** 288 * Protected constructor. This is protected so that container applications 289 * (such as J2EE containers) can subclass the object. It is non-public as 290 * it is intended that there only be one LogManager object, whose value is 291 * retrieved by calling LogManager.getLogManager. 292 */ 293 protected LogManager() { 294 this(checkSubclassPermissions()); 295 } 296 297 private LogManager(Void checked) { 298 299 // Add a shutdown hook to close the global handlers. 300 try { 301 Runtime.getRuntime().addShutdownHook(new Cleaner()); 302 } catch (IllegalStateException e) { 303 // If the VM is already shutting down, 304 // We do not need to register shutdownHook. 305 } 306 } 307 308 private static Void checkSubclassPermissions() { 309 final SecurityManager sm = System.getSecurityManager(); 310 if (sm != null) { 311 // These permission will be checked in the LogManager constructor, 312 // in order to register the Cleaner() thread as a shutdown hook. 313 // Check them here to avoid the penalty of constructing the object 314 // etc... 315 sm.checkPermission(new RuntimePermission("shutdownHooks")); 316 sm.checkPermission(new RuntimePermission("setContextClassLoader")); 317 } 318 return null; 319 } 320 321 /** 322 * Lazy initialization: if this instance of manager is the global 323 * manager then this method will read the initial configuration and 324 * add the root logger and global logger by calling addLogger(). 325 * 326 * Note that it is subtly different from what we do in LoggerContext. 327 * In LoggerContext we're patching up the logger context tree in order to add 328 * the root and global logger *to the context tree*. 329 * 330 * For this to work, addLogger() must have already have been called 331 * once on the LogManager instance for the default logger being 332 * added. 333 * 334 * This is why ensureLogManagerInitialized() needs to be called before 335 * any logger is added to any logger context. 336 * 337 */ 338 private boolean initializedCalled = false; 339 private volatile boolean initializationDone = false; 340 final void ensureLogManagerInitialized() { 341 final LogManager owner = this; 342 if (initializationDone || owner != manager) { 343 // we don't want to do this twice, and we don't want to do 344 // this on private manager instances. 345 return; 346 } 347 348 // Maybe another thread has called ensureLogManagerInitialized() 349 // before us and is still executing it. If so we will block until 350 // the log manager has finished initialized, then acquire the monitor, 351 // notice that initializationDone is now true and return. 352 // Otherwise - we have come here first! We will acquire the monitor, 353 // see that initializationDone is still false, and perform the 354 // initialization. 355 // 356 configurationLock.lock(); 357 try { 358 // If initializedCalled is true it means that we're already in 359 // the process of initializing the LogManager in this thread. 360 // There has been a recursive call to ensureLogManagerInitialized(). 361 final boolean isRecursiveInitialization = (initializedCalled == true); 362 363 assert initializedCalled || !initializationDone 364 : "Initialization can't be done if initialized has not been called!"; 365 366 if (isRecursiveInitialization || initializationDone) { 367 // If isRecursiveInitialization is true it means that we're 368 // already in the process of initializing the LogManager in 369 // this thread. There has been a recursive call to 370 // ensureLogManagerInitialized(). We should not proceed as 371 // it would lead to infinite recursion. 372 // 373 // If initializationDone is true then it means the manager 374 // has finished initializing; just return: we're done. 375 return; 376 } 377 // Calling addLogger below will in turn call requiresDefaultLogger() 378 // which will call ensureLogManagerInitialized(). 379 // We use initializedCalled to break the recursion. 380 initializedCalled = true; 381 try { 382 // // TODO: remove this before pushing 383 // // Hacky sleep that makes it possible to reproduce 8132550 384 // // consistently. see also reset(). 385 // if (!(Thread.currentThread() instanceof Cleaner)) { 386 // try { 387 // // System.err.println("Initializing thread sleeping 2000L"); 388 // Thread.sleep(2000L); 389 // } catch (InterruptedException ex) { 390 // ex.printStackTrace(); 391 // } 392 // } 393 AccessController.doPrivileged(new PrivilegedAction<Object>() { 394 @Override 395 public Object run() { 396 assert rootLogger == null; 397 assert initializedCalled && !initializationDone; 398 399 // Read configuration. 400 owner.readPrimordialConfiguration(); 401 402 // Create and retain Logger for the root of the namespace. 403 owner.rootLogger = owner.new RootLogger(); 404 owner.addLogger(owner.rootLogger); 405 if (!owner.rootLogger.isLevelInitialized()) { 406 owner.rootLogger.setLevel(defaultLevel); 407 } 408 409 // Adding the global Logger. 410 // Do not call Logger.getGlobal() here as this might trigger 411 // subtle inter-dependency issues. 412 @SuppressWarnings("deprecation") 413 final Logger global = Logger.global; 414 415 // Make sure the global logger will be registered in the 416 // global manager 417 owner.addLogger(global); 418 return null; 419 } 420 }); 421 } finally { 422 initializationDone = true; 423 } 424 } finally { 425 configurationLock.unlock(); 426 } 427 } 428 429 /** 430 * Returns the global LogManager object. 431 * @return the global LogManager object 432 */ 433 public static LogManager getLogManager() { 434 if (manager != null) { 435 manager.ensureLogManagerInitialized(); 436 } 437 return manager; 438 } 439 440 private void readPrimordialConfiguration() { // must be called while holding configurationLock 441 if (!readPrimordialConfiguration) { 442 // If System.in/out/err are null, it's a good 443 // indication that we're still in the 444 // bootstrapping phase 445 if (System.out == null) { 446 return; 447 } 448 readPrimordialConfiguration = true; 449 try { 450 readConfiguration(); 451 452 // Platform loggers begin to delegate to java.util.logging.Logger 453 sun.util.logging.PlatformLogger.redirectPlatformLoggers(); 454 } catch (Exception ex) { 455 assert false : "Exception raised while reading logging configuration: " + ex; 456 } 457 } 458 } 459 460 // LoggerContext maps from AppContext 461 private WeakHashMap<Object, LoggerContext> contextsMap = null; 462 463 // Returns the LoggerContext for the user code (i.e. application or AppContext). 464 // Loggers are isolated from each AppContext. 465 private LoggerContext getUserContext() { 466 LoggerContext context = null; 467 468 SecurityManager sm = System.getSecurityManager(); 469 JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess(); 470 if (sm != null && javaAwtAccess != null) { 471 // for each applet, it has its own LoggerContext isolated from others 472 final Object ecx = javaAwtAccess.getAppletContext(); 473 if (ecx != null) { 474 synchronized (javaAwtAccess) { 475 // find the AppContext of the applet code 476 // will be null if we are in the main app context. 477 if (contextsMap == null) { 478 contextsMap = new WeakHashMap<>(); 479 } 480 context = contextsMap.get(ecx); 481 if (context == null) { 482 // Create a new LoggerContext for the applet. 483 context = new LoggerContext(); 484 contextsMap.put(ecx, context); 485 } 486 } 487 } 488 } 489 // for standalone app, return userContext 490 return context != null ? context : userContext; 491 } 492 493 // The system context. 494 final LoggerContext getSystemContext() { 495 return systemContext; 496 } 497 498 private List<LoggerContext> contexts() { 499 List<LoggerContext> cxs = new ArrayList<>(); 500 cxs.add(getSystemContext()); 501 cxs.add(getUserContext()); 502 return cxs; 503 } 504 505 // Find or create a specified logger instance. If a logger has 506 // already been created with the given name it is returned. 507 // Otherwise a new logger instance is created and registered 508 // in the LogManager global namespace. 509 // This method will always return a non-null Logger object. 510 // Synchronization is not required here. All synchronization for 511 // adding a new Logger object is handled by addLogger(). 512 // 513 // This method must delegate to the LogManager implementation to 514 // add a new Logger or return the one that has been added previously 515 // as a LogManager subclass may override the addLogger, getLogger, 516 // readConfiguration, and other methods. 517 Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { 518 Logger result = getLogger(name); 519 if (result == null) { 520 // only allocate the new logger once 521 Logger newLogger = new Logger(name, resourceBundleName, caller, this, false); 522 do { 523 if (addLogger(newLogger)) { 524 // We successfully added the new Logger that we 525 // created above so return it without refetching. 526 return newLogger; 527 } 528 529 // We didn't add the new Logger that we created above 530 // because another thread added a Logger with the same 531 // name after our null check above and before our call 532 // to addLogger(). We have to refetch the Logger because 533 // addLogger() returns a boolean instead of the Logger 534 // reference itself. However, if the thread that created 535 // the other Logger is not holding a strong reference to 536 // the other Logger, then it is possible for the other 537 // Logger to be GC'ed after we saw it in addLogger() and 538 // before we can refetch it. If it has been GC'ed then 539 // we'll just loop around and try again. 540 result = getLogger(name); 541 } while (result == null); 542 } 543 return result; 544 } 545 546 Logger demandSystemLogger(String name, String resourceBundleName, Class<?> caller) { 547 // Add a system logger in the system context's namespace 548 final Logger sysLogger = getSystemContext() 549 .demandLogger(name, resourceBundleName, caller); 550 551 // Add the system logger to the LogManager's namespace if not exist 552 // so that there is only one single logger of the given name. 553 // System loggers are visible to applications unless a logger of 554 // the same name has been added. 555 Logger logger; 556 do { 557 // First attempt to call addLogger instead of getLogger 558 // This would avoid potential bug in custom LogManager.getLogger 559 // implementation that adds a logger if does not exist 560 if (addLogger(sysLogger)) { 561 // successfully added the new system logger 562 logger = sysLogger; 563 } else { 564 logger = getLogger(name); 565 } 566 } while (logger == null); 567 568 // LogManager will set the sysLogger's handlers via LogManager.addLogger method. 569 if (logger != sysLogger && sysLogger.accessCheckedHandlers().length == 0) { 570 // if logger already exists but handlers not set 571 final Logger l = logger; 572 AccessController.doPrivileged(new PrivilegedAction<Void>() { 573 @Override 574 public Void run() { 575 for (Handler hdl : l.accessCheckedHandlers()) { 576 sysLogger.addHandler(hdl); 577 } 578 return null; 579 } 580 }); 581 } 582 return sysLogger; 583 } 584 585 // LoggerContext maintains the logger namespace per context. 586 // The default LogManager implementation has one system context and user 587 // context. The system context is used to maintain the namespace for 588 // all system loggers and is queried by the system code. If a system logger 589 // doesn't exist in the user context, it'll also be added to the user context. 590 // The user context is queried by the user code and all other loggers are 591 // added in the user context. 592 class LoggerContext { 593 // Table of named Loggers that maps names to Loggers. 594 private final ConcurrentHashMap<String,LoggerWeakRef> namedLoggers = 595 new ConcurrentHashMap<>(); 596 // Tree of named Loggers 597 private final LogNode root; 598 private LoggerContext() { 599 this.root = new LogNode(null, this); 600 } 601 602 603 // Tells whether default loggers are required in this context. 604 // If true, the default loggers will be lazily added. 605 final boolean requiresDefaultLoggers() { 606 final boolean requiresDefaultLoggers = (getOwner() == manager); 607 if (requiresDefaultLoggers) { 608 getOwner().ensureLogManagerInitialized(); 609 } 610 return requiresDefaultLoggers; 611 } 612 613 // This context's LogManager. 614 final LogManager getOwner() { 615 return LogManager.this; 616 } 617 618 // This context owner's root logger, which if not null, and if 619 // the context requires default loggers, will be added to the context 620 // logger's tree. 621 final Logger getRootLogger() { 622 return getOwner().rootLogger; 623 } 624 625 // The global logger, which if not null, and if 626 // the context requires default loggers, will be added to the context 627 // logger's tree. 628 final Logger getGlobalLogger() { 629 @SuppressWarnings("deprecation") // avoids initialization cycles. 630 final Logger global = Logger.global; 631 return global; 632 } 633 634 Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { 635 // a LogManager subclass may have its own implementation to add and 636 // get a Logger. So delegate to the LogManager to do the work. 637 final LogManager owner = getOwner(); 638 return owner.demandLogger(name, resourceBundleName, caller); 639 } 640 641 642 // Due to subtle deadlock issues getUserContext() no longer 643 // calls addLocalLogger(rootLogger); 644 // Therefore - we need to add the default loggers later on. 645 // Checks that the context is properly initialized 646 // This is necessary before calling e.g. find(name) 647 // or getLoggerNames() 648 // 649 private void ensureInitialized() { 650 if (requiresDefaultLoggers()) { 651 // Ensure that the root and global loggers are set. 652 ensureDefaultLogger(getRootLogger()); 653 ensureDefaultLogger(getGlobalLogger()); 654 } 655 } 656 657 658 Logger findLogger(String name) { 659 // Attempt to find logger without locking. 660 LoggerWeakRef ref = namedLoggers.get(name); 661 Logger logger = ref == null ? null : ref.get(); 662 663 // if logger is not null, then we can return it right away. 664 // if name is "" or "global" and logger is null 665 // we need to fall through and check that this context is 666 // initialized. 667 // if ref is not null and logger is null we also need to 668 // fall through. 669 if (logger != null || (ref == null && !name.isEmpty() 670 && !name.equals(Logger.GLOBAL_LOGGER_NAME))) { 671 return logger; 672 } 673 674 // We either found a stale reference, or we were looking for 675 // "" or "global" and didn't find them. 676 // Make sure context is initialized (has the default loggers), 677 // and look up again, cleaning the stale reference if it hasn't 678 // been cleaned up in between. All this needs to be done inside 679 // a synchronized block. 680 synchronized(this) { 681 // ensure that this context is properly initialized before 682 // looking for loggers. 683 ensureInitialized(); 684 ref = namedLoggers.get(name); 685 if (ref == null) { 686 return null; 687 } 688 logger = ref.get(); 689 if (logger == null) { 690 // The namedLoggers map holds stale weak reference 691 // to a logger which has been GC-ed. 692 ref.dispose(); 693 } 694 return logger; 695 } 696 } 697 698 // This method is called before adding a logger to the 699 // context. 700 // 'logger' is the context that will be added. 701 // This method will ensure that the defaults loggers are added 702 // before adding 'logger'. 703 // 704 private void ensureAllDefaultLoggers(Logger logger) { 705 if (requiresDefaultLoggers()) { 706 final String name = logger.getName(); 707 if (!name.isEmpty()) { 708 ensureDefaultLogger(getRootLogger()); 709 if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) { 710 ensureDefaultLogger(getGlobalLogger()); 711 } 712 } 713 } 714 } 715 716 private void ensureDefaultLogger(Logger logger) { 717 // Used for lazy addition of root logger and global logger 718 // to a LoggerContext. 719 720 // This check is simple sanity: we do not want that this 721 // method be called for anything else than Logger.global 722 // or owner.rootLogger. 723 if (!requiresDefaultLoggers() || logger == null 724 || logger != getGlobalLogger() && logger != LogManager.this.rootLogger ) { 725 726 // the case where we have a non null logger which is neither 727 // Logger.global nor manager.rootLogger indicates a serious 728 // issue - as ensureDefaultLogger should never be called 729 // with any other loggers than one of these two (or null - if 730 // e.g manager.rootLogger is not yet initialized)... 731 assert logger == null; 732 733 return; 734 } 735 736 // Adds the logger if it's not already there. 737 if (!namedLoggers.containsKey(logger.getName())) { 738 // It is important to prevent addLocalLogger to 739 // call ensureAllDefaultLoggers when we're in the process 740 // off adding one of those default loggers - as this would 741 // immediately cause a stack overflow. 742 // Therefore we must pass addDefaultLoggersIfNeeded=false, 743 // even if requiresDefaultLoggers is true. 744 addLocalLogger(logger, false); 745 } 746 } 747 748 boolean addLocalLogger(Logger logger) { 749 // no need to add default loggers if it's not required 750 return addLocalLogger(logger, requiresDefaultLoggers()); 751 } 752 753 // Add a logger to this context. This method will only set its level 754 // and process parent loggers. It doesn't set its handlers. 755 synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) { 756 // addDefaultLoggersIfNeeded serves to break recursion when adding 757 // default loggers. If we're adding one of the default loggers 758 // (we're being called from ensureDefaultLogger()) then 759 // addDefaultLoggersIfNeeded will be false: we don't want to 760 // call ensureAllDefaultLoggers again. 761 // 762 // Note: addDefaultLoggersIfNeeded can also be false when 763 // requiresDefaultLoggers is false - since calling 764 // ensureAllDefaultLoggers would have no effect in this case. 765 if (addDefaultLoggersIfNeeded) { 766 ensureAllDefaultLoggers(logger); 767 } 768 769 final String name = logger.getName(); 770 if (name == null) { 771 throw new NullPointerException(); 772 } 773 LoggerWeakRef ref = namedLoggers.get(name); 774 if (ref != null) { 775 if (ref.get() == null) { 776 // It's possible that the Logger was GC'ed after a 777 // drainLoggerRefQueueBounded() call above so allow 778 // a new one to be registered. 779 ref.dispose(); 780 } else { 781 // We already have a registered logger with the given name. 782 return false; 783 } 784 } 785 786 // We're adding a new logger. 787 // Note that we are creating a weak reference here. 788 final LogManager owner = getOwner(); 789 logger.setLogManager(owner); 790 ref = owner.new LoggerWeakRef(logger); 791 792 // Apply any initial level defined for the new logger, unless 793 // the logger's level is already initialized 794 Level level = owner.getLevelProperty(name + ".level", null); 795 if (level != null && !logger.isLevelInitialized()) { 796 doSetLevel(logger, level); 797 } 798 799 // instantiation of the handler is done in the LogManager.addLogger 800 // implementation as a handler class may be only visible to LogManager 801 // subclass for the custom log manager case 802 processParentHandlers(logger, name); 803 804 // Find the new node and its parent. 805 LogNode node = getNode(name); 806 node.loggerRef = ref; 807 Logger parent = null; 808 LogNode nodep = node.parent; 809 while (nodep != null) { 810 LoggerWeakRef nodeRef = nodep.loggerRef; 811 if (nodeRef != null) { 812 parent = nodeRef.get(); 813 if (parent != null) { 814 break; 815 } 816 } 817 nodep = nodep.parent; 818 } 819 820 if (parent != null) { 821 doSetParent(logger, parent); 822 } 823 // Walk over the children and tell them we are their new parent. 824 node.walkAndSetParent(logger); 825 // new LogNode is ready so tell the LoggerWeakRef about it 826 ref.setNode(node); 827 828 // Do not publish 'ref' in namedLoggers before the logger tree 829 // is fully updated - because the named logger will be visible as 830 // soon as it is published in namedLoggers (findLogger takes 831 // benefit of the ConcurrentHashMap implementation of namedLoggers 832 // to avoid synchronizing on retrieval when that is possible). 833 namedLoggers.put(name, ref); 834 return true; 835 } 836 837 void removeLoggerRef(String name, LoggerWeakRef ref) { 838 namedLoggers.remove(name, ref); 839 } 840 841 synchronized Enumeration<String> getLoggerNames() { 842 // ensure that this context is properly initialized before 843 // returning logger names. 844 ensureInitialized(); 845 return Collections.enumeration(namedLoggers.keySet()); 846 } 847 848 // If logger.getUseParentHandlers() returns 'true' and any of the logger's 849 // parents have levels or handlers defined, make sure they are instantiated. 850 private void processParentHandlers(final Logger logger, final String name) { 851 final LogManager owner = getOwner(); 852 AccessController.doPrivileged(new PrivilegedAction<Void>() { 853 @Override 854 public Void run() { 855 if (logger != owner.rootLogger) { 856 boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true); 857 if (!useParent) { 858 logger.setUseParentHandlers(false); 859 } 860 } 861 return null; 862 } 863 }); 864 865 int ix = 1; 866 for (;;) { 867 int ix2 = name.indexOf('.', ix); 868 if (ix2 < 0) { 869 break; 870 } 871 String pname = name.substring(0, ix2); 872 if (owner.getProperty(pname + ".level") != null || 873 owner.getProperty(pname + ".handlers") != null) { 874 // This pname has a level/handlers definition. 875 // Make sure it exists. 876 demandLogger(pname, null, null); 877 } 878 ix = ix2+1; 879 } 880 } 881 882 // Gets a node in our tree of logger nodes. 883 // If necessary, create it. 884 LogNode getNode(String name) { 885 if (name == null || name.equals("")) { 886 return root; 887 } 888 LogNode node = root; 889 while (name.length() > 0) { 890 int ix = name.indexOf('.'); 891 String head; 892 if (ix > 0) { 893 head = name.substring(0, ix); 894 name = name.substring(ix + 1); 895 } else { 896 head = name; 897 name = ""; 898 } 899 if (node.children == null) { 900 node.children = new HashMap<>(); 901 } 902 LogNode child = node.children.get(head); 903 if (child == null) { 904 child = new LogNode(node, this); 905 node.children.put(head, child); 906 } 907 node = child; 908 } 909 return node; 910 } 911 } 912 913 final class SystemLoggerContext extends LoggerContext { 914 // Add a system logger in the system context's namespace as well as 915 // in the LogManager's namespace if not exist so that there is only 916 // one single logger of the given name. System loggers are visible 917 // to applications unless a logger of the same name has been added. 918 @Override 919 Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { 920 Logger result = findLogger(name); 921 if (result == null) { 922 // only allocate the new system logger once 923 Logger newLogger = new Logger(name, resourceBundleName, caller, getOwner(), true); 924 do { 925 if (addLocalLogger(newLogger)) { 926 // We successfully added the new Logger that we 927 // created above so return it without refetching. 928 result = newLogger; 929 } else { 930 // We didn't add the new Logger that we created above 931 // because another thread added a Logger with the same 932 // name after our null check above and before our call 933 // to addLogger(). We have to refetch the Logger because 934 // addLogger() returns a boolean instead of the Logger 935 // reference itself. However, if the thread that created 936 // the other Logger is not holding a strong reference to 937 // the other Logger, then it is possible for the other 938 // Logger to be GC'ed after we saw it in addLogger() and 939 // before we can refetch it. If it has been GC'ed then 940 // we'll just loop around and try again. 941 result = findLogger(name); 942 } 943 } while (result == null); 944 } 945 return result; 946 } 947 } 948 949 // Add new per logger handlers. 950 // We need to raise privilege here. All our decisions will 951 // be made based on the logging configuration, which can 952 // only be modified by trusted code. 953 private void loadLoggerHandlers(final Logger logger, final String name, 954 final String handlersPropertyName) 955 { 956 AccessController.doPrivileged(new PrivilegedAction<Object>() { 957 @Override 958 public Object run() { 959 String names[] = parseClassNames(handlersPropertyName); 960 final boolean ensureCloseOnReset = names.length > 0 961 && getBooleanProperty(handlersPropertyName + ".ensureCloseOnReset",true); 962 963 int count = 0; 964 for (String type : names) { 965 try { 966 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(type); 967 Handler hdl = (Handler) clz.newInstance(); 968 // Check if there is a property defining the 969 // this handler's level. 970 String levs = getProperty(type + ".level"); 971 if (levs != null) { 972 Level l = Level.findLevel(levs); 973 if (l != null) { 974 hdl.setLevel(l); 975 } else { 976 // Probably a bad level. Drop through. 977 System.err.println("Can't set level for " + type); 978 } 979 } 980 // Add this Handler to the logger 981 logger.addHandler(hdl); 982 if (++count == 1 && ensureCloseOnReset) { 983 // add this logger to the closeOnResetLoggers list. 984 closeOnResetLoggers.addIfAbsent(CloseOnReset.create(logger)); 985 } 986 } catch (Exception ex) { 987 System.err.println("Can't load log handler \"" + type + "\""); 988 System.err.println("" + ex); 989 ex.printStackTrace(); 990 } 991 } 992 993 return null; 994 } 995 }); 996 } 997 998 999 // loggerRefQueue holds LoggerWeakRef objects for Logger objects 1000 // that have been GC'ed. 1001 private final ReferenceQueue<Logger> loggerRefQueue 1002 = new ReferenceQueue<>(); 1003 1004 // Package-level inner class. 1005 // Helper class for managing WeakReferences to Logger objects. 1006 // 1007 // LogManager.namedLoggers 1008 // - has weak references to all named Loggers 1009 // - namedLoggers keeps the LoggerWeakRef objects for the named 1010 // Loggers around until we can deal with the book keeping for 1011 // the named Logger that is being GC'ed. 1012 // LogManager.LogNode.loggerRef 1013 // - has a weak reference to a named Logger 1014 // - the LogNode will also keep the LoggerWeakRef objects for 1015 // the named Loggers around; currently LogNodes never go away. 1016 // Logger.kids 1017 // - has a weak reference to each direct child Logger; this 1018 // includes anonymous and named Loggers 1019 // - anonymous Loggers are always children of the rootLogger 1020 // which is a strong reference; rootLogger.kids keeps the 1021 // LoggerWeakRef objects for the anonymous Loggers around 1022 // until we can deal with the book keeping. 1023 // 1024 final class LoggerWeakRef extends WeakReference<Logger> { 1025 private String name; // for namedLoggers cleanup 1026 private LogNode node; // for loggerRef cleanup 1027 private WeakReference<Logger> parentRef; // for kids cleanup 1028 private boolean disposed = false; // avoid calling dispose twice 1029 1030 LoggerWeakRef(Logger logger) { 1031 super(logger, loggerRefQueue); 1032 1033 name = logger.getName(); // save for namedLoggers cleanup 1034 } 1035 1036 // dispose of this LoggerWeakRef object 1037 void dispose() { 1038 // Avoid calling dispose twice. When a Logger is gc'ed, its 1039 // LoggerWeakRef will be enqueued. 1040 // However, a new logger of the same name may be added (or looked 1041 // up) before the queue is drained. When that happens, dispose() 1042 // will be called by addLocalLogger() or findLogger(). 1043 // Later when the queue is drained, dispose() will be called again 1044 // for the same LoggerWeakRef. Marking LoggerWeakRef as disposed 1045 // avoids processing the data twice (even though the code should 1046 // now be reentrant). 1047 synchronized(this) { 1048 // Note to maintainers: 1049 // Be careful not to call any method that tries to acquire 1050 // another lock from within this block - as this would surely 1051 // lead to deadlocks, given that dispose() can be called by 1052 // multiple threads, and from within different synchronized 1053 // methods/blocks. 1054 if (disposed) return; 1055 disposed = true; 1056 } 1057 1058 final LogNode n = node; 1059 if (n != null) { 1060 // n.loggerRef can only be safely modified from within 1061 // a lock on LoggerContext. removeLoggerRef is already 1062 // synchronized on LoggerContext so calling 1063 // n.context.removeLoggerRef from within this lock is safe. 1064 synchronized (n.context) { 1065 // if we have a LogNode, then we were a named Logger 1066 // so clear namedLoggers weak ref to us 1067 n.context.removeLoggerRef(name, this); 1068 name = null; // clear our ref to the Logger's name 1069 1070 // LogNode may have been reused - so only clear 1071 // LogNode.loggerRef if LogNode.loggerRef == this 1072 if (n.loggerRef == this) { 1073 n.loggerRef = null; // clear LogNode's weak ref to us 1074 } 1075 node = null; // clear our ref to LogNode 1076 } 1077 } 1078 1079 if (parentRef != null) { 1080 // this LoggerWeakRef has or had a parent Logger 1081 Logger parent = parentRef.get(); 1082 if (parent != null) { 1083 // the parent Logger is still there so clear the 1084 // parent Logger's weak ref to us 1085 parent.removeChildLogger(this); 1086 } 1087 parentRef = null; // clear our weak ref to the parent Logger 1088 } 1089 } 1090 1091 // set the node field to the specified value 1092 void setNode(LogNode node) { 1093 this.node = node; 1094 } 1095 1096 // set the parentRef field to the specified value 1097 void setParentRef(WeakReference<Logger> parentRef) { 1098 this.parentRef = parentRef; 1099 } 1100 } 1101 1102 // Package-level method. 1103 // Drain some Logger objects that have been GC'ed. 1104 // 1105 // drainLoggerRefQueueBounded() is called by addLogger() below 1106 // and by Logger.getAnonymousLogger(String) so we'll drain up to 1107 // MAX_ITERATIONS GC'ed Loggers for every Logger we add. 1108 // 1109 // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives 1110 // us about a 50/50 mix in increased weak ref counts versus 1111 // decreased weak ref counts in the AnonLoggerWeakRefLeak test. 1112 // Here are stats for cleaning up sets of 400 anonymous Loggers: 1113 // - test duration 1 minute 1114 // - sample size of 125 sets of 400 1115 // - average: 1.99 ms 1116 // - minimum: 0.57 ms 1117 // - maximum: 25.3 ms 1118 // 1119 // The same config gives us a better decreased weak ref count 1120 // than increased weak ref count in the LoggerWeakRefLeak test. 1121 // Here are stats for cleaning up sets of 400 named Loggers: 1122 // - test duration 2 minutes 1123 // - sample size of 506 sets of 400 1124 // - average: 0.57 ms 1125 // - minimum: 0.02 ms 1126 // - maximum: 10.9 ms 1127 // 1128 private final static int MAX_ITERATIONS = 400; 1129 final void drainLoggerRefQueueBounded() { 1130 for (int i = 0; i < MAX_ITERATIONS; i++) { 1131 if (loggerRefQueue == null) { 1132 // haven't finished loading LogManager yet 1133 break; 1134 } 1135 1136 LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll(); 1137 if (ref == null) { 1138 break; 1139 } 1140 // a Logger object has been GC'ed so clean it up 1141 ref.dispose(); 1142 } 1143 } 1144 1145 /** 1146 * Add a named logger. This does nothing and returns false if a logger 1147 * with the same name is already registered. 1148 * <p> 1149 * The Logger factory methods call this method to register each 1150 * newly created Logger. 1151 * <p> 1152 * The application should retain its own reference to the Logger 1153 * object to avoid it being garbage collected. The LogManager 1154 * may only retain a weak reference. 1155 * 1156 * @param logger the new logger. 1157 * @return true if the argument logger was registered successfully, 1158 * false if a logger of that name already exists. 1159 * @exception NullPointerException if the logger name is null. 1160 */ 1161 public boolean addLogger(Logger logger) { 1162 final String name = logger.getName(); 1163 if (name == null) { 1164 throw new NullPointerException(); 1165 } 1166 drainLoggerRefQueueBounded(); 1167 LoggerContext cx = getUserContext(); 1168 if (cx.addLocalLogger(logger)) { 1169 // Do we have a per logger handler too? 1170 // Note: this will add a 200ms penalty 1171 loadLoggerHandlers(logger, name, name + ".handlers"); 1172 return true; 1173 } else { 1174 return false; 1175 } 1176 } 1177 1178 // Private method to set a level on a logger. 1179 // If necessary, we raise privilege before doing the call. 1180 private static void doSetLevel(final Logger logger, final Level level) { 1181 SecurityManager sm = System.getSecurityManager(); 1182 if (sm == null) { 1183 // There is no security manager, so things are easy. 1184 logger.setLevel(level); 1185 return; 1186 } 1187 // There is a security manager. Raise privilege before 1188 // calling setLevel. 1189 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1190 @Override 1191 public Object run() { 1192 logger.setLevel(level); 1193 return null; 1194 }}); 1195 } 1196 1197 // Private method to set a parent on a logger. 1198 // If necessary, we raise privilege before doing the setParent call. 1199 private static void doSetParent(final Logger logger, final Logger parent) { 1200 SecurityManager sm = System.getSecurityManager(); 1201 if (sm == null) { 1202 // There is no security manager, so things are easy. 1203 logger.setParent(parent); 1204 return; 1205 } 1206 // There is a security manager. Raise privilege before 1207 // calling setParent. 1208 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1209 @Override 1210 public Object run() { 1211 logger.setParent(parent); 1212 return null; 1213 }}); 1214 } 1215 1216 /** 1217 * Method to find a named logger. 1218 * <p> 1219 * Note that since untrusted code may create loggers with 1220 * arbitrary names this method should not be relied on to 1221 * find Loggers for security sensitive logging. 1222 * It is also important to note that the Logger associated with the 1223 * String {@code name} may be garbage collected at any time if there 1224 * is no strong reference to the Logger. The caller of this method 1225 * must check the return value for null in order to properly handle 1226 * the case where the Logger has been garbage collected. 1227 * 1228 * @param name name of the logger 1229 * @return matching logger or null if none is found 1230 */ 1231 public Logger getLogger(String name) { 1232 return getUserContext().findLogger(name); 1233 } 1234 1235 /** 1236 * Get an enumeration of known logger names. 1237 * <p> 1238 * Note: Loggers may be added dynamically as new classes are loaded. 1239 * This method only reports on the loggers that are currently registered. 1240 * It is also important to note that this method only returns the name 1241 * of a Logger, not a strong reference to the Logger itself. 1242 * The returned String does nothing to prevent the Logger from being 1243 * garbage collected. In particular, if the returned name is passed 1244 * to {@code LogManager.getLogger()}, then the caller must check the 1245 * return value from {@code LogManager.getLogger()} for null to properly 1246 * handle the case where the Logger has been garbage collected in the 1247 * time since its name was returned by this method. 1248 * 1249 * @return enumeration of logger name strings 1250 */ 1251 public Enumeration<String> getLoggerNames() { 1252 return getUserContext().getLoggerNames(); 1253 } 1254 1255 /** 1256 * Reinitialize the logging properties and reread the logging configuration. 1257 * <p> 1258 * The same rules are used for locating the configuration properties 1259 * as are used at startup. So normally the logging properties will 1260 * be re-read from the same file that was used at startup. 1261 * <P> 1262 * Any log level definitions in the new configuration file will be 1263 * applied using Logger.setLevel(), if the target Logger exists. 1264 * <p> 1265 * Any {@linkplain #addConfigurationListener registered configuration 1266 * listener} will be invoked after the properties are read. 1267 * 1268 * @exception SecurityException if a security manager exists and if 1269 * the caller does not have LoggingPermission("control"). 1270 * @exception IOException if there are IO problems reading the configuration. 1271 */ 1272 public void readConfiguration() throws IOException, SecurityException { 1273 checkPermission(); 1274 1275 // if a configuration class is specified, load it and use it. 1276 String cname = System.getProperty("java.util.logging.config.class"); 1277 if (cname != null) { 1278 try { 1279 // Instantiate the named class. It is its constructor's 1280 // responsibility to initialize the logging configuration, by 1281 // calling readConfiguration(InputStream) with a suitable stream. 1282 try { 1283 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname); 1284 clz.newInstance(); 1285 return; 1286 } catch (ClassNotFoundException ex) { 1287 Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname); 1288 clz.newInstance(); 1289 return; 1290 } 1291 } catch (Exception ex) { 1292 System.err.println("Logging configuration class \"" + cname + "\" failed"); 1293 System.err.println("" + ex); 1294 // keep going and useful config file. 1295 } 1296 } 1297 1298 String fname = System.getProperty("java.util.logging.config.file"); 1299 if (fname == null) { 1300 fname = System.getProperty("java.home"); 1301 if (fname == null) { 1302 throw new Error("Can't find java.home ??"); 1303 } 1304 File f = new File(fname, "conf"); 1305 f = new File(f, "logging.properties"); 1306 fname = f.getCanonicalPath(); 1307 } 1308 try (final InputStream in = new FileInputStream(fname)) { 1309 final BufferedInputStream bin = new BufferedInputStream(in); 1310 readConfiguration(bin); 1311 } 1312 } 1313 1314 /** 1315 * Reset the logging configuration. 1316 * <p> 1317 * For all named loggers, the reset operation removes and closes 1318 * all Handlers and (except for the root logger) sets the level 1319 * to null. The root logger's level is set to Level.INFO. 1320 * 1321 * @exception SecurityException if a security manager exists and if 1322 * the caller does not have LoggingPermission("control"). 1323 */ 1324 1325 public void reset() throws SecurityException { 1326 checkPermission(); 1327 1328 List<CloseOnReset> persistent; 1329 1330 // We don't want reset() and readConfiguration() 1331 // to run in parallel 1332 configurationLock.lock(); 1333 try { 1334 1335 // // TODO: remove this before pushing 1336 // // Hacky sleep that makes it possible to reproduce 8132550 1337 // // consistently. see also ensureLogManagerInitialized(). 1338 // if (Thread.currentThread() instanceof Cleaner) { 1339 // try { 1340 // // System.err.println("Cleaner Thread sleeping 5000L"); 1341 // Thread.sleep(5000L); 1342 // } catch (InterruptedException ex) { 1343 // ex.printStackTrace(); 1344 // } 1345 // } 1346 1347 // install new empty properties 1348 props = new Properties(); 1349 // make sure we keep the loggers persistent until reset is done. 1350 // Those are the loggers for which we previously created a 1351 // handler from the configuration, and we need to prevent them 1352 // from being gc'ed until those handlers are closed. 1353 persistent = new ArrayList<>(closeOnResetLoggers); 1354 closeOnResetLoggers.clear(); 1355 1356 // if reset has been called from shutdown-hook (Cleaner), 1357 // or if reset has been called from readConfiguration() which 1358 // already holds the lock and will change the state itself, 1359 // then do not change state here... 1360 if (globalHandlersState != STATE_SHUTDOWN && 1361 globalHandlersState != STATE_READING_CONFIG) { 1362 // ...else user called reset()... 1363 // Since we are doing a reset we no longer want to initialize 1364 // the global handlers, if they haven't been initialized yet. 1365 globalHandlersState = STATE_INITIALIZED; 1366 } 1367 1368 for (LoggerContext cx : contexts()) { 1369 resetLoggerContext(cx); 1370 } 1371 1372 persistent.clear(); 1373 } finally { 1374 configurationLock.unlock(); 1375 } 1376 } 1377 1378 private void resetLoggerContext(LoggerContext cx) { 1379 Enumeration<String> enum_ = cx.getLoggerNames(); 1380 while (enum_.hasMoreElements()) { 1381 String name = enum_.nextElement(); 1382 Logger logger = cx.findLogger(name); 1383 if (logger != null) { 1384 resetLogger(logger); 1385 } 1386 } 1387 } 1388 1389 private void closeHandlers(Logger logger) { 1390 Handler[] targets = logger.getHandlers(); 1391 for (Handler h : targets) { 1392 logger.removeHandler(h); 1393 try { 1394 h.close(); 1395 } catch (Exception ex) { 1396 // Problems closing a handler? Keep going... 1397 } 1398 } 1399 } 1400 1401 // Private method to reset an individual target logger. 1402 private void resetLogger(Logger logger) { 1403 // Close all the Logger handlers. 1404 closeHandlers(logger); 1405 1406 // Reset Logger level 1407 String name = logger.getName(); 1408 if (name != null && name.equals("")) { 1409 // This is the root logger. 1410 logger.setLevel(defaultLevel); 1411 } else { 1412 logger.setLevel(null); 1413 } 1414 } 1415 1416 // get a list of whitespace separated classnames from a property. 1417 private String[] parseClassNames(String propertyName) { 1418 String hands = getProperty(propertyName); 1419 if (hands == null) { 1420 return new String[0]; 1421 } 1422 hands = hands.trim(); 1423 int ix = 0; 1424 final List<String> result = new ArrayList<>(); 1425 while (ix < hands.length()) { 1426 int end = ix; 1427 while (end < hands.length()) { 1428 if (Character.isWhitespace(hands.charAt(end))) { 1429 break; 1430 } 1431 if (hands.charAt(end) == ',') { 1432 break; 1433 } 1434 end++; 1435 } 1436 String word = hands.substring(ix, end); 1437 ix = end+1; 1438 word = word.trim(); 1439 if (word.length() == 0) { 1440 continue; 1441 } 1442 result.add(word); 1443 } 1444 return result.toArray(new String[result.size()]); 1445 } 1446 1447 /** 1448 * Reinitialize the logging properties and reread the logging configuration 1449 * from the given stream, which should be in java.util.Properties format. 1450 * Any {@linkplain #addConfigurationListener registered configuration 1451 * listener} will be invoked after the properties are read. 1452 * <p> 1453 * Any log level definitions in the new configuration file will be 1454 * applied using Logger.setLevel(), if the target Logger exists. 1455 * 1456 * @param ins stream to read properties from 1457 * @exception SecurityException if a security manager exists and if 1458 * the caller does not have LoggingPermission("control"). 1459 * @exception IOException if there are problems reading from the stream. 1460 */ 1461 public void readConfiguration(InputStream ins) throws IOException, SecurityException { 1462 checkPermission(); 1463 1464 // We don't want reset() and readConfiguration() to run 1465 // in parallel. 1466 configurationLock.lock(); 1467 try { 1468 if (globalHandlersState == STATE_SHUTDOWN) { 1469 // already in terminal state: don't even bother 1470 // to read the configuration 1471 return; 1472 } 1473 1474 // change state to STATE_READING_CONFIG to signal reset() to not change it 1475 globalHandlersState = STATE_READING_CONFIG; 1476 try { 1477 // reset configuration which leaves globalHandlersState at STATE_READING_CONFIG 1478 // so that while reading configuration, any ongoing logging requests block and 1479 // wait for the outcome (see the end of this try statement) 1480 reset(); 1481 1482 try { 1483 // Load the properties 1484 props.load(ins); 1485 } catch (IllegalArgumentException x) { 1486 // props.load may throw an IllegalArgumentException if the stream 1487 // contains malformed Unicode escape sequences. 1488 // We wrap that in an IOException as readConfiguration is 1489 // specified to throw IOException if there are problems reading 1490 // from the stream. 1491 // Note: new IOException(x.getMessage(), x) allow us to get a more 1492 // concise error message than new IOException(x); 1493 throw new IOException(x.getMessage(), x); 1494 } 1495 1496 // Instantiate new configuration objects. 1497 String names[] = parseClassNames("config"); 1498 1499 for (String word : names) { 1500 try { 1501 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word); 1502 clz.newInstance(); 1503 } catch (Exception ex) { 1504 System.err.println("Can't load config class \"" + word + "\""); 1505 System.err.println("" + ex); 1506 // ex.printStackTrace(); 1507 } 1508 } 1509 1510 // Set levels on any pre-existing loggers, based on the new properties. 1511 setLevelsOnExistingLoggers(); 1512 1513 // Note that we need to reinitialize global handles when 1514 // they are first referenced. 1515 globalHandlersState = STATE_UNINITIALIZED; 1516 } catch (Throwable t) { 1517 // If there were any trouble, then set state to STATE_INITIALIZED 1518 // so that no global handlers reinitialization is performed on not fully 1519 // initialized configuration. 1520 globalHandlersState = STATE_INITIALIZED; 1521 // re-throw 1522 throw t; 1523 } 1524 } finally { 1525 configurationLock.unlock(); 1526 } 1527 1528 // should be called out of lock to avoid dead-lock situations 1529 // when user code is involved 1530 invokeConfigurationListeners(); 1531 } 1532 1533 /** 1534 * Get the value of a logging property. 1535 * The method returns null if the property is not found. 1536 * @param name property name 1537 * @return property value 1538 */ 1539 public String getProperty(String name) { 1540 return props.getProperty(name); 1541 } 1542 1543 // Package private method to get a String property. 1544 // If the property is not defined we return the given 1545 // default value. 1546 String getStringProperty(String name, String defaultValue) { 1547 String val = getProperty(name); 1548 if (val == null) { 1549 return defaultValue; 1550 } 1551 return val.trim(); 1552 } 1553 1554 // Package private method to get an integer property. 1555 // If the property is not defined or cannot be parsed 1556 // we return the given default value. 1557 int getIntProperty(String name, int defaultValue) { 1558 String val = getProperty(name); 1559 if (val == null) { 1560 return defaultValue; 1561 } 1562 try { 1563 return Integer.parseInt(val.trim()); 1564 } catch (Exception ex) { 1565 return defaultValue; 1566 } 1567 } 1568 1569 // Package private method to get a long property. 1570 // If the property is not defined or cannot be parsed 1571 // we return the given default value. 1572 long getLongProperty(String name, long defaultValue) { 1573 String val = getProperty(name); 1574 if (val == null) { 1575 return defaultValue; 1576 } 1577 try { 1578 return Long.parseLong(val.trim()); 1579 } catch (Exception ex) { 1580 return defaultValue; 1581 } 1582 } 1583 1584 // Package private method to get a boolean property. 1585 // If the property is not defined or cannot be parsed 1586 // we return the given default value. 1587 boolean getBooleanProperty(String name, boolean defaultValue) { 1588 String val = getProperty(name); 1589 if (val == null) { 1590 return defaultValue; 1591 } 1592 val = val.toLowerCase(); 1593 if (val.equals("true") || val.equals("1")) { 1594 return true; 1595 } else if (val.equals("false") || val.equals("0")) { 1596 return false; 1597 } 1598 return defaultValue; 1599 } 1600 1601 // Package private method to get a Level property. 1602 // If the property is not defined or cannot be parsed 1603 // we return the given default value. 1604 Level getLevelProperty(String name, Level defaultValue) { 1605 String val = getProperty(name); 1606 if (val == null) { 1607 return defaultValue; 1608 } 1609 Level l = Level.findLevel(val.trim()); 1610 return l != null ? l : defaultValue; 1611 } 1612 1613 // Package private method to get a filter property. 1614 // We return an instance of the class named by the "name" 1615 // property. If the property is not defined or has problems 1616 // we return the defaultValue. 1617 Filter getFilterProperty(String name, Filter defaultValue) { 1618 String val = getProperty(name); 1619 try { 1620 if (val != null) { 1621 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val); 1622 return (Filter) clz.newInstance(); 1623 } 1624 } catch (Exception ex) { 1625 // We got one of a variety of exceptions in creating the 1626 // class or creating an instance. 1627 // Drop through. 1628 } 1629 // We got an exception. Return the defaultValue. 1630 return defaultValue; 1631 } 1632 1633 1634 // Package private method to get a formatter property. 1635 // We return an instance of the class named by the "name" 1636 // property. If the property is not defined or has problems 1637 // we return the defaultValue. 1638 Formatter getFormatterProperty(String name, Formatter defaultValue) { 1639 String val = getProperty(name); 1640 try { 1641 if (val != null) { 1642 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val); 1643 return (Formatter) clz.newInstance(); 1644 } 1645 } catch (Exception ex) { 1646 // We got one of a variety of exceptions in creating the 1647 // class or creating an instance. 1648 // Drop through. 1649 } 1650 // We got an exception. Return the defaultValue. 1651 return defaultValue; 1652 } 1653 1654 // Private method to load the global handlers. 1655 // We do the real work lazily, when the global handlers 1656 // are first used. 1657 private void initializeGlobalHandlers() { 1658 int state = globalHandlersState; 1659 if (state == STATE_INITIALIZED || 1660 state == STATE_SHUTDOWN) { 1661 // Nothing to do: return. 1662 return; 1663 } 1664 1665 // If we have not initialized global handlers yet (or need to 1666 // reinitialize them), lets do it now (this case is indicated by 1667 // globalHandlersState == STATE_UNINITIALIZED). 1668 // If we are in the process of initializing global handlers we 1669 // also need to lock & wait (this case is indicated by 1670 // globalHandlersState == STATE_INITIALIZING). 1671 // If we are in the process of reading configuration we also need to 1672 // wait to see what the outcome will be (this case 1673 // is indicated by globalHandlersState == STATE_READING_CONFIG) 1674 // So in either case we need to wait for the lock. 1675 configurationLock.lock(); 1676 try { 1677 if (globalHandlersState != STATE_UNINITIALIZED) { 1678 return; // recursive call or nothing to do 1679 } 1680 // set globalHandlersState to STATE_INITIALIZING first to avoid 1681 // getting an infinite recursion when loadLoggerHandlers(...) 1682 // is going to call addHandler(...) 1683 globalHandlersState = STATE_INITIALIZING; 1684 try { 1685 loadLoggerHandlers(rootLogger, null, "handlers"); 1686 } finally { 1687 globalHandlersState = STATE_INITIALIZED; 1688 } 1689 } finally { 1690 configurationLock.unlock(); 1691 } 1692 } 1693 1694 static final Permission controlPermission = new LoggingPermission("control", null); 1695 1696 void checkPermission() { 1697 SecurityManager sm = System.getSecurityManager(); 1698 if (sm != null) 1699 sm.checkPermission(controlPermission); 1700 } 1701 1702 /** 1703 * Check that the current context is trusted to modify the logging 1704 * configuration. This requires LoggingPermission("control"). 1705 * <p> 1706 * If the check fails we throw a SecurityException, otherwise 1707 * we return normally. 1708 * 1709 * @exception SecurityException if a security manager exists and if 1710 * the caller does not have LoggingPermission("control"). 1711 */ 1712 public void checkAccess() throws SecurityException { 1713 checkPermission(); 1714 } 1715 1716 // Nested class to represent a node in our tree of named loggers. 1717 private static class LogNode { 1718 HashMap<String,LogNode> children; 1719 LoggerWeakRef loggerRef; 1720 LogNode parent; 1721 final LoggerContext context; 1722 1723 LogNode(LogNode parent, LoggerContext context) { 1724 this.parent = parent; 1725 this.context = context; 1726 } 1727 1728 // Recursive method to walk the tree below a node and set 1729 // a new parent logger. 1730 void walkAndSetParent(Logger parent) { 1731 if (children == null) { 1732 return; 1733 } 1734 for (LogNode node : children.values()) { 1735 LoggerWeakRef ref = node.loggerRef; 1736 Logger logger = (ref == null) ? null : ref.get(); 1737 if (logger == null) { 1738 node.walkAndSetParent(parent); 1739 } else { 1740 doSetParent(logger, parent); 1741 } 1742 } 1743 } 1744 } 1745 1746 // We use a subclass of Logger for the root logger, so 1747 // that we only instantiate the global handlers when they 1748 // are first needed. 1749 private final class RootLogger extends Logger { 1750 private RootLogger() { 1751 // We do not call the protected Logger two args constructor here, 1752 // to avoid calling LogManager.getLogManager() from within the 1753 // RootLogger constructor. 1754 super("", null, null, LogManager.this, true); 1755 } 1756 1757 @Override 1758 public void log(LogRecord record) { 1759 // Make sure that the global handlers have been instantiated. 1760 initializeGlobalHandlers(); 1761 super.log(record); 1762 } 1763 1764 @Override 1765 public void addHandler(Handler h) { 1766 initializeGlobalHandlers(); 1767 super.addHandler(h); 1768 } 1769 1770 @Override 1771 public void removeHandler(Handler h) { 1772 initializeGlobalHandlers(); 1773 super.removeHandler(h); 1774 } 1775 1776 @Override 1777 Handler[] accessCheckedHandlers() { 1778 initializeGlobalHandlers(); 1779 return super.accessCheckedHandlers(); 1780 } 1781 } 1782 1783 1784 // Private method to be called when the configuration has 1785 // changed to apply any level settings to any pre-existing loggers. 1786 private void setLevelsOnExistingLoggers() { 1787 Enumeration<?> enum_ = props.propertyNames(); 1788 while (enum_.hasMoreElements()) { 1789 String key = (String)enum_.nextElement(); 1790 if (!key.endsWith(".level")) { 1791 // Not a level definition. 1792 continue; 1793 } 1794 int ix = key.length() - 6; 1795 String name = key.substring(0, ix); 1796 Level level = getLevelProperty(key, null); 1797 if (level == null) { 1798 System.err.println("Bad level value for property: " + key); 1799 continue; 1800 } 1801 for (LoggerContext cx : contexts()) { 1802 Logger l = cx.findLogger(name); 1803 if (l == null) { 1804 continue; 1805 } 1806 l.setLevel(level); 1807 } 1808 } 1809 } 1810 1811 // Management Support 1812 private static LoggingMXBean loggingMXBean = null; 1813 /** 1814 * String representation of the 1815 * {@link javax.management.ObjectName} for the management interface 1816 * for the logging facility. 1817 * 1818 * @see java.lang.management.PlatformLoggingMXBean 1819 * @see java.util.logging.LoggingMXBean 1820 * 1821 * @since 1.5 1822 */ 1823 public final static String LOGGING_MXBEAN_NAME 1824 = "java.util.logging:type=Logging"; 1825 1826 /** 1827 * Returns <tt>LoggingMXBean</tt> for managing loggers. 1828 * An alternative way to manage loggers is through the 1829 * {@link java.lang.management.PlatformLoggingMXBean} interface 1830 * that can be obtained by calling: 1831 * <pre> 1832 * PlatformLoggingMXBean logging = {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class) 1833 * ManagementFactory.getPlatformMXBean}(PlatformLoggingMXBean.class); 1834 * </pre> 1835 * 1836 * @return a {@link LoggingMXBean} object. 1837 * 1838 * @see java.lang.management.PlatformLoggingMXBean 1839 * @since 1.5 1840 */ 1841 public static synchronized LoggingMXBean getLoggingMXBean() { 1842 if (loggingMXBean == null) { 1843 loggingMXBean = new Logging(); 1844 } 1845 return loggingMXBean; 1846 } 1847 1848 /** 1849 * Adds a configuration listener to be invoked each time the logging 1850 * configuration is read. 1851 * If the listener is already registered the method does nothing. 1852 * <p> 1853 * The listener is invoked with privileges that are restricted by the 1854 * calling context of this method. 1855 * The order in which the listeners are invoked is unspecified. 1856 * <p> 1857 * It is recommended that listeners do not throw errors or exceptions. 1858 * 1859 * If a listener terminates with an uncaught error or exception then 1860 * the first exception will be propagated to the caller of 1861 * {@link #readConfiguration()} (or {@link #readConfiguration(java.io.InputStream)}) 1862 * after all listeners have been invoked. 1863 * 1864 * @implNote If more than one listener terminates with an uncaught error or 1865 * exception, an implementation may record the additional errors or 1866 * exceptions as {@linkplain Throwable#addSuppressed(java.lang.Throwable) 1867 * suppressed exceptions}. 1868 * 1869 * @param listener A configuration listener that will be invoked after the 1870 * configuration changed. 1871 * @return This LogManager. 1872 * @throws SecurityException if a security manager exists and if the 1873 * caller does not have LoggingPermission("control"). 1874 * @throws NullPointerException if the listener is null. 1875 * 1876 * @since 1.9 1877 */ 1878 public LogManager addConfigurationListener(Runnable listener) { 1879 final Runnable r = Objects.requireNonNull(listener); 1880 checkPermission(); 1881 final SecurityManager sm = System.getSecurityManager(); 1882 final AccessControlContext acc = 1883 sm == null ? null : AccessController.getContext(); 1884 final PrivilegedAction<Void> pa = 1885 acc == null ? null : () -> { r.run() ; return null; }; 1886 final Runnable pr = 1887 acc == null ? r : () -> AccessController.doPrivileged(pa, acc); 1888 // Will do nothing if already registered. 1889 listeners.putIfAbsent(r, pr); 1890 return this; 1891 } 1892 1893 /** 1894 * Removes a previously registered configuration listener. 1895 * 1896 * Returns silently if the listener is not found. 1897 * 1898 * @param listener the configuration listener to remove. 1899 * @throws NullPointerException if the listener is null. 1900 * @throws SecurityException if a security manager exists and if the 1901 * caller does not have LoggingPermission("control"). 1902 * 1903 * @since 1.9 1904 */ 1905 public void removeConfigurationListener(Runnable listener) { 1906 final Runnable key = Objects.requireNonNull(listener); 1907 checkPermission(); 1908 listeners.remove(key); 1909 } 1910 1911 private void invokeConfigurationListeners() { 1912 Throwable t = null; 1913 1914 // We're using an IdentityHashMap because we want to compare 1915 // keys using identity (==). 1916 // We don't want to loop within a block synchronized on 'listeners' 1917 // to avoid invoking listeners from yet another synchronized block. 1918 // So we're taking a snapshot of the values list to avoid the risk of 1919 // ConcurrentModificationException while looping. 1920 // 1921 for (Runnable c : listeners.values().toArray(new Runnable[0])) { 1922 try { 1923 c.run(); 1924 } catch (ThreadDeath death) { 1925 throw death; 1926 } catch (Error | RuntimeException x) { 1927 if (t == null) t = x; 1928 else t.addSuppressed(x); 1929 } 1930 } 1931 // Listeners are not supposed to throw exceptions, but if that 1932 // happens, we will rethrow the first error or exception that is raised 1933 // after all listeners have been invoked. 1934 if (t instanceof Error) throw (Error)t; 1935 if (t instanceof RuntimeException) throw (RuntimeException)t; 1936 } 1937 1938 }