org.apache.openejb.util.Logger Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.openejb.util;
import org.apache.openejb.loader.IO;
import org.apache.openejb.loader.SystemInstance;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
public class Logger {
private static final String SUFFIX = ".Messages";
private static final String OPENEJB = "org.apache.tomee";
private static LogStreamFactory logStreamFactory; // TODO: make it resettable
// don't return the instance since it needs to stay private but export which one is used to allow integration with other libs (as tomcat ;))
@SuppressWarnings("UnusedDeclaration")
public static String delegateClass() {
if (logStreamFactory == null) {
throw new IllegalStateException("Call this method after having configured the logger");
}
return logStreamFactory.getClass().getName();
}
public static LogStreamFactory unsafeDelegateClass() {
return logStreamFactory;
}
public static synchronized void configure() {
configure(SystemInstance.isInitialized() ? SystemInstance.get().getProperties() : JavaSecurityManagers.getSystemProperties());
}
public static synchronized void configure(final Properties config) {
if (logStreamFactory != null) {
return;
}
//See if user factory has been specified
final String julFqn = JuliLogStreamFactory.class.getName();
String factoryName = config.getProperty("openejb.log.factory",
SystemInstance.isInitialized() ? SystemInstance.get().getOptions().get("openejb.log.factory", julFqn) : julFqn);
if ("jul".equalsIgnoreCase(factoryName) || "juli".equalsIgnoreCase(factoryName)) {
factoryName = JuliLogStreamFactory.class.getName();
} else if ("slf4j".equalsIgnoreCase(factoryName)) {
factoryName = Slf4jLogStreamFactory.class.getName();
} else if ("log4j".equalsIgnoreCase(factoryName)) {
if (exists("org.apache.log4j.Logger")) {
// don't use .class to avoid to force loading since log4j is not mandatory
factoryName = "org.apache.openejb.util.Log4jLogStreamFactory";
} else {
System.out.println("Cannot respect 'openejb.log.factory=log4j' setting as Log4j is not in the classpath.");
}
} else if ("pax".equalsIgnoreCase(factoryName)) {
factoryName = "org.apache.openejb.util.PaxLogStreamFactory";
} else if ("log4j2".equalsIgnoreCase(factoryName)) {
factoryName = "org.apache.openejb.util.Log4j2LogStreamFactory";
}
// we can be called before having SystemInstance so we need this hack to set some specific
// environment
// without changing LogStreamFactory contract
final String[] specialKeys = new String[] { "openejb.jul.forceReload", "openejb.jul.consoleHandlerClazz", "openejb.logger.external" };
final String[] originals = new String[specialKeys.length];
for (int i = 0; i < specialKeys.length; i++) {
originals[i] = JavaSecurityManagers.getSystemProperty(specialKeys[i]);
final String property = config.getProperty(
specialKeys[i],
SystemInstance.isInitialized() ? SystemInstance.get().getOptions().get(specialKeys[i], (String) null) : null);
if (property != null) {
JavaSecurityManagers.setSystemProperty(specialKeys[i], property);
}
}
try {
if (factoryName != null) {
logStreamFactory = createFactory(factoryName);
}
if (isLog4jImplied()) {
logStreamFactory = createFactory("org.apache.openejb.util.Log4jLogStreamFactory");
}
//Fall back -> JUL
if (logStreamFactory == null) {
logStreamFactory = new JuliLogStreamFactory();
}
checkForIgnoredLog4jConfig();
} finally {
for (int i = 0; i < specialKeys.length; i++) {
if (originals[i] == null) {
JavaSecurityManagers.removeSystemProperty(specialKeys[i]);
} else {
JavaSecurityManagers.setSystemProperty(specialKeys[i], originals[i]);
}
}
}
}
private static void checkForIgnoredLog4jConfig() {
if (logStreamFactory.getClass().getName().equals("org.apache.openejb.util.Log4jLogStreamFactory")) {
return;
}
try {
final Properties configFile = log4j(loadLoggingProperties());
final Properties systemProperties = log4j(SystemInstance.get().getProperties());
if (configFile.size() == 0 && systemProperties.size() == 0) {
return;
}
if (systemProperties.size() == 1 && "log4j.configurationFile".equals(systemProperties.stringPropertyNames().iterator().next())) {
// not a logger config but the overall config
// since log4j2 uses it too we can't pollute logs with warnings there for that only
return;
}
final LogStream stream = logStreamFactory.createLogStream(LogCategory.OPENEJB);
stream.warn("Log4j not installed. The following properties will be ignored.");
final String format = "Ignored %s property '%s'";
for (final Object key : configFile.keySet()) {
stream.warn(String.format(format, "conf/logging.properties", key));
}
for (final Object key : systemProperties.keySet()) {
stream.warn(String.format(format, "Property overrides", key));
}
} catch (final Throwable e) {
// added strong catch block just in case
// This check is only a convenience
}
}
private static LogStreamFactory createFactory(final String factoryName) {
final Class> factoryClass = load(factoryName);
if (factoryClass == null) {
return null;
}
try {
//Try and use the user specified factory
return (LogStreamFactory) factoryClass.newInstance();
} catch (final Throwable e) {
//Ignore
}
return null;
}
private static Class> load(final String factoryName) {
try {
final ClassLoader classLoader = Logger.class.getClassLoader();
return classLoader.loadClass(factoryName);
} catch (final Throwable e) {
//Ignore
}
try {
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
return contextClassLoader.loadClass(factoryName);
} catch (final Throwable e1) {
//Ignore
}
try {
return Class.forName(factoryName);
} catch (final Throwable e2) {
//Ignore
}
return null;
}
/**
* Computes the parent of a resource name. E.g. if we pass in a key of
* a.b.c, it returns the value a.b
*/
private static final Computable heirarchyResolver = new Computable() {
@Override
public String compute(final String key) throws InterruptedException {
final int index = key.lastIndexOf('.');
final String parent = key.substring(0, index);
if (parent.contains(OPENEJB)) {
return parent;
}
return null;
}
};
/**
* Simply returns the ResourceBundle for a given baseName
*/
private static final Computable bundleResolver = new Computable() {
@Override
public ResourceBundle compute(final String baseName) throws InterruptedException {
try {
return ResourceBundle.getBundle(baseName + SUFFIX);
} catch (final MissingResourceException e) {
return null;
}
}
};
/**
* Builds a Logger object and returns it
*/
private static final Computable loggerResolver = new Computable() {
@Override
public Logger compute(final LoggerKey args) throws InterruptedException {
return new Logger(args.category, logStreamFactory.createLogStream(args.category), args.baseName);
}
};
/**
* Creates a MessageFormat object for a message and returns it
*/
private static final Computable messageFormatResolver = MessageFormat::new;
/**
* Cache of parent-child relationships between resource names
*/
private static final Computable heirarchyCache = new Memoizer<>(heirarchyResolver);
/**
* Cache of ResourceBundles
*/
private static final Computable bundleCache = new Memoizer<>(bundleResolver);
/**
* Cache of Loggers
*/
private static final Computable loggerCache = new Memoizer<>(loggerResolver);
/**
* Cache of MessageFormats
*/
private static final Computable messageFormatCache = new Memoizer<>(messageFormatResolver);
/**
* Finds a Logger from the cache and returns it. If not found in cache then builds a Logger and returns it.
*
* @param category - The category of the logger
* @param baseName - The baseName for the ResourceBundle
* @return Logger
*/
public static Logger getInstance(final LogCategory category, final String baseName) {
configure();
try {
return loggerCache.compute(new LoggerKey(category, baseName));
} catch (final InterruptedException e) {
// Don't return null here. Just create a new Logger and set it up.
// It will not be stored in the cache, but a later lookup for the
// same Logger would probably end up in the cache
final LogStream logStream = logStreamFactory.createLogStream(category);
return new Logger(category, logStream, baseName);
}
}
private final LogCategory category;
private final LogStream logStream;
private final String baseName;
public Logger(final LogCategory category, final LogStream logStream, final String baseName) {
this.category = category;
this.baseName = baseName;
this.logStream = // tomcat is already async so abuse of it
("true".equals(SystemInstance.get().getProperty("openejb.log.async", "true")) && JavaSecurityManagers.getSystemProperty("catalina.home") == null) ?
new LogStreamAsync(logStream) : logStream;
}
public static Logger getInstance(final LogCategory category, final Class clazz) {
return getInstance(category, packageName(clazz));
}
private static String packageName(final Class clazz) {
final String name = clazz.getName();
return name.substring(0, name.lastIndexOf('.'));
}
private static Boolean isLog4j;
public static boolean isLog4jImplied() {
if (null == isLog4j) {
isLog4j = false;
final List locations = new ArrayList<>();
{
final Properties configFile = log4j(loadLoggingProperties());
final Properties systemProperties = log4j(SystemInstance.get().getProperties());
if (configFile.size() > 0) {
locations.add("conf/logging.properties");
}
if (systemProperties.size() > 0) {
locations.add("Properties overrides");
}
}
if (locations.size() > 0) {
if (exists("org.apache.log4j.Logger")) {
isLog4j = true;
}
}
}
return isLog4j;
}
private static boolean exists(final String s) {
return load(s) != null;
}
private static Properties log4j(final Properties system) {
final Properties properties = new Properties();
for (final Map.Entry
© 2015 - 2025 Weber Informatics LLC | Privacy Policy