Sure. I can't believe I forgot to document that better. On 26 May 2016 at 12:06, Ralph Goers <[email protected]> wrote:
> Can you provide documentation on using the builder? I tried to implement > something a few months ago using a builder and couldn’t quite figure it all > out so I went back to using a factory. > > Ralph > > On May 26, 2016, at 8:31 AM, Matt Sicker <[email protected]> wrote: > > 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 >> <http://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]> > > > -- Matt Sicker <[email protected]>
