jdk/src/share/classes/java/util/logging/LogManager.java
changeset 16105 fe7392acb767
parent 16100 379f48d34516
child 16111 5c5fc1d5bb38
equal deleted inserted replaced
16104:234ab73a1830 16105:fe7392acb767
   156     // count to allow for cases where the same listener is registered many times.
   156     // count to allow for cases where the same listener is registered many times.
   157     private final Map<Object,Integer> listenerMap = new HashMap<>();
   157     private final Map<Object,Integer> listenerMap = new HashMap<>();
   158 
   158 
   159     // LoggerContext for system loggers and user loggers
   159     // LoggerContext for system loggers and user loggers
   160     private final LoggerContext systemContext = new SystemLoggerContext();
   160     private final LoggerContext systemContext = new SystemLoggerContext();
   161     private final LoggerContext userContext = new UserLoggerContext();
   161     private final LoggerContext userContext = new LoggerContext();
   162     private Logger rootLogger;
   162     private Logger rootLogger;
   163 
   163 
   164     // Have we done the primordial reading of the configuration file?
   164     // Have we done the primordial reading of the configuration file?
   165     // (Must be done after a suitable amount of java.lang.System
   165     // (Must be done after a suitable amount of java.lang.System
   166     // initialization has been done)
   166     // initialization has been done)
   194                         manager = new LogManager();
   194                         manager = new LogManager();
   195                     }
   195                     }
   196 
   196 
   197                     // Create and retain Logger for the root of the namespace.
   197                     // Create and retain Logger for the root of the namespace.
   198                     manager.rootLogger = manager.new RootLogger();
   198                     manager.rootLogger = manager.new RootLogger();
   199                     manager.systemContext.addLogger(manager.rootLogger);
   199                     manager.addLogger(manager.rootLogger);
   200                     manager.userContext.addLogger(manager.rootLogger);
   200                     manager.systemContext.addLocalLogger(manager.rootLogger);
   201 
   201 
   202                     // Adding the global Logger. Doing so in the Logger.<clinit>
   202                     // Adding the global Logger. Doing so in the Logger.<clinit>
   203                     // would deadlock with the LogManager.<clinit>.
   203                     // would deadlock with the LogManager.<clinit>.
   204                     Logger.getGlobal().setLogManager(manager);
   204                     Logger.global.setLogManager(manager);
   205                     manager.systemContext.addLogger(Logger.getGlobal());
   205                     manager.addLogger(Logger.global);
   206 
   206 
   207                     // We don't call readConfiguration() here, as we may be running
   207                     // We don't call readConfiguration() here, as we may be running
   208                     // very early in the JVM startup sequence.  Instead readConfiguration
   208                     // very early in the JVM startup sequence.  Instead readConfiguration
   209                     // will be called lazily in getLogManager().
   209                     // will be called lazily in getLogManager().
   210                     return null;
   210                     return null;
   371         }
   371         }
   372     }
   372     }
   373 
   373 
   374     // Returns the LoggerContext for the user code (i.e. application or AppContext).
   374     // Returns the LoggerContext for the user code (i.e. application or AppContext).
   375     // Loggers are isolated from each AppContext.
   375     // Loggers are isolated from each AppContext.
   376     LoggerContext getUserContext() {
   376     private LoggerContext getUserContext() {
   377         LoggerContext context = null;
   377         LoggerContext context = null;
   378 
   378 
   379         SecurityManager sm = System.getSecurityManager();
   379         SecurityManager sm = System.getSecurityManager();
   380         JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
   380         JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
   381         if (sm != null && javaAwtAccess != null) {
   381         if (sm != null && javaAwtAccess != null) {
   392                 context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class);
   392                 context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class);
   393                 if (context == null) {
   393                 if (context == null) {
   394                     if (javaAwtAccess.isMainAppContext()) {
   394                     if (javaAwtAccess.isMainAppContext()) {
   395                         context = userContext;
   395                         context = userContext;
   396                     } else {
   396                     } else {
   397                         context = new UserLoggerContext();
   397                         context = new LoggerContext();
   398                         context.addLogger(manager.rootLogger);
   398                         context.addLocalLogger(manager.rootLogger);
   399                     }
   399                     }
   400                     javaAwtAccess.put(ecx, LoggerContext.class, context);
   400                     javaAwtAccess.put(ecx, LoggerContext.class, context);
   401                 }
   401                 }
   402             }
   402             }
   403         } else {
   403         } else {
   404             context = userContext;
   404             context = userContext;
   405         }
   405         }
   406         return context;
   406         return context;
   407     }
       
   408 
       
   409     LoggerContext getSystemContext() {
       
   410         return systemContext;
       
   411     }
   407     }
   412 
   408 
   413     private List<LoggerContext> contexts() {
   409     private List<LoggerContext> contexts() {
   414         List<LoggerContext> cxs = new ArrayList<>();
   410         List<LoggerContext> cxs = new ArrayList<>();
   415         cxs.add(systemContext);
   411         cxs.add(systemContext);
   416         cxs.add(getUserContext());
   412         cxs.add(getUserContext());
   417         return cxs;
   413         return cxs;
   418     }
   414     }
   419 
   415 
       
   416     // Find or create a specified logger instance. If a logger has
       
   417     // already been created with the given name it is returned.
       
   418     // Otherwise a new logger instance is created and registered
       
   419     // in the LogManager global namespace.
       
   420     // This method will always return a non-null Logger object.
       
   421     // Synchronization is not required here. All synchronization for
       
   422     // adding a new Logger object is handled by addLogger().
       
   423     //
       
   424     // This method must delegate to the LogManager implementation to
       
   425     // add a new Logger or return the one that has been added previously
       
   426     // as a LogManager subclass may override the addLogger, getLogger,
       
   427     // readConfiguration, and other methods.
       
   428     Logger demandLogger(String name, String resourceBundleName) {
       
   429         Logger result = getLogger(name);
       
   430         if (result == null) {
       
   431             // only allocate the new logger once
       
   432             Logger newLogger = new Logger(name, resourceBundleName);
       
   433             do {
       
   434                 if (addLogger(newLogger)) {
       
   435                     // We successfully added the new Logger that we
       
   436                     // created above so return it without refetching.
       
   437                     return newLogger;
       
   438                 }
       
   439 
       
   440                 // We didn't add the new Logger that we created above
       
   441                 // because another thread added a Logger with the same
       
   442                 // name after our null check above and before our call
       
   443                 // to addLogger(). We have to refetch the Logger because
       
   444                 // addLogger() returns a boolean instead of the Logger
       
   445                 // reference itself. However, if the thread that created
       
   446                 // the other Logger is not holding a strong reference to
       
   447                 // the other Logger, then it is possible for the other
       
   448                 // Logger to be GC'ed after we saw it in addLogger() and
       
   449                 // before we can refetch it. If it has been GC'ed then
       
   450                 // we'll just loop around and try again.
       
   451                 result = getLogger(name);
       
   452             } while (result == null);
       
   453         }
       
   454         return result;
       
   455     }
       
   456 
       
   457     Logger demandSystemLogger(String name, String resourceBundleName) {
       
   458         return systemContext.demandLogger(name, resourceBundleName);
       
   459     }
       
   460 
       
   461     // LoggerContext maintains the logger namespace per context.
       
   462     // The default LogManager implementation has one system context and user
       
   463     // context.  The system context is used to maintain the namespace for
       
   464     // all system loggers and is queried by the system code.  If a system logger
       
   465     // doesn't exist in the user context, it'll also be added to the user context.
       
   466     // The user context is queried by the user code and all other loggers are
       
   467     // added in the user context.
   420     static class LoggerContext {
   468     static class LoggerContext {
   421         // Table of named Loggers that maps names to Loggers.
   469         // Table of named Loggers that maps names to Loggers.
   422         private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
   470         private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
   423         // Tree of named Loggers
   471         // Tree of named Loggers
   424         private final LogNode root;
   472         private final LogNode root;
   425 
   473 
   426         private LoggerContext() {
   474         private LoggerContext() {
   427             this.root = new LogNode(null, this);
   475             this.root = new LogNode(null, this);
   428         }
   476         }
   429 
   477 
       
   478         Logger demandLogger(String name, String resourceBundleName) {
       
   479             // a LogManager subclass may have its own implementation to add and
       
   480             // get a Logger.  So delegate to the LogManager to do the work.
       
   481             return manager.demandLogger(name, resourceBundleName);
       
   482         }
       
   483 
   430         synchronized Logger findLogger(String name) {
   484         synchronized Logger findLogger(String name) {
   431             LoggerWeakRef ref = namedLoggers.get(name);
   485             LoggerWeakRef ref = namedLoggers.get(name);
   432             if (ref == null) {
   486             if (ref == null) {
   433                 return null;
   487                 return null;
   434             }
   488             }
   439                 removeLogger(name);
   493                 removeLogger(name);
   440             }
   494             }
   441             return logger;
   495             return logger;
   442         }
   496         }
   443 
   497 
   444         synchronized boolean addLogger(Logger logger) {
   498         // Add a logger to this context.  This method will only set its level
       
   499         // and process parent loggers.  It doesn't set its handlers.
       
   500         synchronized boolean addLocalLogger(Logger logger) {
   445             final String name = logger.getName();
   501             final String name = logger.getName();
   446             if (name == null) {
   502             if (name == null) {
   447                 throw new NullPointerException();
   503                 throw new NullPointerException();
   448             }
   504             }
   449 
   505 
   472             Level level = manager.getLevelProperty(name + ".level", null);
   528             Level level = manager.getLevelProperty(name + ".level", null);
   473             if (level != null) {
   529             if (level != null) {
   474                 doSetLevel(logger, level);
   530                 doSetLevel(logger, level);
   475             }
   531             }
   476 
   532 
   477             // Do we have a per logger handler too?
   533             // instantiation of the handler is done in the LogManager.addLogger
   478             // Note: this will add a 200ms penalty
   534             // implementation as a handler class may be only visible to LogManager
   479             manager.loadLoggerHandlers(logger, name, name + ".handlers");
   535             // subclass for the custom log manager case
   480             processParentHandlers(logger, name);
   536             processParentHandlers(logger, name);
   481 
   537 
   482             // Find the new node and its parent.
   538             // Find the new node and its parent.
   483             LogNode node = getNode(name);
   539             LogNode node = getNode(name);
   484             node.loggerRef = ref;
   540             node.loggerRef = ref;
   511 
   567 
   512         synchronized Enumeration<String> getLoggerNames() {
   568         synchronized Enumeration<String> getLoggerNames() {
   513             return namedLoggers.keys();
   569             return namedLoggers.keys();
   514         }
   570         }
   515 
   571 
   516         Logger demandLogger(String name) {
       
   517             return demandLogger(name, null);
       
   518         }
       
   519 
       
   520         // Find or create a specified logger instance. If a logger has
       
   521         // already been created with the given name it is returned.
       
   522         // Otherwise a new logger instance is created and registered
       
   523         // in the LogManager global namespace.
       
   524 
       
   525         // This method will always return a non-null Logger object.
       
   526         // Synchronization is not required here. All synchronization for
       
   527         // adding a new Logger object is handled by addLogger().
       
   528         Logger demandLogger(String name, String resourceBundleName) {
       
   529             Logger result = findLogger(name);
       
   530             if (result == null) {
       
   531                 // only allocate the new logger once
       
   532                 Logger newLogger = new Logger(name, resourceBundleName);
       
   533                 do {
       
   534                     if (addLogger(newLogger)) {
       
   535                         // We successfully added the new Logger that we
       
   536                         // created above so return it without refetching.
       
   537                         return newLogger;
       
   538                     }
       
   539 
       
   540                     // We didn't add the new Logger that we created above
       
   541                     // because another thread added a Logger with the same
       
   542                     // name after our null check above and before our call
       
   543                     // to addLogger(). We have to refetch the Logger because
       
   544                     // addLogger() returns a boolean instead of the Logger
       
   545                     // reference itself. However, if the thread that created
       
   546                     // the other Logger is not holding a strong reference to
       
   547                     // the other Logger, then it is possible for the other
       
   548                     // Logger to be GC'ed after we saw it in addLogger() and
       
   549                     // before we can refetch it. If it has been GC'ed then
       
   550                     // we'll just loop around and try again.
       
   551                     result = findLogger(name);
       
   552                 } while (result == null);
       
   553             }
       
   554             return result;
       
   555         }
       
   556 
       
   557         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
   572         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
   558         // parents have levels or handlers defined, make sure they are instantiated.
   573         // parents have levels or handlers defined, make sure they are instantiated.
   559         private void processParentHandlers(Logger logger, String name) {
   574         private void processParentHandlers(final Logger logger, final String name) {
       
   575             AccessController.doPrivileged(new PrivilegedAction<Void>() {
       
   576                 public Void run() {
       
   577                     if (logger != manager.rootLogger) {
       
   578                         boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true);
       
   579                         if (!useParent) {
       
   580                             logger.setUseParentHandlers(false);
       
   581                         }
       
   582                     }
       
   583                     return null;
       
   584                 }
       
   585             });
       
   586 
   560             int ix = 1;
   587             int ix = 1;
   561             for (;;) {
   588             for (;;) {
   562                 int ix2 = name.indexOf(".", ix);
   589                 int ix2 = name.indexOf(".", ix);
   563                 if (ix2 < 0) {
   590                 if (ix2 < 0) {
   564                     break;
   591                     break;
   565                 }
   592                 }
   566                 String pname = name.substring(0, ix2);
   593                 String pname = name.substring(0, ix2);
   567 
       
   568                 if (manager.getProperty(pname + ".level") != null ||
   594                 if (manager.getProperty(pname + ".level") != null ||
   569                     manager.getProperty(pname + ".handlers") != null) {
   595                     manager.getProperty(pname + ".handlers") != null) {
   570                     // This pname has a level/handlers definition.
   596                     // This pname has a level/handlers definition.
   571                     // Make sure it exists.
   597                     // Make sure it exists.
   572                     demandLogger(pname);
   598                     demandLogger(pname, null);
   573                 }
   599                 }
   574                 ix = ix2+1;
   600                 ix = ix2+1;
   575             }
   601             }
   576         }
   602         }
   577 
   603 
   605             return node;
   631             return node;
   606         }
   632         }
   607     }
   633     }
   608 
   634 
   609     static class SystemLoggerContext extends LoggerContext {
   635     static class SystemLoggerContext extends LoggerContext {
   610         // Default resource bundle for all system loggers
   636         // Add a system logger in the system context's namespace as well as
   611         Logger demandLogger(String name) {
   637         // in the LogManager's namespace if not exist so that there is only
   612             // default to use the system logger's resource bundle
   638         // one single logger of the given name.  System loggers are visible
   613             return super.demandLogger(name, Logger.SYSTEM_LOGGER_RB_NAME);
   639         // to applications unless a logger of the same name has been added.
   614         }
       
   615     }
       
   616 
       
   617     static class UserLoggerContext extends LoggerContext {
       
   618         /**
       
   619          * Returns a Logger of the given name if there is one registered
       
   620          * in this context.  Otherwise, it will return the one registered
       
   621          * in the system context if there is one.  The returned Logger
       
   622          * instance may be initialized with a different resourceBundleName.
       
   623          * If no such logger exists, a new Logger instance will be created
       
   624          * and registered in this context.
       
   625          */
       
   626         Logger demandLogger(String name, String resourceBundleName) {
   640         Logger demandLogger(String name, String resourceBundleName) {
   627             Logger result = findLogger(name);
   641             Logger result = findLogger(name);
   628             if (result == null) {
   642             if (result == null) {
   629                 // use the system logger if exists; or allocate a new logger.
   643                 // only allocate the new system logger once
   630                 // The system logger is added to the app logger context so that
   644                 Logger newLogger = new Logger(name, resourceBundleName);
   631                 // any child logger created in the app logger context can have
       
   632                 // a system logger as its parent if already exist.
       
   633                 Logger logger = manager.systemContext.findLogger(name);
       
   634                 Logger newLogger =
       
   635                     logger != null ? logger : new Logger(name, resourceBundleName);
       
   636                 do {
   645                 do {
   637                     if (addLogger(newLogger)) {
   646                     if (addLocalLogger(newLogger)) {
   638                         // We successfully added the new Logger that we
   647                         // We successfully added the new Logger that we
   639                         // created above so return it without refetching.
   648                         // created above so return it without refetching.
   640                         return newLogger;
   649                         result = newLogger;
       
   650                     } else {
       
   651                         // We didn't add the new Logger that we created above
       
   652                         // because another thread added a Logger with the same
       
   653                         // name after our null check above and before our call
       
   654                         // to addLogger(). We have to refetch the Logger because
       
   655                         // addLogger() returns a boolean instead of the Logger
       
   656                         // reference itself. However, if the thread that created
       
   657                         // the other Logger is not holding a strong reference to
       
   658                         // the other Logger, then it is possible for the other
       
   659                         // Logger to be GC'ed after we saw it in addLogger() and
       
   660                         // before we can refetch it. If it has been GC'ed then
       
   661                         // we'll just loop around and try again.
       
   662                         result = findLogger(name);
   641                     }
   663                     }
   642 
       
   643                     // We didn't add the new Logger that we created above
       
   644                     // because another thread added a Logger with the same
       
   645                     // name after our null check above and before our call
       
   646                     // to addLogger(). We have to refetch the Logger because
       
   647                     // addLogger() returns a boolean instead of the Logger
       
   648                     // reference itself. However, if the thread that created
       
   649                     // the other Logger is not holding a strong reference to
       
   650                     // the other Logger, then it is possible for the other
       
   651                     // Logger to be GC'ed after we saw it in addLogger() and
       
   652                     // before we can refetch it. If it has been GC'ed then
       
   653                     // we'll just loop around and try again.
       
   654                     result = findLogger(name);
       
   655                 } while (result == null);
   664                 } while (result == null);
       
   665             }
       
   666             // Add the system logger to the LogManager's namespace if not exists
       
   667             // The LogManager will set its handlers via the LogManager.addLogger method.
       
   668             if (!manager.addLogger(result) && result.getHandlers().length == 0) {
       
   669                 // if logger already exists but handlers not set
       
   670                 final Logger l = manager.getLogger(name);
       
   671                 final Logger logger = result;
       
   672                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
       
   673                     public Void run() {
       
   674                         for (Handler hdl : l.getHandlers()) {
       
   675                             logger.addHandler(hdl);
       
   676                         }
       
   677                         return null;
       
   678                     }
       
   679                 });
   656             }
   680             }
   657             return result;
   681             return result;
   658         }
   682         }
   659     }
   683     }
   660 
   684 
   661     // Add new per logger handlers.
   685     // Add new per logger handlers.
   662     // We need to raise privilege here. All our decisions will
   686     // We need to raise privilege here. All our decisions will
   663     // be made based on the logging configuration, which can
   687     // be made based on the logging configuration, which can
   664     // only be modified by trusted code.
   688     // only be modified by trusted code.
   665     private void loadLoggerHandlers(final Logger logger, final String name,
   689     private void loadLoggerHandlers(final Logger logger, final String name,
   666                                     final String handlersPropertyName) {
   690                                     final String handlersPropertyName)
       
   691     {
   667         AccessController.doPrivileged(new PrivilegedAction<Object>() {
   692         AccessController.doPrivileged(new PrivilegedAction<Object>() {
   668             public Object run() {
   693             public Object run() {
   669                 if (logger != rootLogger) {
       
   670                     boolean useParent = getBooleanProperty(name + ".useParentHandlers", true);
       
   671                     if (!useParent) {
       
   672                         logger.setUseParentHandlers(false);
       
   673                     }
       
   674                 }
       
   675 
       
   676                 String names[] = parseClassNames(handlersPropertyName);
   694                 String names[] = parseClassNames(handlersPropertyName);
   677                 for (int i = 0; i < names.length; i++) {
   695                 for (int i = 0; i < names.length; i++) {
   678                     String word = names[i];
   696                     String word = names[i];
   679                     try {
   697                     try {
   680                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
   698                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
   681                         Handler  hdl = (Handler) clz.newInstance();
   699                         Handler hdl = (Handler) clz.newInstance();
   682                         // Check if there is a property defining the
   700                         // Check if there is a property defining the
   683                         // this handler's level.
   701                         // this handler's level.
   684                         String levs = getProperty(word + ".level");
   702                         String levs = getProperty(word + ".level");
   685                         if (levs != null) {
   703                         if (levs != null) {
   686                             Level l = Level.findLevel(levs);
   704                             Level l = Level.findLevel(levs);
   698                         System.err.println("" + ex);
   716                         System.err.println("" + ex);
   699                         ex.printStackTrace();
   717                         ex.printStackTrace();
   700                     }
   718                     }
   701                 }
   719                 }
   702                 return null;
   720                 return null;
   703             }});
   721             }
       
   722         });
   704     }
   723     }
   705 
   724 
   706 
   725 
   707     // loggerRefQueue holds LoggerWeakRef objects for Logger objects
   726     // loggerRefQueue holds LoggerWeakRef objects for Logger objects
   708     // that have been GC'ed.
   727     // that have been GC'ed.
   837     public boolean addLogger(Logger logger) {
   856     public boolean addLogger(Logger logger) {
   838         final String name = logger.getName();
   857         final String name = logger.getName();
   839         if (name == null) {
   858         if (name == null) {
   840             throw new NullPointerException();
   859             throw new NullPointerException();
   841         }
   860         }
   842         if (systemContext.findLogger(name) != null) {
   861         LoggerContext cx = getUserContext();
       
   862         if (cx.addLocalLogger(logger)) {
       
   863             // Do we have a per logger handler too?
       
   864             // Note: this will add a 200ms penalty
       
   865             loadLoggerHandlers(logger, name, name + ".handlers");
       
   866             return true;
       
   867         } else {
   843             return false;
   868             return false;
   844         }
   869         }
   845         return getUserContext().addLogger(logger);
   870     }
   846     }
       
   847 
       
   848 
   871 
   849     // Private method to set a level on a logger.
   872     // Private method to set a level on a logger.
   850     // If necessary, we raise privilege before doing the call.
   873     // If necessary, we raise privilege before doing the call.
   851     private static void doSetLevel(final Logger logger, final Level level) {
   874     private static void doSetLevel(final Logger logger, final Level level) {
   852         SecurityManager sm = System.getSecurityManager();
   875         SecurityManager sm = System.getSecurityManager();
   861             public Object run() {
   884             public Object run() {
   862                 logger.setLevel(level);
   885                 logger.setLevel(level);
   863                 return null;
   886                 return null;
   864             }});
   887             }});
   865     }
   888     }
   866 
       
   867 
       
   868 
   889 
   869     // Private method to set a parent on a logger.
   890     // Private method to set a parent on a logger.
   870     // If necessary, we raise privilege before doing the setParent call.
   891     // If necessary, we raise privilege before doing the setParent call.
   871     private static void doSetParent(final Logger logger, final Logger parent) {
   892     private static void doSetParent(final Logger logger, final Logger parent) {
   872         SecurityManager sm = System.getSecurityManager();
   893         SecurityManager sm = System.getSecurityManager();
   898      * <p>
   919      * <p>
   899      * @param name name of the logger
   920      * @param name name of the logger
   900      * @return  matching logger or null if none is found
   921      * @return  matching logger or null if none is found
   901      */
   922      */
   902     public Logger getLogger(String name) {
   923     public Logger getLogger(String name) {
   903         // return the first logger added
   924         return getUserContext().findLogger(name);
   904         //
       
   905         // once a system logger is added in the system context, no one can
       
   906         // adds a logger with the same name in the global context
       
   907         // (see LogManager.addLogger).  So if there is a logger in the global
       
   908         // context with the same name as one in the system context, it must be
       
   909         // added before the system logger was created.
       
   910         Logger logger = getUserContext().findLogger(name);
       
   911         return logger != null ? logger : systemContext.findLogger(name);
       
   912     }
   925     }
   913 
   926 
   914     /**
   927     /**
   915      * Get an enumeration of known logger names.
   928      * Get an enumeration of known logger names.
   916      * <p>
   929      * <p>
   926      * time since its name was returned by this method.
   939      * time since its name was returned by this method.
   927      * <p>
   940      * <p>
   928      * @return  enumeration of logger name strings
   941      * @return  enumeration of logger name strings
   929      */
   942      */
   930     public Enumeration<String> getLoggerNames() {
   943     public Enumeration<String> getLoggerNames() {
   931         // only return unique names
   944         return getUserContext().getLoggerNames();
   932         Set<String> names = new HashSet<>(Collections.list(systemContext.getLoggerNames()));
       
   933         names.addAll(Collections.list(getUserContext().getLoggerNames()));
       
   934         return Collections.enumeration(names);
       
   935     }
   945     }
   936 
   946 
   937     /**
   947     /**
   938      * Reinitialize the logging properties and reread the logging configuration.
   948      * Reinitialize the logging properties and reread the logging configuration.
   939      * <p>
   949      * <p>
  1327 
  1337 
  1328     // We use a subclass of Logger for the root logger, so
  1338     // We use a subclass of Logger for the root logger, so
  1329     // that we only instantiate the global handlers when they
  1339     // that we only instantiate the global handlers when they
  1330     // are first needed.
  1340     // are first needed.
  1331     private class RootLogger extends Logger {
  1341     private class RootLogger extends Logger {
  1332 
       
  1333         private RootLogger() {
  1342         private RootLogger() {
  1334             super("", null);
  1343             super("", null);
  1335             setLevel(defaultLevel);
  1344             setLevel(defaultLevel);
  1336         }
  1345         }
  1337 
  1346