001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.jul; 018 019import java.util.Collections; 020import java.util.Enumeration; 021import java.util.HashSet; 022import java.util.Set; 023import java.util.logging.Logger; 024 025import org.apache.logging.log4j.LoggingException; 026import org.apache.logging.log4j.status.StatusLogger; 027import org.apache.logging.log4j.util.LoaderUtil; 028import org.apache.logging.log4j.util.PropertiesUtil; 029 030/** 031 * Log4j implementation of {@link java.util.logging.LogManager}. Note that the system property 032 * {@code java.util.logging.manager} must be set to {@code org.apache.logging.log4j.jul.LogManager} in order to use 033 * this adaptor. This LogManager requires the {@code log4j-api} library to be available. If {@code log4j-core} is 034 * also available, then more features of {@link java.util.logging.Logger} are supported. 035 * 036 * <p>To override the default {@link AbstractLoggerAdapter} that is used, specify the Log4j property 037 * {@code log4j.jul.LoggerAdapter} and set it to the fully qualified class name of a custom 038 * implementation. All implementations must have a default constructor.</p> 039 * 040 * @since 2.1 041 */ 042public class LogManager extends java.util.logging.LogManager { 043 044 private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger(); 045 private final AbstractLoggerAdapter loggerAdapter; 046 // Contains the set of logger names that are actively being requested using getLogger. 047 private final ThreadLocal<Set<String>> recursive = ThreadLocal.withInitial(HashSet::new); 048 049 public LogManager() { 050 AbstractLoggerAdapter adapter = null; 051 final String overrideAdaptorClassName = 052 PropertiesUtil.getProperties().getStringProperty(Constants.LOGGER_ADAPTOR_PROPERTY); 053 if (overrideAdaptorClassName != null) { 054 try { 055 LOGGER.info("Trying to use LoggerAdaptor [{}] specified by Log4j property.", overrideAdaptorClassName); 056 adapter = LoaderUtil.newCheckedInstanceOf(overrideAdaptorClassName, AbstractLoggerAdapter.class); 057 } catch (final Exception e) { 058 LOGGER.error("Specified LoggerAdapter [{}] is incompatible.", overrideAdaptorClassName, e); 059 } 060 } 061 if (adapter == null) { 062 // default adapter 063 String adapterClassName; 064 try { 065 // find out if log4j-core is available 066 LoaderUtil.loadClass(Constants.CORE_LOGGER_CLASS_NAME); 067 adapterClassName = Constants.CORE_LOGGER_ADAPTER_CLASS_NAME; 068 } catch (final ClassNotFoundException ignored) { 069 adapterClassName = Constants.API_LOGGER_ADAPTER_CLASS_NAME; 070 } 071 LOGGER.debug("Attempting to use {}", adapterClassName); 072 try { 073 adapter = LoaderUtil.newCheckedInstanceOf(adapterClassName, AbstractLoggerAdapter.class); 074 } catch (final Exception e) { 075 throw LOGGER.throwing(new LoggingException(e)); 076 } 077 } 078 loggerAdapter = adapter; 079 LOGGER.info("Registered Log4j as the java.util.logging.LogManager."); 080 } 081 082 @Override 083 public boolean addLogger(final Logger logger) { 084 // in order to prevent non-bridged loggers from being registered, we always return false to indicate that 085 // the named logger should be obtained through getLogger(name) 086 return false; 087 } 088 089 @Override 090 public Logger getLogger(final String name) { 091 LOGGER.trace("Call to LogManager.getLogger({})", name); 092 Set<String> activeRequests = recursive.get(); 093 if (activeRequests.add(name)) { 094 try { 095 return loggerAdapter.getLogger(name); 096 } finally { 097 activeRequests.remove(name); 098 } 099 } 100 LOGGER.warn("Recursive call to getLogger for {} ignored.", name); 101 return new NoOpLogger(name); 102 } 103 104 @Override 105 public Enumeration<String> getLoggerNames() { 106 return Collections.enumeration(loggerAdapter.getLoggersInContext(loggerAdapter.getContext()).keySet()); 107 } 108 109}