Repository: logging-log4j2 Updated Branches: refs/heads/master 671f30ba3 -> 92e4b8754
LOG4J2-1917 - Use ServiceLoader to locate implementations. Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/92e4b875 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/92e4b875 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/92e4b875 Branch: refs/heads/master Commit: 92e4b875463e8dc9e4683687d3572969f39b1593 Parents: 671f30b Author: Ralph Goers <[email protected]> Authored: Sun May 21 01:27:57 2017 -0700 Committer: Ralph Goers <[email protected]> Committed: Sun May 21 01:27:57 2017 -0700 ---------------------------------------------------------------------- log4j-api/pom.xml | 23 ++++-- .../org/apache/logging/log4j/spi/Provider.java | 73 +++++++++++++++++--- .../apache/logging/log4j/util/Activator.java | 4 +- .../logging/log4j/util/ClassNamePredicate.java | 45 ------------ .../logging/log4j/util/ClassPredicate.java | 46 ------------ .../apache/logging/log4j/util/ProviderUtil.java | 11 +++ .../log4j/util/StackWalkerStackLocator.java | 63 ----------------- .../logging/log4j/util/ClassNamePredicate.java | 45 ++++++++++++ .../logging/log4j/util/ClassPredicate.java | 46 ++++++++++++ .../log4j/util/StackWalkerStackLocator.java | 63 +++++++++++++++++ .../org/apache/logging/log4j/TestProvider.java | 28 ++++++++ .../META-INF/log4j-provider.properties | 3 - .../org.apache.logging.log4j.spi.Provider | 1 + .../logging/log4j/core/impl/Log4jProvider.java | 28 ++++++++ .../META-INF/log4j-provider.properties | 18 ----- .../org.apache.logging.log4j.spi.Provider | 1 + .../appender/AsyncAppenderNoLocationTest.java | 20 +++++- .../org/apache/logging/slf4j/SLF4JProvider.java | 28 ++++++++ .../META-INF/log4j-provider.properties | 19 ----- .../org.apache.logging.log4j.spi.Provider | 1 + src/changes/changes.xml | 3 + src/site/xdoc/manual/extending.xml | 37 ++++++---- 22 files changed, 378 insertions(+), 228 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/pom.xml ---------------------------------------------------------------------- diff --git a/log4j-api/pom.xml b/log4j-api/pom.xml index bacf907..0b161d6 100644 --- a/log4j-api/pom.xml +++ b/log4j-api/pom.xml @@ -127,6 +127,23 @@ </configuration> </plugin> <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <phase>process-classes</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>src/main/java9</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> + <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <executions> @@ -134,12 +151,6 @@ <id>default-compile</id> <!-- recompile everything for target VM except the module-info.java --> <configuration> - <excludes> - <exclude>module-info.java</exclude> - <exclude>**/util/ClassNamePredicate.java</exclude> - <exclude>**/util/ClassPredicate.java</exclude> - <exclude>**/util/StackWalkerStackLocator.java</exclude> - </excludes> <source>1.7</source> <target>1.7</target> </configuration> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java index 7ed3af5..a50c227 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java @@ -47,7 +47,10 @@ public class Provider { private final Integer priority; private final String className; + private final Class<? extends LoggerContextFactory> loggerContextFactoryClass; private final String threadContextMap; + private final Class<? extends ThreadContextMap> threadContextMapClass; + private final String versions; private final URL url; private final WeakReference<ClassLoader> classLoader; @@ -58,6 +61,36 @@ public class Provider { priority = weight == null ? DEFAULT_PRIORITY : Integer.valueOf(weight); className = props.getProperty(LOGGER_CONTEXT_FACTORY); threadContextMap = props.getProperty(THREAD_CONTEXT_MAP); + loggerContextFactoryClass = null; + threadContextMapClass = null; + versions = null; + } + + public Provider(Integer priority, String versions, + Class<? extends LoggerContextFactory> loggerContextFactoryClass) { + this(priority, versions, loggerContextFactoryClass, null); + } + + + public Provider(Integer priority, String versions, + Class<? extends LoggerContextFactory> loggerContextFactoryClass, + Class<? extends ThreadContextMap> threadContextMapClass) { + this.url = null; + this.classLoader = null; + this.priority = priority; + this.loggerContextFactoryClass = loggerContextFactoryClass; + this.threadContextMapClass = threadContextMapClass; + this.className = null; + this.threadContextMap = null; + this.versions = versions; + } + + /** + * Returns the Log4j API versions supported by the implementation. + * @return A String containing the Log4j versions supported. + */ + public String getVersions() { + return versions; } /** @@ -76,6 +109,9 @@ public class Provider { * @return the class name of a LoggerContextFactory implementation */ public String getClassName() { + if (loggerContextFactoryClass != null) { + return loggerContextFactoryClass.getName(); + } return className; } @@ -85,6 +121,9 @@ public class Provider { * @return the LoggerContextFactory implementation class or {@code null} if there was an error loading it */ public Class<? extends LoggerContextFactory> loadLoggerContextFactory() { + if (loggerContextFactoryClass != null) { + return loggerContextFactoryClass; + } if (className == null) { return null; } @@ -109,6 +148,9 @@ public class Provider { * @return the class name of a ThreadContextMap implementation */ public String getThreadContextMap() { + if (threadContextMapClass != null) { + return threadContextMapClass.getName(); + } return threadContextMap; } @@ -118,6 +160,9 @@ public class Provider { * @return the ThreadContextMap implementation class or {@code null} if there was an error loading it */ public Class<? extends ThreadContextMap> loadThreadContextMap() { + if (threadContextMapClass != null) { + return threadContextMapClass; + } if (threadContextMap == null) { return null; } @@ -147,24 +192,30 @@ public class Provider { @Override public String toString() { - String result = "Provider["; + StringBuilder result = new StringBuilder("Provider["); if (!DEFAULT_PRIORITY.equals(priority)) { - result += "priority=" + priority + ", "; + result.append("priority=").append(priority).append(", "); } if (threadContextMap != null) { - result += "threadContextMap=" + threadContextMap + ", "; + result.append("threadContextMap=").append(threadContextMap).append(", "); + } else if (threadContextMapClass != null) { + result.append("threadContextMapClass=").append(threadContextMapClass.getName()); } if (className != null) { - result += "className=" + className + ", "; + result.append("className=").append(className).append(", "); + } else if (loggerContextFactoryClass != null) { + result.append("class=").append(loggerContextFactoryClass.getName()); } - result += "url=" + url; - final ClassLoader loader = classLoader.get(); - if (loader == null) { - result += ", classLoader=null(not reachable)"; + if (url != null) { + result.append("url=").append(url); + } + final ClassLoader loader; + if (classLoader == null || (loader = classLoader.get()) == null) { + result.append(", classLoader=null(not reachable)"); } else { - result += ", classLoader=" + loader; + result.append(", classLoader=").append(loader); } - result += "]"; - return result; + result.append("]"); + return result.toString(); } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/util/Activator.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Activator.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Activator.java index bcf3bc4..f35ace8 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Activator.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Activator.java @@ -16,6 +16,7 @@ */ package org.apache.logging.log4j.util; +import javax.annotation.processing.ProcessingEnvironment; import java.net.URL; import java.security.Permission; import java.util.List; @@ -72,6 +73,7 @@ public class Activator implements BundleActivator, SynchronousBundleListener { } private void loadProvider(final BundleWiring provider) { + ProviderUtil.loadProviders(provider.getClassLoader()); final List<URL> urls = provider.findEntries("META-INF", "log4j-provider.properties", 0); for (final URL url : urls) { ProviderUtil.loadProvider(url, provider.getClassLoader()); @@ -83,7 +85,7 @@ public class Activator implements BundleActivator, SynchronousBundleListener { ProviderUtil.STARTUP_LOCK.lock(); lockingProviderUtil = true; final BundleWiring self = context.getBundle().adapt(BundleWiring.class); - final List<BundleWire> required = self.getRequiredWires(LoggerContextFactory.class.getName()); + List<BundleWire> required = self.getRequiredWires(LoggerContextFactory.class.getName()); for (final BundleWire wire : required) { loadProvider(wire.getProviderWiring()); } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassNamePredicate.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassNamePredicate.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassNamePredicate.java deleted file mode 100644 index 063e538..0000000 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassNamePredicate.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.logging.log4j.util; - -import java.util.function.Predicate; - -/** - * <em>This class should be considered to be internal.</em> Used to locate the StackFrame that called the named class. - */ -public final class ClassNamePredicate implements Predicate<StackWalker.StackFrame> { - - private final String fqcn; - - public ClassNamePredicate(String fqcn) { - this.fqcn = fqcn; - } - - private boolean next = false; - - @Override - public boolean test(StackWalker.StackFrame f) { - if (fqcn.equals(f.getClassName())) { - next = true; - return false; - } else if (next) { - next = false; - return true; - } - return false; - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassPredicate.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassPredicate.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassPredicate.java deleted file mode 100644 index 3f8d15a..0000000 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ClassPredicate.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.logging.log4j.util; - -import java.util.function.Predicate; - -/** - * <em>This class should be considered to be internal.</em> Used to locate the StackFrame that called the named class. - */ - -public final class ClassPredicate implements Predicate<StackWalker.StackFrame> { - - private final Class<?> clazz; - - public ClassPredicate(Class<?> clazz) { - this.clazz = clazz; - } - - private boolean next = false; - - @Override - public boolean test(StackWalker.StackFrame f) { - if (clazz.equals(f.getDeclaringClass())) { - next = true; - return false; - } else if (next) { - next = false; - return true; - } - return false; - } -} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java index 498bda9..b5be525 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import java.util.Properties; +import java.util.ServiceLoader; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -62,6 +63,7 @@ public final class ProviderUtil { private static volatile ProviderUtil instance; private ProviderUtil() { + loadProviders(findClassLoader()); for (final LoaderUtil.UrlResource resource : LoaderUtil.findUrlResources(PROVIDER_RESOURCE)) { loadProvider(resource.getUrl(), resource.getClassLoader()); } @@ -87,6 +89,15 @@ public final class ProviderUtil { } } + protected static void loadProviders(final ClassLoader cl) { + ServiceLoader<Provider> serviceLoader = ServiceLoader.load(Provider.class, cl); + for (Provider provider : serviceLoader) { + if (validVersion(provider.getVersions())) { + PROVIDERS.add(provider); + } + } + } + /** * @deprecated Use {@link #loadProvider(java.net.URL, ClassLoader)} instead. Will be removed in 3.0. */ http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java/org/apache/logging/log4j/util/StackWalkerStackLocator.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackWalkerStackLocator.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/StackWalkerStackLocator.java deleted file mode 100644 index dc10fef..0000000 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackWalkerStackLocator.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.logging.log4j.util; - -import java.util.List; -import java.util.Stack; -import java.util.stream.Collectors; - -/** - * <em>Consider this class private.</em> Determines the caller's class. - */ -public class StackWalkerStackLocator implements StackLocator { - - private final static StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); - - private final static StackWalker stackWalker = StackWalker.getInstance(); - - public Class<?> getCallerClass(final String fqcn) { - return getCallerClass(fqcn, ""); - } - - public Class<?> getCallerClass(final String fqcn, final String pkg) { - return walker.walk(s -> s.filter(new ClassNamePredicate(fqcn)).findFirst()).get().getDeclaringClass(); - } - - public Class<?> getCallerClass(final Class<?> anchor) { - return walker.walk(s -> s.filter(new ClassPredicate(anchor)).findFirst()).get().getDeclaringClass(); - } - - public Class<?> getCallerClass(final int depth) { - ; - return walker.walk(s -> s.skip(depth).findFirst()).get().getDeclaringClass(); - } - - public Stack<Class<?>> getCurrentStackTrace() { - Stack<Class<?>> stack = new Stack<Class<?>>(); - List<Class<?>> classes = walker.walk(s -> s.map(f -> f.getDeclaringClass()).collect(Collectors.toList())); - stack.addAll(classes); - return stack; - } - - public StackTraceElement calcLocation(final String fqcnOfLogger) { - return stackWalker.walk(s -> s.filter(new ClassNamePredicate(fqcnOfLogger)).findFirst()).get().toStackTraceElement(); - } - - public StackTraceElement getStackTraceElement(final int depth) { - return stackWalker.walk(s -> s.skip(depth).findFirst()).get().toStackTraceElement(); - } -} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassNamePredicate.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassNamePredicate.java b/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassNamePredicate.java new file mode 100644 index 0000000..063e538 --- /dev/null +++ b/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassNamePredicate.java @@ -0,0 +1,45 @@ +/* + * 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.logging.log4j.util; + +import java.util.function.Predicate; + +/** + * <em>This class should be considered to be internal.</em> Used to locate the StackFrame that called the named class. + */ +public final class ClassNamePredicate implements Predicate<StackWalker.StackFrame> { + + private final String fqcn; + + public ClassNamePredicate(String fqcn) { + this.fqcn = fqcn; + } + + private boolean next = false; + + @Override + public boolean test(StackWalker.StackFrame f) { + if (fqcn.equals(f.getClassName())) { + next = true; + return false; + } else if (next) { + next = false; + return true; + } + return false; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassPredicate.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassPredicate.java b/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassPredicate.java new file mode 100644 index 0000000..3f8d15a --- /dev/null +++ b/log4j-api/src/main/java9/org/apache/logging/log4j/util/ClassPredicate.java @@ -0,0 +1,46 @@ +/* + * 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.logging.log4j.util; + +import java.util.function.Predicate; + +/** + * <em>This class should be considered to be internal.</em> Used to locate the StackFrame that called the named class. + */ + +public final class ClassPredicate implements Predicate<StackWalker.StackFrame> { + + private final Class<?> clazz; + + public ClassPredicate(Class<?> clazz) { + this.clazz = clazz; + } + + private boolean next = false; + + @Override + public boolean test(StackWalker.StackFrame f) { + if (clazz.equals(f.getDeclaringClass())) { + next = true; + return false; + } else if (next) { + next = false; + return true; + } + return false; + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/main/java9/org/apache/logging/log4j/util/StackWalkerStackLocator.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java9/org/apache/logging/log4j/util/StackWalkerStackLocator.java b/log4j-api/src/main/java9/org/apache/logging/log4j/util/StackWalkerStackLocator.java new file mode 100644 index 0000000..dc10fef --- /dev/null +++ b/log4j-api/src/main/java9/org/apache/logging/log4j/util/StackWalkerStackLocator.java @@ -0,0 +1,63 @@ +/* + * 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.logging.log4j.util; + +import java.util.List; +import java.util.Stack; +import java.util.stream.Collectors; + +/** + * <em>Consider this class private.</em> Determines the caller's class. + */ +public class StackWalkerStackLocator implements StackLocator { + + private final static StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); + + private final static StackWalker stackWalker = StackWalker.getInstance(); + + public Class<?> getCallerClass(final String fqcn) { + return getCallerClass(fqcn, ""); + } + + public Class<?> getCallerClass(final String fqcn, final String pkg) { + return walker.walk(s -> s.filter(new ClassNamePredicate(fqcn)).findFirst()).get().getDeclaringClass(); + } + + public Class<?> getCallerClass(final Class<?> anchor) { + return walker.walk(s -> s.filter(new ClassPredicate(anchor)).findFirst()).get().getDeclaringClass(); + } + + public Class<?> getCallerClass(final int depth) { + ; + return walker.walk(s -> s.skip(depth).findFirst()).get().getDeclaringClass(); + } + + public Stack<Class<?>> getCurrentStackTrace() { + Stack<Class<?>> stack = new Stack<Class<?>>(); + List<Class<?>> classes = walker.walk(s -> s.map(f -> f.getDeclaringClass()).collect(Collectors.toList())); + stack.addAll(classes); + return stack; + } + + public StackTraceElement calcLocation(final String fqcnOfLogger) { + return stackWalker.walk(s -> s.filter(new ClassNamePredicate(fqcnOfLogger)).findFirst()).get().toStackTraceElement(); + } + + public StackTraceElement getStackTraceElement(final int depth) { + return stackWalker.walk(s -> s.skip(depth).findFirst()).get().toStackTraceElement(); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/test/java/org/apache/logging/log4j/TestProvider.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/TestProvider.java b/log4j-api/src/test/java/org/apache/logging/log4j/TestProvider.java new file mode 100644 index 0000000..f96181a --- /dev/null +++ b/log4j-api/src/test/java/org/apache/logging/log4j/TestProvider.java @@ -0,0 +1,28 @@ +/* + * 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.logging.log4j; + +import org.apache.logging.log4j.spi.Provider; + +/** + * Binding for the Log4j API. + */ +public class TestProvider extends Provider { + public TestProvider() { + super(0, "2.6.0", TestLoggerContextFactory.class); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/test/resources/META-INF/log4j-provider.properties ---------------------------------------------------------------------- diff --git a/log4j-api/src/test/resources/META-INF/log4j-provider.properties b/log4j-api/src/test/resources/META-INF/log4j-provider.properties deleted file mode 100644 index 36fc6d6..0000000 --- a/log4j-api/src/test/resources/META-INF/log4j-provider.properties +++ /dev/null @@ -1,3 +0,0 @@ -LoggerContextFactory = org.apache.logging.log4j.TestLoggerContextFactory -Log4jAPIVersion = 2.6.0 -FactoryPriority = 0 \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-api/src/test/resources/META-INF/services/org.apache.logging.log4j.spi.Provider ---------------------------------------------------------------------- diff --git a/log4j-api/src/test/resources/META-INF/services/org.apache.logging.log4j.spi.Provider b/log4j-api/src/test/resources/META-INF/services/org.apache.logging.log4j.spi.Provider new file mode 100644 index 0000000..5ae649a --- /dev/null +++ b/log4j-api/src/test/resources/META-INF/services/org.apache.logging.log4j.spi.Provider @@ -0,0 +1 @@ +org.apache.logging.log4j.TestProvider \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java new file mode 100644 index 0000000..499fb45 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jProvider.java @@ -0,0 +1,28 @@ +/* + * 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.logging.log4j.core.impl; + +import org.apache.logging.log4j.spi.Provider; + +/** + * Binding for the Log4j API. + */ +public class Log4jProvider extends Provider { + public Log4jProvider() { + super(10, "2.6.0", Log4jContextFactory.class); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-core/src/main/resources/META-INF/log4j-provider.properties ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/resources/META-INF/log4j-provider.properties b/log4j-core/src/main/resources/META-INF/log4j-provider.properties deleted file mode 100644 index 2335e85..0000000 --- a/log4j-core/src/main/resources/META-INF/log4j-provider.properties +++ /dev/null @@ -1,18 +0,0 @@ -# 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. - -LoggerContextFactory = org.apache.logging.log4j.core.impl.Log4jContextFactory -Log4jAPIVersion = 2.6.0 -FactoryPriority= 10 http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-core/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider b/log4j-core/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider new file mode 100644 index 0000000..c4c6c6c --- /dev/null +++ b/log4j-core/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider @@ -0,0 +1 @@ +org.apache.logging.log4j.core.impl.Log4jProvider \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/AsyncAppenderNoLocationTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/AsyncAppenderNoLocationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/AsyncAppenderNoLocationTest.java index ba7da83..17865a8 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/AsyncAppenderNoLocationTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/AsyncAppenderNoLocationTest.java @@ -36,11 +36,26 @@ public class AsyncAppenderNoLocationTest { private ListAppender app; @ClassRule - public static LoggerContextRule init = new LoggerContextRule("log4j-asynch-no-location.xml"); + public static LoggerContextRule init = null; + + static { + try { + init = new LoggerContextRule("log4j-asynch-no-location.xml"); + } catch (Exception ex) { + ex.printStackTrace(); + } + } @Before public void setUp() throws Exception { - this.app = (ListAppender) init.getAppender("List"); + try { + this.app = (ListAppender) init.getAppender("List"); + assertNotNull("No List appender found", app); + } catch (Exception ex) { + System.out.println("init = " + init == null ? "null" : init); + + } + } @After @@ -56,6 +71,7 @@ public class AsyncAppenderNoLocationTest { logger.error("This is a test"); logger.warn("Hello world!"); Thread.sleep(100); + System.out.println("app = " + app == null ? "null" : app); final List<String> list = app.getMessages(); assertNotNull("No events generated", list); assertEquals("Incorrect number of events. Expected 2, got " + list.size(), list.size(), 2); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JProvider.java ---------------------------------------------------------------------- diff --git a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JProvider.java b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JProvider.java new file mode 100644 index 0000000..979d5e9 --- /dev/null +++ b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JProvider.java @@ -0,0 +1,28 @@ +/* + * 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.logging.slf4j; + +import org.apache.logging.log4j.spi.Provider; + +/** + * Bind the Log4j API to SLF4J. + */ +public class SLF4JProvider extends Provider { + public SLF4JProvider() { + super(15, "2.6.0", SLF4JLoggerContextFactory.class, MDCContextMap.class); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties ---------------------------------------------------------------------- diff --git a/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties b/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties deleted file mode 100644 index f213cc2..0000000 --- a/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties +++ /dev/null @@ -1,19 +0,0 @@ -# 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. - -LoggerContextFactory = org.apache.logging.slf4j.SLF4JLoggerContextFactory -Log4jAPIVersion = 2.6.0 -FactoryPriority= 15 -ThreadContextMap = org.apache.logging.slf4j.MDCContextMap \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/log4j-to-slf4j/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider ---------------------------------------------------------------------- diff --git a/log4j-to-slf4j/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider b/log4j-to-slf4j/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider new file mode 100644 index 0000000..c66b5c9 --- /dev/null +++ b/log4j-to-slf4j/src/main/resources/META-INF/services/org.apache.logging.log4j.spi.Provider @@ -0,0 +1 @@ +org.apache.logging.slf4j.SLF4JProvider \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 9681eb4..db263d1 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -31,6 +31,9 @@ - "remove" - Removed --> <release version="2.9.0" date="2017-MM-DD" description="GA Release 2.9.0"> + <action issue="LOG4J2-1917" dev="rgoers" type="update"> + Support using java.util.ServiceLoader to locate Log4j 2 API providers. + </action> <action issue="LOG4J2-1854" dev="mikes" type="add" due-to="Xavier Jodoin"> Support null byte delimiter in GelfLayout. </action> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/92e4b875/src/site/xdoc/manual/extending.xml ---------------------------------------------------------------------- diff --git a/src/site/xdoc/manual/extending.xml b/src/site/xdoc/manual/extending.xml index 357bb67..4362cfb 100644 --- a/src/site/xdoc/manual/extending.xml +++ b/src/site/xdoc/manual/extending.xml @@ -33,25 +33,34 @@ <subsection name="LoggerContextFactory"> <p> The <code>LoggerContextFactory</code> binds the Log4j API to its implementation. The Log4j - <code>LogManager</code> locates a <code>LoggerContextFactory</code> by locating all instances of - <code>META-INF/log4j-provider.properties</code>, a standard <code>java.util.Properties</code> file, - and then inspecting each to verify that it specifies a value for the <var>Log4jAPIVersion</var> property - that conforms to the version required by the <code>LogManager</code>. If more than one valid - implementation is located the value for <var>FactoryPriority</var> will be used to identify the factory - with the highest priority. Finally, the value of the <var>LoggerContextFactory</var> property will be - used to locate the <code>LoggerContextFactory</code>. In Log4j 2 this is provided by - <code>Log4jContextFactory</code>. + <code>LogManager</code> locates a <code>LoggerContextFactory</code> by using java.util.ServiceLoader + to locate all instances of <code>org.apache.logging.log4j.spi.Provider</code>. Each implementation must + provide a class that extends<code>org.apache.logging.log4j.spi.Provider</code> and should have a + no-arg constructor that delegates to Provider's constructor passing the <var>Priority</var>, + the API versions it is compatible with, and the class that implements + <code>org.apache.logging.log4j.spi.LoggerContextFactory</code>. Log4j will compare the current API + version and if it is compatible the implementation will be added to the list of providers. The + API version in <code>org.apache.logging.log4j.LogManager</code> is only changed when a feature is added + to the API that implementations need to be aware of. If more than one valid implementation is located + the value for the <var>Priority</var> will be used to identify the factory with the highest priority. + Finally, the class that implements <code>org.apache.logging.log4j.spi.LoggerContextFactory</code> will be + instantiated and bound to the LogManager. In Log4j 2 this is provided by <code>Log4jContextFactory</code>. </p> <p> Applications may change the LoggerContextFactory that will be used by </p> <ol> - <li>Implementing a new <code>LoggerContextFactory</code> and creating a <code>log4j-provider.properties</code> - to reference it making sure that it has the highest priority. - </li> - <li>Create a new <code>log4j-provider.xml</code> and configure it with the desired - <code>LoggerContextFactory</code> making sure that it has the highest priority. - </li> + <li>Create a binding to the logging implementation. + <ol style="list-style-type: lower-alpha"> + <li>Implement a new <code>LoggerContextFactory</code>.</li> + <li>Implement a class that extends <code>org.apache.logging.spi.Provider.</code> with a no-arg + constructor that calls super-class's constructor with the <var>Priority</var>, the API version(s), + <code>LoggerContextFactory</code> class, and optinall, a <code>ThreadContextMap</code> + implementation class.</li> + <li>Create a <code>META-INF/services/org.apache.logging.spi.Provider</code> file that contains the + name of the class that implements <code>org.apache.logging.spi.Provider</code>. + </li> + </ol></li> <li>Setting the system property <var>log4j2.loggerContextFactory</var> to the name of the <code>LoggerContextFactory</code> class to use. </li>
