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]>
