Added documentation to the "Extending Log4j" page. Let me know if you have
any more questions about it.

On 26 May 2016 at 16:23, Matt Sicker <[email protected]> wrote:

> Is there any place the factory method version is documented? I could add
> the info there. Otherwise, I'll have to figure out an appropriate place for
> it (perhaps in the manual).
>
> On 26 May 2016 at 13:35, Matt Sicker <[email protected]> wrote:
>
>> 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]>
>>
>
>
>
> --
> Matt Sicker <[email protected]>
>



-- 
Matt Sicker <[email protected]>

Reply via email to