I prefer builders when you have more than 2 arguments to the factory. This is based on Item 2 from Effective Java (prefer builders for constructors that take a lot of arguments).
On 26 May 2016 at 10:24, Mikael Ståldal <[email protected]> wrote: > Which one of builder and factory is preferred? > > On Thu, May 26, 2016 at 5:22 PM, Matt Sicker <[email protected]> wrote: > >> Just FYI, if you make a plugin builder, you don't need to make a plugin >> factory as well. The builder is used first if available followed by the >> factory method. Classes that have both are mainly for backwards >> compatibility. >> >> ---------- Forwarded message ---------- >> From: <[email protected]> >> Date: 26 May 2016 at 10:12 >> Subject: logging-log4j2 git commit: FastConsoleAppender >> To: [email protected] >> >> >> Repository: logging-log4j2 >> Updated Branches: >> refs/heads/LOG4J2-1395 [created] 06c554689 >> >> >> FastConsoleAppender >> >> >> Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo >> Commit: >> http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/06c55468 >> Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/06c55468 >> Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/06c55468 >> >> Branch: refs/heads/LOG4J2-1395 >> Commit: 06c55468948efdce95a591801d5f9e2ffdb69dd4 >> Parents: e012269 >> Author: Mikael Ståldal <[email protected]> >> Authored: Thu May 26 17:12:33 2016 +0200 >> Committer: Mikael Ståldal <[email protected]> >> Committed: Thu May 26 17:12:33 2016 +0200 >> >> ---------------------------------------------------------------------- >> .../core/appender/FastConsoleAppender.java | 227 +++++++++++++++++++ >> .../jmh/Log4j2AppenderComparisonBenchmark.java | 18 ++ >> .../resources/log4j2-appenderComparison.xml | 6 + >> 3 files changed, 251 insertions(+) >> ---------------------------------------------------------------------- >> >> >> >> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/06c55468/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FastConsoleAppender.java >> ---------------------------------------------------------------------- >> diff --git >> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FastConsoleAppender.java >> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FastConsoleAppender.java >> new file mode 100644 >> index 0000000..a7cd905 >> --- /dev/null >> +++ >> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FastConsoleAppender.java >> @@ -0,0 +1,227 @@ >> +/* >> + * 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.appender; >> + >> +import java.io.FileDescriptor; >> +import java.io.FileOutputStream; >> +import java.io.OutputStream; >> +import java.io.Serializable; >> +import java.util.concurrent.atomic.AtomicInteger; >> + >> +import org.apache.logging.log4j.core.Filter; >> +import org.apache.logging.log4j.core.Layout; >> +import org.apache.logging.log4j.core.config.plugins.Plugin; >> +import org.apache.logging.log4j.core.config.plugins.PluginAttribute; >> +import >> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; >> +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; >> +import org.apache.logging.log4j.core.config.plugins.PluginElement; >> +import org.apache.logging.log4j.core.config.plugins.PluginFactory; >> +import >> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; >> +import org.apache.logging.log4j.core.layout.PatternLayout; >> +import org.apache.logging.log4j.core.util.CloseShieldOutputStream; >> + >> +/** >> + * Appends log events to <code>System.out</code> or >> <code>System.err</code> using a layout specified by the user. The >> + * default target is <code>System.out</code>. >> + */ >> +@Plugin(name = "FastConsole", category = "Core", elementType = >> "appender", printObject = true) >> +public final class FastConsoleAppender extends >> AbstractOutputStreamAppender<OutputStreamManager> { >> + >> + private static ConsoleManagerFactory factory = new >> ConsoleManagerFactory(); >> + private static final Target DEFAULT_TARGET = Target.SYSTEM_OUT; >> + private static final AtomicInteger COUNT = new AtomicInteger(); >> + >> + private final Target target; >> + >> + /** >> + * Enumeration of console destinations. >> + */ >> + public enum Target { >> + /** Standard output. */ >> + SYSTEM_OUT, >> + /** Standard error output. */ >> + SYSTEM_ERR >> + } >> + >> + private FastConsoleAppender(final String name, final Layout<? >> extends Serializable> layout, final Filter filter, >> + final OutputStreamManager manager, final >> boolean ignoreExceptions, Target target) { >> + super(name, layout, filter, ignoreExceptions, true, manager); >> + this.target = target; >> + } >> + >> + /** >> + * Creates a Console Appender. >> + * >> + * @param layout The layout to use (required). >> + * @param filter The Filter or null. >> + * @param target The target (SYSTEM_OUT or SYSTEM_ERR). The default >> is SYSTEM_OUT. >> + * @param name The name of the Appender (required). >> + * @param ignoreExceptions If {@code "true"} (default) exceptions >> encountered when appending events are logged; otherwise they >> + * are propagated to the caller. >> + * @return The ConsoleAppender. >> + */ >> + @PluginFactory >> + public static FastConsoleAppender createAppender( >> + // @formatter:off >> + @PluginElement("Layout") Layout<? extends Serializable> >> layout, >> + @PluginElement("Filter") final Filter filter, >> + @PluginAttribute(value = "target") Target target, >> + @PluginAttribute("name") final String name, >> + @PluginAttribute(value = "ignoreExceptions", defaultBoolean >> = true) final boolean ignoreExceptions) { >> + // @formatter:on >> + if (name == null) { >> + LOGGER.error("No name provided for ConsoleAppender"); >> + return null; >> + } >> + if (layout == null) { >> + layout = PatternLayout.createDefaultLayout(); >> + } >> + target = target == null ? Target.SYSTEM_OUT : target; >> + return new FastConsoleAppender(name, layout, filter, >> getManager(target, layout), ignoreExceptions, target); >> + } >> + >> + public static FastConsoleAppender >> createDefaultAppenderForLayout(final Layout<? extends Serializable> layout) >> { >> + // this method cannot use the builder class without introducing >> an infinite loop due to DefaultConfiguration >> + return new FastConsoleAppender("DefaultConsole-" + >> COUNT.incrementAndGet(), layout, null, >> + getDefaultManager(DEFAULT_TARGET, layout), true, >> DEFAULT_TARGET); >> + } >> + >> + @PluginBuilderFactory >> + public static Builder newBuilder() { >> + return new Builder(); >> + } >> + >> + /** >> + * Builds ConsoleAppender instances. >> + */ >> + public static class Builder implements >> org.apache.logging.log4j.core.util.Builder<FastConsoleAppender> { >> + >> + @PluginElement("Layout") >> + @Required >> + private Layout<? extends Serializable> layout = >> PatternLayout.createDefaultLayout(); >> + >> + @PluginElement("Filter") >> + private Filter filter; >> + >> + @PluginBuilderAttribute >> + @Required >> + private Target target = DEFAULT_TARGET; >> + >> + @PluginBuilderAttribute >> + @Required >> + private String name; >> + >> + @PluginBuilderAttribute >> + private boolean ignoreExceptions = true; >> + >> + public Builder setLayout(final Layout<? extends Serializable> >> aLayout) { >> + this.layout = aLayout; >> + return this; >> + } >> + >> + public Builder setFilter(final Filter aFilter) { >> + this.filter = aFilter; >> + return this; >> + } >> + >> + public Builder setTarget(final Target aTarget) { >> + this.target = aTarget; >> + return this; >> + } >> + >> + public Builder setName(final String aName) { >> + this.name = aName; >> + return this; >> + } >> + >> + public Builder setIgnoreExceptions(final boolean >> shouldIgnoreExceptions) { >> + this.ignoreExceptions = shouldIgnoreExceptions; >> + return this; >> + } >> + >> + @Override >> + public FastConsoleAppender build() { >> + return new FastConsoleAppender(name, layout, filter, >> getManager(target, layout), ignoreExceptions, target); >> + } >> + } >> + >> + private static OutputStreamManager getDefaultManager(final Target >> target, final Layout<? extends Serializable> layout) { >> + final OutputStream os = getOutputStream(target); >> + >> + // LOG4J2-1176 DefaultConfiguration should not share >> OutputStreamManager instances to avoid memory leaks. >> + final String managerName = target.name() + '-' + COUNT.get(); >> + return OutputStreamManager.getManager(managerName, new >> FactoryData(os, managerName, layout), factory); >> + } >> + >> + private static OutputStreamManager getManager(final Target target, >> final Layout<? extends Serializable> layout) { >> + final OutputStream os = getOutputStream(target); >> + final String managerName = target.name(); >> + return OutputStreamManager.getManager(managerName, new >> FactoryData(os, managerName, layout), factory); >> + } >> + >> + private static OutputStream getOutputStream(final Target target) { >> + OutputStream outputStream = target == Target.SYSTEM_OUT >> + ? new FileOutputStream(FileDescriptor.out) >> + : new FileOutputStream(FileDescriptor.err); >> + return new CloseShieldOutputStream(outputStream); >> + } >> + >> + /** >> + * Data to pass to factory method. >> + */ >> + private static class FactoryData { >> + private final OutputStream os; >> + private final String name; >> + private final Layout<? extends Serializable> layout; >> + >> + /** >> + * Constructor. >> + * >> + * @param os The OutputStream. >> + * @param type The name of the target. >> + * @param layout A Serializable layout >> + */ >> + public FactoryData(final OutputStream os, final String type, >> final Layout<? extends Serializable> layout) { >> + this.os = os; >> + this.name = type; >> + this.layout = layout; >> + } >> + } >> + >> + /** >> + * Factory to create the Appender. >> + */ >> + private static class ConsoleManagerFactory implements >> ManagerFactory<OutputStreamManager, FactoryData> { >> + >> + /** >> + * Create an OutputStreamManager. >> + * >> + * @param name The name of the entity to manage. >> + * @param data The data required to create the entity. >> + * @return The OutputStreamManager >> + */ >> + @Override >> + public OutputStreamManager createManager(final String name, >> final FactoryData data) { >> + return new OutputStreamManager(data.os, data.name, >> data.layout, true); >> + } >> + } >> + >> + public Target getTarget() { >> + return target; >> + } >> + >> +} >> >> >> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/06c55468/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java >> ---------------------------------------------------------------------- >> diff --git >> a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java >> b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java >> index 0527709..a4ea02e 100644 >> --- >> a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java >> +++ >> b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/Log4j2AppenderComparisonBenchmark.java >> @@ -57,12 +57,14 @@ public class Log4j2AppenderComparisonBenchmark { >> private Logger rafLogger; >> private Logger mmapLogger; >> private Logger consoleLogger; >> + private Logger fastConsoleLogger; >> private Logger noopLogger; >> private Logger rewriteLogger; >> private Appender fileAppender; >> private Appender rafAppender; >> private Appender mmapAppender; >> private Appender consoleAppender; >> + private Appender fastConsoleAppender; >> private Appender noopAppender; >> private Appender rewriteAppender; >> >> @@ -102,6 +104,7 @@ public class Log4j2AppenderComparisonBenchmark { >> rafLogger = LogManager.getLogger("RAFLogger"); >> mmapLogger = LogManager.getLogger("MMapLogger"); >> consoleLogger = LogManager.getLogger("ConsoleLogger"); >> + fastConsoleLogger = LogManager.getLogger("FastConsoleLogger"); >> noopLogger = LogManager.getLogger("NoopLogger"); >> rewriteLogger = LogManager.getLogger("RewriteLogger"); >> >> @@ -109,6 +112,7 @@ public class Log4j2AppenderComparisonBenchmark { >> rafAppender = ((org.apache.logging.log4j.core.Logger) >> rafLogger).getAppenders().get("RandomAccessFile"); >> mmapAppender = ((org.apache.logging.log4j.core.Logger) >> mmapLogger).getAppenders().get("MemoryMappedFile"); >> consoleAppender = ((org.apache.logging.log4j.core.Logger) >> consoleLogger).getAppenders().get("Console"); >> + fastConsoleAppender = ((org.apache.logging.log4j.core.Logger) >> fastConsoleLogger).getAppenders().get("FastConsole"); >> noopAppender = ((org.apache.logging.log4j.core.Logger) >> noopLogger).getAppenders().get("NoOp"); >> rewriteAppender = ((org.apache.logging.log4j.core.Logger) >> rewriteLogger).getAppenders().get("Rewrite"); >> } >> @@ -218,4 +222,18 @@ public class Log4j2AppenderComparisonBenchmark { >> public void appenderConsole() { >> consoleAppender.append(EVENT); >> } >> + >> + @BenchmarkMode(Mode.Throughput) >> + @OutputTimeUnit(TimeUnit.SECONDS) >> + @Benchmark >> + public void end2endFastConsole() { >> + fastConsoleLogger.debug(MESSAGE); >> + } >> + >> + @BenchmarkMode(Mode.Throughput) >> + @OutputTimeUnit(TimeUnit.SECONDS) >> + @Benchmark >> + public void appenderFastConsole() { >> + fastConsoleAppender.append(EVENT); >> + } >> } >> >> >> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/06c55468/log4j-perf/src/main/resources/log4j2-appenderComparison.xml >> ---------------------------------------------------------------------- >> diff --git a/log4j-perf/src/main/resources/log4j2-appenderComparison.xml >> b/log4j-perf/src/main/resources/log4j2-appenderComparison.xml >> index 741a225..8ad6327 100644 >> --- a/log4j-perf/src/main/resources/log4j2-appenderComparison.xml >> +++ b/log4j-perf/src/main/resources/log4j2-appenderComparison.xml >> @@ -21,6 +21,9 @@ >> <Console name="Console" target="SYSTEM_OUT"> >> <PatternLayout pattern="%d %p [%t] %c{1} %X{transactionId} - >> %m%n"/> >> </Console> >> + <FastConsole name="FastConsole" target="SYSTEM_OUT"> >> + <PatternLayout pattern="%d %p [%t] %c{1} %X{transactionId} - >> %m%n"/> >> + </FastConsole> >> <File name="File" fileName="target/testlog4j2.log" >> immediateFlush="false"> >> <PatternLayout pattern="%d %p [%t] %c{1} %X{transactionId} - >> %m%n"/> >> </File> >> @@ -55,6 +58,9 @@ >> <Logger name="ConsoleLogger" level="debug" additivity="false"> >> <AppenderRef ref="Console"/> >> </Logger> >> + <Logger name="FastConsoleLogger" level="debug" >> additivity="false"> >> + <AppenderRef ref="FastConsole"/> >> + </Logger> >> <Logger name="NoopLogger" level="debug" additivity="false"> >> <AppenderRef ref="NoOp"/> >> </Logger> >> >> >> >> >> -- >> Matt Sicker <[email protected]> >> > > > > -- > [image: MagineTV] > > *Mikael Ståldal* > Senior software developer > > *Magine TV* > [email protected] > Grev Turegatan 3 | 114 46 Stockholm, Sweden | www.magine.com > > Privileged and/or Confidential Information may be contained in this > message. If you are not the addressee indicated in this message > (or responsible for delivery of the message to such a person), you may not > copy or deliver this message to anyone. In such case, > you should destroy this message and kindly notify the sender by reply > email. > -- Matt Sicker <[email protected]>
