src/share/classes/java/util/logging/LogManager.java

Print this page




 129  * "a.b1" and a.b2" are peers.
 130  * <p>
 131  * All properties whose names end with ".level" are assumed to define
 132  * log levels for Loggers.  Thus "foo.level" defines a log level for
 133  * the logger called "foo" and (recursively) for any of its children
 134  * in the naming hierarchy.  Log Levels are applied in the order they
 135  * are defined in the properties file.  Thus level settings for child
 136  * nodes in the tree should come after settings for their parents.
 137  * The property name ".level" can be used to set the level for the
 138  * root of the tree.
 139  * <p>
 140  * All methods on the LogManager object are multi-thread safe.
 141  *
 142  * @since 1.4
 143 */
 144 
 145 public class LogManager {
 146     // The global LogManager object
 147     private static final LogManager manager;
 148 
 149     private Properties props = new Properties();







 150     private final static Level defaultLevel = Level.INFO;
 151 
 152     // The map of the registered listeners. The map value is the registration
 153     // count to allow for cases where the same listener is registered many times.
 154     private final Map<Object,Integer> listenerMap = new HashMap<>();
 155 
 156     // LoggerContext for system loggers and user loggers
 157     private final LoggerContext systemContext = new SystemLoggerContext();
 158     private final LoggerContext userContext = new LoggerContext();
 159     // non final field - make it volatile to make sure that other threads
 160     // will see the new value once ensureLogManagerInitialized() has finished
 161     // executing.
 162     private volatile Logger rootLogger;
 163     // Have we done the primordial reading of the configuration file?
 164     // (Must be done after a suitable amount of java.lang.System
 165     // initialization has been done)
 166     private volatile boolean readPrimordialConfiguration;
 167     // Have we initialized global (root) handlers yet?
 168     // This gets set to false in readConfiguration
 169     private boolean initializedGlobalHandlers = true;


 653             if (requiresDefaultLoggers()) {
 654                 // Ensure that the root and global loggers are set.
 655                 ensureDefaultLogger(getRootLogger());
 656                 ensureDefaultLogger(getGlobalLogger());
 657             }
 658         }
 659 
 660 
 661         synchronized Logger findLogger(String name) {
 662             // ensure that this context is properly initialized before
 663             // looking for loggers.
 664             ensureInitialized();
 665             LoggerWeakRef ref = namedLoggers.get(name);
 666             if (ref == null) {
 667                 return null;
 668             }
 669             Logger logger = ref.get();
 670             if (logger == null) {
 671                 // Hashtable holds stale weak reference
 672                 // to a logger which has been GC-ed.
 673                 removeLogger(name);
 674             }
 675             return logger;
 676         }
 677 
 678         // This method is called before adding a logger to the
 679         // context.
 680         // 'logger' is the context that will be added.
 681         // This method will ensure that the defaults loggers are added
 682         // before adding 'logger'.
 683         //
 684         private void ensureAllDefaultLoggers(Logger logger) {
 685             if (requiresDefaultLoggers()) {
 686                 final String name = logger.getName();
 687                 if (!name.isEmpty()) {
 688                     ensureDefaultLogger(getRootLogger());
 689                     if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
 690                         ensureDefaultLogger(getGlobalLogger());
 691                     }
 692                 }
 693             }


 739             // addDefaultLoggersIfNeeded will be false: we don't want to
 740             // call ensureAllDefaultLoggers again.
 741             //
 742             // Note: addDefaultLoggersIfNeeded can also be false when
 743             //       requiresDefaultLoggers is false - since calling
 744             //       ensureAllDefaultLoggers would have no effect in this case.
 745             if (addDefaultLoggersIfNeeded) {
 746                 ensureAllDefaultLoggers(logger);
 747             }
 748 
 749             final String name = logger.getName();
 750             if (name == null) {
 751                 throw new NullPointerException();
 752             }
 753             LoggerWeakRef ref = namedLoggers.get(name);
 754             if (ref != null) {
 755                 if (ref.get() == null) {
 756                     // It's possible that the Logger was GC'ed after a
 757                     // drainLoggerRefQueueBounded() call above so allow
 758                     // a new one to be registered.
 759                     removeLogger(name);
 760                 } else {
 761                     // We already have a registered logger with the given name.
 762                     return false;
 763                 }
 764             }
 765 
 766             // We're adding a new logger.
 767             // Note that we are creating a weak reference here.
 768             final LogManager owner = getOwner();
 769             logger.setLogManager(owner);
 770             ref = owner.new LoggerWeakRef(logger);
 771             namedLoggers.put(name, ref);
 772 
 773             // Apply any initial level defined for the new logger, unless
 774             // the logger's level is already initialized
 775             Level level = owner.getLevelProperty(name + ".level", null);
 776             if (level != null && !logger.isLevelInitialized()) {
 777                 doSetLevel(logger, level);
 778             }
 779 


 791                 LoggerWeakRef nodeRef = nodep.loggerRef;
 792                 if (nodeRef != null) {
 793                     parent = nodeRef.get();
 794                     if (parent != null) {
 795                         break;
 796                     }
 797                 }
 798                 nodep = nodep.parent;
 799             }
 800 
 801             if (parent != null) {
 802                 doSetParent(logger, parent);
 803             }
 804             // Walk over the children and tell them we are their new parent.
 805             node.walkAndSetParent(logger);
 806             // new LogNode is ready so tell the LoggerWeakRef about it
 807             ref.setNode(node);
 808             return true;
 809         }
 810 
 811         // note: all calls to removeLogger are synchronized on LogManager's
 812         // intrinsic lock
 813         void removeLogger(String name) {
 814             namedLoggers.remove(name);
 815         }
 816 
 817         synchronized Enumeration<String> getLoggerNames() {
 818             // ensure that this context is properly initialized before
 819             // returning logger names.
 820             ensureInitialized();
 821             return namedLoggers.keys();
 822         }
 823 
 824         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
 825         // parents have levels or handlers defined, make sure they are instantiated.
 826         private void processParentHandlers(final Logger logger, final String name) {
 827             final LogManager owner = getOwner();
 828             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 829                 @Override
 830                 public Void run() {
 831                     if (logger != owner.rootLogger) {
 832                         boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
 833                         if (!useParent) {
 834                             logger.setUseParentHandlers(false);


 976     //     - has weak references to all named Loggers
 977     //     - namedLoggers keeps the LoggerWeakRef objects for the named
 978     //       Loggers around until we can deal with the book keeping for
 979     //       the named Logger that is being GC'ed.
 980     // LogManager.LogNode.loggerRef
 981     //     - has a weak reference to a named Logger
 982     //     - the LogNode will also keep the LoggerWeakRef objects for
 983     //       the named Loggers around; currently LogNodes never go away.
 984     // Logger.kids
 985     //     - has a weak reference to each direct child Logger; this
 986     //       includes anonymous and named Loggers
 987     //     - anonymous Loggers are always children of the rootLogger
 988     //       which is a strong reference; rootLogger.kids keeps the
 989     //       LoggerWeakRef objects for the anonymous Loggers around
 990     //       until we can deal with the book keeping.
 991     //
 992     final class LoggerWeakRef extends WeakReference<Logger> {
 993         private String                name;       // for namedLoggers cleanup
 994         private LogNode               node;       // for loggerRef cleanup
 995         private WeakReference<Logger> parentRef;  // for kids cleanup

 996 
 997         LoggerWeakRef(Logger logger) {
 998             super(logger, loggerRefQueue);
 999 
1000             name = logger.getName();  // save for namedLoggers cleanup
1001         }
1002 
1003         // dispose of this LoggerWeakRef object
1004         void dispose() {
1005             if (node != null) {


























1006                 // if we have a LogNode, then we were a named Logger
1007                 // so clear namedLoggers weak ref to us
1008                 node.context.removeLogger(name);
1009                 name = null;  // clear our ref to the Logger's name
1010 
1011                 node.loggerRef = null;  // clear LogNode's weak ref to us




1012                 node = null;            // clear our ref to LogNode
1013             }

1014 
1015             if (parentRef != null) {
1016                 // this LoggerWeakRef has or had a parent Logger
1017                 Logger parent = parentRef.get();
1018                 if (parent != null) {
1019                     // the parent Logger is still there so clear the
1020                     // parent Logger's weak ref to us
1021                     parent.removeChildLogger(this);
1022                 }
1023                 parentRef = null;  // clear our weak ref to the parent Logger
1024             }
1025         }
1026 
1027         // set the node field to the specified value
1028         void setNode(LogNode node) {
1029             this.node = node;
1030         }
1031 
1032         // set the parentRef field to the specified value
1033         void setParentRef(WeakReference<Logger> parentRef) {


1045     // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
1046     // us about a 50/50 mix in increased weak ref counts versus
1047     // decreased weak ref counts in the AnonLoggerWeakRefLeak test.
1048     // Here are stats for cleaning up sets of 400 anonymous Loggers:
1049     //   - test duration 1 minute
1050     //   - sample size of 125 sets of 400
1051     //   - average: 1.99 ms
1052     //   - minimum: 0.57 ms
1053     //   - maximum: 25.3 ms
1054     //
1055     // The same config gives us a better decreased weak ref count
1056     // than increased weak ref count in the LoggerWeakRefLeak test.
1057     // Here are stats for cleaning up sets of 400 named Loggers:
1058     //   - test duration 2 minutes
1059     //   - sample size of 506 sets of 400
1060     //   - average: 0.57 ms
1061     //   - minimum: 0.02 ms
1062     //   - maximum: 10.9 ms
1063     //
1064     private final static int MAX_ITERATIONS = 400;
1065     final synchronized void drainLoggerRefQueueBounded() {
1066         for (int i = 0; i < MAX_ITERATIONS; i++) {
1067             if (loggerRefQueue == null) {
1068                 // haven't finished loading LogManager yet
1069                 break;
1070             }
1071 
1072             LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll();
1073             if (ref == null) {
1074                 break;
1075             }
1076             // a Logger object has been GC'ed so clean it up
1077             ref.dispose();
1078         }
1079     }
1080 
1081     /**
1082      * Add a named logger.  This does nothing and returns false if a logger
1083      * with the same name is already registered.
1084      * <p>
1085      * The Logger factory methods call this method to register each




 129  * "a.b1" and a.b2" are peers.
 130  * <p>
 131  * All properties whose names end with ".level" are assumed to define
 132  * log levels for Loggers.  Thus "foo.level" defines a log level for
 133  * the logger called "foo" and (recursively) for any of its children
 134  * in the naming hierarchy.  Log Levels are applied in the order they
 135  * are defined in the properties file.  Thus level settings for child
 136  * nodes in the tree should come after settings for their parents.
 137  * The property name ".level" can be used to set the level for the
 138  * root of the tree.
 139  * <p>
 140  * All methods on the LogManager object are multi-thread safe.
 141  *
 142  * @since 1.4
 143 */
 144 
 145 public class LogManager {
 146     // The global LogManager object
 147     private static final LogManager manager;
 148 
 149     // 'props' is assigned within a lock but accessed without it.
 150     // Declaring it volatile makes sure that another thread will not
 151     // be able to see a partially constructed 'props' object.
 152     // (seeing a partially constructed 'props' object can result in
 153     // NPE being thrown in Hashtable.get(), because it leaves the door
 154     // open for props.getProperties() to be called before the construcor
 155     // of Hashtable is actually completed).
 156     private volatile Properties props = new Properties();
 157     private final static Level defaultLevel = Level.INFO;
 158 
 159     // The map of the registered listeners. The map value is the registration
 160     // count to allow for cases where the same listener is registered many times.
 161     private final Map<Object,Integer> listenerMap = new HashMap<>();
 162 
 163     // LoggerContext for system loggers and user loggers
 164     private final LoggerContext systemContext = new SystemLoggerContext();
 165     private final LoggerContext userContext = new LoggerContext();
 166     // non final field - make it volatile to make sure that other threads
 167     // will see the new value once ensureLogManagerInitialized() has finished
 168     // executing.
 169     private volatile Logger rootLogger;
 170     // Have we done the primordial reading of the configuration file?
 171     // (Must be done after a suitable amount of java.lang.System
 172     // initialization has been done)
 173     private volatile boolean readPrimordialConfiguration;
 174     // Have we initialized global (root) handlers yet?
 175     // This gets set to false in readConfiguration
 176     private boolean initializedGlobalHandlers = true;


 660             if (requiresDefaultLoggers()) {
 661                 // Ensure that the root and global loggers are set.
 662                 ensureDefaultLogger(getRootLogger());
 663                 ensureDefaultLogger(getGlobalLogger());
 664             }
 665         }
 666 
 667 
 668         synchronized Logger findLogger(String name) {
 669             // ensure that this context is properly initialized before
 670             // looking for loggers.
 671             ensureInitialized();
 672             LoggerWeakRef ref = namedLoggers.get(name);
 673             if (ref == null) {
 674                 return null;
 675             }
 676             Logger logger = ref.get();
 677             if (logger == null) {
 678                 // Hashtable holds stale weak reference
 679                 // to a logger which has been GC-ed.
 680                 ref.dispose();
 681             }
 682             return logger;
 683         }
 684 
 685         // This method is called before adding a logger to the
 686         // context.
 687         // 'logger' is the context that will be added.
 688         // This method will ensure that the defaults loggers are added
 689         // before adding 'logger'.
 690         //
 691         private void ensureAllDefaultLoggers(Logger logger) {
 692             if (requiresDefaultLoggers()) {
 693                 final String name = logger.getName();
 694                 if (!name.isEmpty()) {
 695                     ensureDefaultLogger(getRootLogger());
 696                     if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
 697                         ensureDefaultLogger(getGlobalLogger());
 698                     }
 699                 }
 700             }


 746             // addDefaultLoggersIfNeeded will be false: we don't want to
 747             // call ensureAllDefaultLoggers again.
 748             //
 749             // Note: addDefaultLoggersIfNeeded can also be false when
 750             //       requiresDefaultLoggers is false - since calling
 751             //       ensureAllDefaultLoggers would have no effect in this case.
 752             if (addDefaultLoggersIfNeeded) {
 753                 ensureAllDefaultLoggers(logger);
 754             }
 755 
 756             final String name = logger.getName();
 757             if (name == null) {
 758                 throw new NullPointerException();
 759             }
 760             LoggerWeakRef ref = namedLoggers.get(name);
 761             if (ref != null) {
 762                 if (ref.get() == null) {
 763                     // It's possible that the Logger was GC'ed after a
 764                     // drainLoggerRefQueueBounded() call above so allow
 765                     // a new one to be registered.
 766                     ref.dispose();
 767                 } else {
 768                     // We already have a registered logger with the given name.
 769                     return false;
 770                 }
 771             }
 772 
 773             // We're adding a new logger.
 774             // Note that we are creating a weak reference here.
 775             final LogManager owner = getOwner();
 776             logger.setLogManager(owner);
 777             ref = owner.new LoggerWeakRef(logger);
 778             namedLoggers.put(name, ref);
 779 
 780             // Apply any initial level defined for the new logger, unless
 781             // the logger's level is already initialized
 782             Level level = owner.getLevelProperty(name + ".level", null);
 783             if (level != null && !logger.isLevelInitialized()) {
 784                 doSetLevel(logger, level);
 785             }
 786 


 798                 LoggerWeakRef nodeRef = nodep.loggerRef;
 799                 if (nodeRef != null) {
 800                     parent = nodeRef.get();
 801                     if (parent != null) {
 802                         break;
 803                     }
 804                 }
 805                 nodep = nodep.parent;
 806             }
 807 
 808             if (parent != null) {
 809                 doSetParent(logger, parent);
 810             }
 811             // Walk over the children and tell them we are their new parent.
 812             node.walkAndSetParent(logger);
 813             // new LogNode is ready so tell the LoggerWeakRef about it
 814             ref.setNode(node);
 815             return true;
 816         }
 817 
 818         synchronized void removeLoggerRef(String name, LoggerWeakRef ref) {
 819             namedLoggers.remove(name, ref);


 820         }
 821 
 822         synchronized Enumeration<String> getLoggerNames() {
 823             // ensure that this context is properly initialized before
 824             // returning logger names.
 825             ensureInitialized();
 826             return namedLoggers.keys();
 827         }
 828 
 829         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
 830         // parents have levels or handlers defined, make sure they are instantiated.
 831         private void processParentHandlers(final Logger logger, final String name) {
 832             final LogManager owner = getOwner();
 833             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 834                 @Override
 835                 public Void run() {
 836                     if (logger != owner.rootLogger) {
 837                         boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
 838                         if (!useParent) {
 839                             logger.setUseParentHandlers(false);


 981     //     - has weak references to all named Loggers
 982     //     - namedLoggers keeps the LoggerWeakRef objects for the named
 983     //       Loggers around until we can deal with the book keeping for
 984     //       the named Logger that is being GC'ed.
 985     // LogManager.LogNode.loggerRef
 986     //     - has a weak reference to a named Logger
 987     //     - the LogNode will also keep the LoggerWeakRef objects for
 988     //       the named Loggers around; currently LogNodes never go away.
 989     // Logger.kids
 990     //     - has a weak reference to each direct child Logger; this
 991     //       includes anonymous and named Loggers
 992     //     - anonymous Loggers are always children of the rootLogger
 993     //       which is a strong reference; rootLogger.kids keeps the
 994     //       LoggerWeakRef objects for the anonymous Loggers around
 995     //       until we can deal with the book keeping.
 996     //
 997     final class LoggerWeakRef extends WeakReference<Logger> {
 998         private String                name;       // for namedLoggers cleanup
 999         private LogNode               node;       // for loggerRef cleanup
1000         private WeakReference<Logger> parentRef;  // for kids cleanup
1001         private boolean disposed = false;         // avoid calling dispose twice
1002 
1003         LoggerWeakRef(Logger logger) {
1004             super(logger, loggerRefQueue);
1005 
1006             name = logger.getName();  // save for namedLoggers cleanup
1007         }
1008 
1009         // dispose of this LoggerWeakRef object
1010         void dispose() {
1011             // Avoid calling dispose twice. When a Logger is gc'ed, its
1012             // LoggerWeakRef will be enqueued.
1013             // However, a new logger of the same name may be added (or looked
1014             // up) before the queue is drained. When that happens, dispose()
1015             // will be called by addLocalLogger() or findLogger().
1016             // Later when the queue is drained, dispose() will be called again
1017             // for the same LoggerWeakRef. Marking LoggerWeakRef as disposed
1018             // avoids processing the data twice (even though the code should
1019             // now be reentrant).
1020             synchronized(this) {
1021                 // Note to maintainers:
1022                 // Be careful not to call any method that tries to acquire
1023                 // another lock from within this block - as this would surely
1024                 // lead to deadlocks, given that dispose() can be called by
1025                 // multiple threads, and from within different synchronized
1026                 // methods/blocks.
1027                 if (disposed) return;
1028                 disposed = true;
1029             }
1030 
1031             final LogNode n = node;
1032             if (n != null) {
1033                 // n.loggerRef can only be safely modified from within
1034                 // a lock on LoggerContext. removeLoggerRef is already
1035                 // synchronized on LoggerContext so calling
1036                 // n.context.removeLoggerRef from within this lock is safe.
1037                 synchronized (n.context) {
1038                     // if we have a LogNode, then we were a named Logger
1039                     // so clear namedLoggers weak ref to us
1040                     n.context.removeLoggerRef(name, this);
1041                     name = null;  // clear our ref to the Logger's name
1042 
1043                     // LogNode may have been reused - so only clear
1044                     // LogNode.loggerRef if LogNode.loggerRef == this
1045                     if (n.loggerRef == this) {
1046                         n.loggerRef = null;  // clear LogNode's weak ref to us
1047                     }
1048                     node = null;            // clear our ref to LogNode
1049                 }
1050              }
1051 
1052             if (parentRef != null) {
1053                 // this LoggerWeakRef has or had a parent Logger
1054                 Logger parent = parentRef.get();
1055                 if (parent != null) {
1056                     // the parent Logger is still there so clear the
1057                     // parent Logger's weak ref to us
1058                     parent.removeChildLogger(this);
1059                 }
1060                 parentRef = null;  // clear our weak ref to the parent Logger
1061             }
1062         }
1063 
1064         // set the node field to the specified value
1065         void setNode(LogNode node) {
1066             this.node = node;
1067         }
1068 
1069         // set the parentRef field to the specified value
1070         void setParentRef(WeakReference<Logger> parentRef) {


1082     // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
1083     // us about a 50/50 mix in increased weak ref counts versus
1084     // decreased weak ref counts in the AnonLoggerWeakRefLeak test.
1085     // Here are stats for cleaning up sets of 400 anonymous Loggers:
1086     //   - test duration 1 minute
1087     //   - sample size of 125 sets of 400
1088     //   - average: 1.99 ms
1089     //   - minimum: 0.57 ms
1090     //   - maximum: 25.3 ms
1091     //
1092     // The same config gives us a better decreased weak ref count
1093     // than increased weak ref count in the LoggerWeakRefLeak test.
1094     // Here are stats for cleaning up sets of 400 named Loggers:
1095     //   - test duration 2 minutes
1096     //   - sample size of 506 sets of 400
1097     //   - average: 0.57 ms
1098     //   - minimum: 0.02 ms
1099     //   - maximum: 10.9 ms
1100     //
1101     private final static int MAX_ITERATIONS = 400;
1102     final void drainLoggerRefQueueBounded() {
1103         for (int i = 0; i < MAX_ITERATIONS; i++) {
1104             if (loggerRefQueue == null) {
1105                 // haven't finished loading LogManager yet
1106                 break;
1107             }
1108 
1109             LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll();
1110             if (ref == null) {
1111                 break;
1112             }
1113             // a Logger object has been GC'ed so clean it up
1114             ref.dispose();
1115         }
1116     }
1117 
1118     /**
1119      * Add a named logger.  This does nothing and returns false if a logger
1120      * with the same name is already registered.
1121      * <p>
1122      * The Logger factory methods call this method to register each