You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2019/06/29 04:39:03 UTC

[logging-log4j2] branch master updated (af75bf7 -> 45503f5)

This is an automated email from the ASF dual-hosted git repository.

rgoers pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git.


    from af75bf7  LOG4J2-2566 - Add missing modules to bom pom.xml
     new 3bd605d  LOG4J2-2639 - Allow logging calls to be constructed using a builder pattern
     new b15623d  LOG4J2-2639 - changes due to review comments
     new 20f7341  LOG4J2-2639 - more code review changes
     new 45503f5  LOG4J2-2639 - More code review changes

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../java/org/apache/logging/log4j/LogBuilder.java  |  68 ++++++++
 .../main/java/org/apache/logging/log4j/Logger.java |  90 +++++++++-
 .../logging/log4j/internal/DefaultLogBuilder.java  | 168 +++++++++++++++++++
 .../log4j/message/AbstractMessageFactory.java      | 124 +-------------
 .../log4j/message/FormattedMessageFactory.java     |   9 +-
 .../log4j/message/LocalizedMessageFactory.java     |   8 +-
 .../logging/log4j/message/MessageFactory.java      | 186 ++++++++++++++++++++-
 .../logging/log4j/message/MessageFactory2.java     | 156 +----------------
 .../log4j/message/MessageFormatMessageFactory.java |   9 +-
 .../log4j/message/ParameterizedMessageFactory.java |   9 +-
 .../ParameterizedNoReferenceMessageFactory.java    |   9 +-
 .../log4j/message/ReusableMessageFactory.java      |   2 +-
 .../log4j/message/SimpleMessageFactory.java        |   9 +-
 .../message/StringFormatterMessageFactory.java     |   9 +-
 .../apache/logging/log4j/spi/AbstractLogger.java   | 141 ++++++++++++++--
 .../logging/log4j/spi/MessageFactory2Adapter.java  | 118 -------------
 .../apache/logging/log4j/AbstractLoggerTest.java   |   5 +-
 .../java/org/apache/logging/log4j/LoggerTest.java  |  20 ++-
 .../java/org/apache/logging/log4j/TestLogger.java  |  15 +-
 .../java/org/apache/logging/log4j/core/Logger.java |   7 +
 .../config/AwaitCompletionReliabilityStrategy.java |  19 +++
 .../AwaitUnconditionallyReliabilityStrategy.java   |  14 ++
 .../core/config/DefaultReliabilityStrategy.java    |  14 ++
 .../core/config/LockingReliabilityStrategy.java    |  19 +++
 .../logging/log4j/core/config/LoggerConfig.java    |  46 +++++
 .../log4j/core/config/ReliabilityStrategy.java     |  16 ++
 .../log4j/core/impl/DefaultLogEventFactory.java    |  19 +++
 .../logging/log4j/core/impl/Log4jLogEvent.java     |  24 +++
 .../logging/log4j/core/impl/LogEventFactory.java   |   5 +
 .../org/apache/logging/log4j/core/LoggerTest.java  |  41 +++--
 .../logging/log4j/taglib/SetLoggerTagTest.java     |  16 +-
 .../java/org/apache/logging/slf4j/LoggerTest.java  |  14 +-
 32 files changed, 915 insertions(+), 494 deletions(-)
 create mode 100644 log4j-api/src/main/java/org/apache/logging/log4j/LogBuilder.java
 create mode 100644 log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
 delete mode 100644 log4j-api/src/main/java/org/apache/logging/log4j/spi/MessageFactory2Adapter.java


[logging-log4j2] 04/04: LOG4J2-2639 - More code review changes

Posted by rg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rgoers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 45503f5885a655b10ee870a24cf9f520b5b90833
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Tue Jun 25 21:43:41 2019 -0700

    LOG4J2-2639 - More code review changes
---
 .../logging/log4j/{internal => }/LogBuilder.java   |  29 +++--
 .../main/java/org/apache/logging/log4j/Logger.java |  16 +--
 .../logging/log4j/internal/DefaultLogBuilder.java  | 137 +++++++++------------
 .../apache/logging/log4j/spi/AbstractLogger.java   |  18 +--
 .../java/org/apache/logging/log4j/LoggerTest.java  |   6 +-
 .../org/apache/logging/log4j/core/LoggerTest.java  |   6 +-
 6 files changed, 94 insertions(+), 118 deletions(-)

diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/internal/LogBuilder.java b/log4j-api/src/main/java/org/apache/logging/log4j/LogBuilder.java
similarity index 68%
rename from log4j-api/src/main/java/org/apache/logging/log4j/internal/LogBuilder.java
rename to log4j-api/src/main/java/org/apache/logging/log4j/LogBuilder.java
index 93b40f8..e18ae40 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/internal/LogBuilder.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/LogBuilder.java
@@ -14,15 +14,15 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.internal;
+package org.apache.logging.log4j;
 
-import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.util.Supplier;
 
-import java.util.function.Supplier;
 
 /**
- * Interface for constructing log events before logging them.
+ * Interface for constructing log events before logging them. Instances of LogBuilders should only be created
+ * by calling one of the Logger methods that return a LogBuilder.
  */
 public interface LogBuilder {
 
@@ -44,26 +44,25 @@ public interface LogBuilder {
         return this;
     }
 
-    default LogBuilder withMessage(Message msg) {
-        return this;
+    default void log(CharSequence message) {
     }
 
-    default LogBuilder withMessage(String msg) {
-        return this;
+    default void log(String message) {
     }
 
-    default LogBuilder withMessage(Object msg) {
-        return this;
+    default void log(String message, Object... params) {
     }
 
-    default LogBuilder withParameters(Object... params) {
-        return this;
+    default void log(String message, Supplier<?>... params) {
     }
 
-    default LogBuilder withParameters(Supplier<Object>... params) {
-        return this;
+    default void log(Message message) {
+    }
+
+    default void log(Supplier<Message> messageSupplier) {
     }
 
-    default void log() {
+    default void log(Object message) {
+
     }
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
index 03e3c42..0d7b090 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
@@ -16,16 +16,12 @@
  */
 package org.apache.logging.log4j;
 
-import org.apache.logging.log4j.internal.DefaultLogBuilder;
-import org.apache.logging.log4j.internal.LogBuilder;
 import org.apache.logging.log4j.message.EntryMessage;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.MessageFactory;
 import org.apache.logging.log4j.util.MessageSupplier;
 import org.apache.logging.log4j.util.Supplier;
 
-import java.util.List;
-
 /**
  * This is the central interface in the log4j package. Most logging operations, except configuration, are done through
  * this interface.
@@ -4217,7 +4213,7 @@ public interface Logger {
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder trace() {
+    default LogBuilder atTrace() {
         return LogBuilder.NOOP;
     }
     /**
@@ -4225,7 +4221,7 @@ public interface Logger {
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder debug() {
+    default LogBuilder atDebug() {
         return LogBuilder.NOOP;
     }
     /**
@@ -4233,7 +4229,7 @@ public interface Logger {
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder info() {
+    default LogBuilder atInfo() {
         return LogBuilder.NOOP;
     }
     /**
@@ -4241,7 +4237,7 @@ public interface Logger {
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder warn() {
+    default LogBuilder atWarn() {
         return LogBuilder.NOOP;
     }
     /**
@@ -4249,7 +4245,7 @@ public interface Logger {
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder error() {
+    default LogBuilder atError() {
         return LogBuilder.NOOP;
     }
     /**
@@ -4257,7 +4253,7 @@ public interface Logger {
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder fatal() {
+    default LogBuilder atFatal() {
         return LogBuilder.NOOP;
     }
     /**
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java b/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
index 6d1681f..6d97f83 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
@@ -17,17 +17,19 @@
 package org.apache.logging.log4j.internal;
 
 import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogBuilder;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LambdaUtil;
 import org.apache.logging.log4j.util.StackLocatorUtil;
 import org.apache.logging.log4j.util.Supplier;
 
 
 /**
- * Collects data for a log event and then logs it.
+ * Collects data for a log event and then logs it. This class should be considered private.
  */
 public class DefaultLogBuilder implements LogBuilder {
     private static Message EMPTY_MESSAGE = new SimpleMessage("");
@@ -39,18 +41,12 @@ public class DefaultLogBuilder implements LogBuilder {
     private Marker marker;
     private Throwable throwable;
     private StackTraceElement location;
-    private Object object;
-    private Message msg;
-    private String textMessage;
-    private Supplier<Message> supplier;
-    private Object[] parameters;
     private volatile boolean inUse;
     private long threadId;
 
     public DefaultLogBuilder(Logger logger, Level level) {
         this.logger = logger;
         this.level = level;
-        this.inUse = false;
         this.threadId = Thread.currentThread().getId();
         this.inUse = true;
     }
@@ -61,17 +57,17 @@ public class DefaultLogBuilder implements LogBuilder {
         this.threadId = Thread.currentThread().getId();
     }
 
-    public LogBuilder setLevel(Level level) {
+    /**
+     * This method should be considered internal. It is used to reset the LogBuilder for a new log message.
+     * @param level The logging level for this event.
+     * @return This LogBuilder instance.
+     */
+    public LogBuilder reset(Level level) {
         this.inUse = true;
         this.level = level;
         this.marker = null;
         this.throwable = null;
         this.location = null;
-        this.object = null;
-        this.msg = null;
-        this.textMessage = null;
-        this.supplier = null;
-        this.parameters = null;
         return this;
     }
 
@@ -95,93 +91,78 @@ public class DefaultLogBuilder implements LogBuilder {
         return this;
     }
 
-    public LogBuilder withMessage(String msg) {
-        this.textMessage = msg;
-        return this;
+    public boolean isInUse() {
+        return inUse;
     }
 
-    public LogBuilder withMessage(Object msg) {
-        this.object = msg;
-        return this;
+    @Override
+    public void log(Message message) {
+        if (isValid()) {
+            logMessage(message);
+        }
     }
 
-    public LogBuilder withMessage(Message msg) {
-        this.msg = msg;
-        return this;
+    @Override
+    public void log(CharSequence message) {
+        if (isValid()) {
+            logMessage(logger.getMessageFactory().newMessage(message));
+        }
     }
 
-    public LogBuilder withMessage(Supplier<Message> supplier) {
-        this.supplier = supplier;
-        return this;
+    @Override
+    public void log(String message) {
+        if (isValid()) {
+            logMessage(logger.getMessageFactory().newMessage(message));
+        }
     }
 
-    public LogBuilder withParameters(Object... params) {
-        if (params != null && params.length > 0) {
-            if (parameters == null) {
-                parameters = params;
-            } else {
-                Object[] prev = parameters;
-                int count = parameters.length + params.length;
-                parameters = new Object[count];
-                System.arraycopy(prev, 0, parameters, 0, prev.length);
-                System.arraycopy(params, 0, parameters, prev.length, params.length);
-            }
+    @Override
+    public void log(String message, Object... params) {
+        if (isValid()) {
+            logMessage(logger.getMessageFactory().newMessage(message, params));
         }
-        return this;
     }
 
-     @SafeVarargs
-     public final LogBuilder withParameters(java.util.function.Supplier<Object>... params) {
-         if (params != null && params.length > 0) {
-             if (parameters == null) {
-                 parameters = new Object[params.length];
-                 for (int i = 0; i < params.length; ++i) {
-                    parameters[i] = params[i].get();
-                 }
-             } else {
-                 Object[] prev = parameters;
-                 int count = parameters.length + params.length;
-                 parameters = new Object[count];
-                 System.arraycopy(prev, 0, parameters, 0, prev.length);
-                 for (int i = 0; i < params.length; ++i) {
-                     parameters[prev.length + i] = params[i].get();
-                 }
-             }
-         }
-        return this;
+    @Override
+    public void log(String message, Supplier<?>... params) {
+        if (isValid()) {
+            logMessage(logger.getMessageFactory().newMessage(message, LambdaUtil.getAll(params)));
+        }
     }
 
-    public boolean isInUse() {
-        return inUse;
+    @Override
+    public void log(Supplier<Message> messageSupplier) {
+        if (isValid()) {
+            logMessage(messageSupplier.get());
+        }
     }
 
-    public void log() {
+    @Override
+    public void log(Object message) {
+        if (isValid()) {
+            logMessage(logger.getMessageFactory().newMessage(message));
+        }
+    }
+
+    private void logMessage(Message message) {
+        try {
+            logger.logMessage(level, marker, FQCN, location, message, throwable);
+        } finally {
+            inUse = false;
+        }
+    }
+
+    private boolean isValid() {
         if (!inUse) {
             LOGGER.warn("Attempt to reuse LogBuilder was ignored. {}",
                     StackLocatorUtil.getCallerClass(2));
-            return;
+            return false ;
         }
         if (this.threadId != Thread.currentThread().getId()) {
             LOGGER.warn("LogBuilder can only be used on the owning thread. {}",
                     StackLocatorUtil.getCallerClass(2));
+            return false;
         }
-        try {
-            Message message;
-            if (msg != null) {
-                message = msg;
-            } else if (supplier != null) {
-                message = supplier.get();
-            } else if (object != null) {
-                message = logger.getMessageFactory().newMessage(object);
-            } else if (textMessage != null) {
-                message = logger.getMessageFactory().newMessage(textMessage, parameters);
-            } else {
-                message = EMPTY_MESSAGE;
-            }
-            logger.logMessage(level, marker, FQCN, location, message, throwable);
-        } finally {
-            inUse = false;
-        }
-
+        return true;
     }
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
index 4918c52..02a9f57 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
@@ -21,7 +21,7 @@ import org.apache.logging.log4j.LoggingException;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.MarkerManager;
 import org.apache.logging.log4j.internal.DefaultLogBuilder;
-import org.apache.logging.log4j.internal.LogBuilder;
+import org.apache.logging.log4j.LogBuilder;
 import org.apache.logging.log4j.message.DefaultFlowMessageFactory;
 import org.apache.logging.log4j.message.EntryMessage;
 import org.apache.logging.log4j.message.FlowMessageFactory;
@@ -2755,7 +2755,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      * @since 3.0
      */
     @Override
-    public  LogBuilder trace() {
+    public  LogBuilder atTrace() {
         return atLevel(Level.TRACE);
     }
     /**
@@ -2764,7 +2764,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      * @since 3.0
      */
     @Override
-    public LogBuilder debug() {
+    public LogBuilder atDebug() {
         return atLevel(Level.DEBUG);
     }
     /**
@@ -2773,7 +2773,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      * @since 3.0
      */
     @Override
-    public LogBuilder info() {
+    public LogBuilder atInfo() {
         return atLevel(Level.INFO);
     }
     /**
@@ -2782,7 +2782,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      * @since 3.0
      */
     @Override
-    public LogBuilder warn() {
+    public LogBuilder atWarn() {
         return atLevel(Level.WARN);
     }
     /**
@@ -2791,7 +2791,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      * @since 3.0
      */
     @Override
-    public LogBuilder error() {
+    public LogBuilder atError() {
         return atLevel(Level.ERROR);
     }
     /**
@@ -2800,7 +2800,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      * @since 3.0
      */
     @Override
-    public LogBuilder fatal() {
+    public LogBuilder atFatal() {
         return atLevel(Level.FATAL);
     }
     /**
@@ -2814,7 +2814,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
         if (builder.isInUse()) {
             return new DefaultLogBuilder(this);
         }
-        return logBuilder.get().setLevel(Level.OFF);
+        return builder.reset(Level.OFF);
     }
     /**
      * Constuct a log event.
@@ -2828,7 +2828,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
             if (builder.isInUse()) {
                 return new DefaultLogBuilder(this, level);
             }
-            return logBuilder.get().setLevel(level);
+            return builder.reset(level);
         } else {
             return LogBuilder.NOOP;
         }
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
index 3388515..978c08d 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
@@ -59,9 +59,9 @@ public class LoggerTest {
 
     @Test
     public void builder() {
-        logger.debug().withLocation().withMessage("Hello").log();
-        logger.error().withMarker(marker).withMessage("Hello {}").withParameters("John").log();
-        logger.warn().withMessage(new SimpleMessage("Log4j rocks!")).withThrowable(new Throwable("This is a test")).log();
+        logger.atDebug().withLocation().log("Hello");
+        logger.atError().withMarker(marker).log("Hello {}", "John");
+        logger.atWarn().withThrowable(new Throwable("This is a test")).log((Message) new SimpleMessage("Log4j rocks!"));
         assertEquals(3, results.size());
         assertThat("Incorrect message 1", results.get(0), equalTo(" DEBUG org.apache.logging.log4j.LoggerTest.builder(LoggerTest.java:62) Hello"));
         assertThat("Incorrect message 2", results.get(1), equalTo("test ERROR Hello John"));
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java
index 59a4465..e385277 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java
@@ -85,10 +85,10 @@ public class LoggerTest {
 
     @Test
     public void builder() {
-        logger.atDebug().withLocation().withMessage("Hello").log();
+        logger.atDebug().withLocation().log("Hello");
         Marker marker = MarkerManager.getMarker("test");
-        logger.atError().withMarker(marker).withMessage("Hello {}").withParameters("John").log();
-        logger.atWarn().withMessage(new SimpleMessage("Log4j rocks!")).withThrowable(new Throwable("This is a test")).log();
+        logger.atError().withMarker(marker).log("Hello {}", "John");
+        logger.atWarn().withThrowable(new Throwable("This is a test")).log((Message) new SimpleMessage("Log4j rocks!"));
         final List<LogEvent> events = app.getEvents();
         assertEventCount(events, 3);
         assertEquals("Incorrect location", "org.apache.logging.log4j.core.LoggerTest.builder(LoggerTest.java:88)", events.get(0).getSource().toString());


[logging-log4j2] 02/04: LOG4J2-2639 - changes due to review comments

Posted by rg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rgoers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit b15623d17918aae414648997157b6f6056a399d8
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Sun Jun 23 21:33:23 2019 -0700

    LOG4J2-2639 - changes due to review comments
---
 .../main/java/org/apache/logging/log4j/Logger.java | 34 ++++++----
 .../logging/log4j/internal/DefaultLogBuilder.java  | 70 +++++++++++++++----
 .../apache/logging/log4j/internal/LogBuilder.java  | 11 ++-
 .../apache/logging/log4j/spi/AbstractLogger.java   | 79 ++++++++++++++++------
 .../java/org/apache/logging/log4j/LoggerTest.java  |  6 +-
 5 files changed, 148 insertions(+), 52 deletions(-)

diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
index 6927c42..03e3c42 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
@@ -4217,48 +4217,56 @@ public interface Logger {
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder atTrace() {
-        return LogBuilder.INSTANCE;
+    default LogBuilder trace() {
+        return LogBuilder.NOOP;
     }
     /**
      * Constuct a trace log event.
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder atDebug() {
-        return LogBuilder.INSTANCE;
+    default LogBuilder debug() {
+        return LogBuilder.NOOP;
     }
     /**
      * Constuct a trace log event.
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder atInfo() {
-        return LogBuilder.INSTANCE;
+    default LogBuilder info() {
+        return LogBuilder.NOOP;
     }
     /**
      * Constuct a trace log event.
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder atWarn() {
-        return LogBuilder.INSTANCE;
+    default LogBuilder warn() {
+        return LogBuilder.NOOP;
     }
     /**
      * Constuct a trace log event.
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder atError() {
-        return LogBuilder.INSTANCE;
+    default LogBuilder error() {
+        return LogBuilder.NOOP;
     }
     /**
      * Constuct a trace log event.
      * @return a LogBuilder.
      * @since 3.0
      */
-    default LogBuilder atFatal() {
-        return LogBuilder.INSTANCE;
+    default LogBuilder fatal() {
+        return LogBuilder.NOOP;
+    }
+    /**
+     * Constuct a log event that will alwways be logged.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    default LogBuilder always() {
+        return LogBuilder.NOOP;
     }
     /**
      * Constuct a log event.
@@ -4266,7 +4274,7 @@ public interface Logger {
      * @since 3.0
      */
     default LogBuilder atLevel(Level level) {
-        return LogBuilder.INSTANCE;
+        return LogBuilder.NOOP;
     }
 
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java b/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
index cd80b84..2549663 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
@@ -21,6 +21,7 @@ import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.StackLocatorUtil;
 import org.apache.logging.log4j.util.Supplier;
 
@@ -31,6 +32,7 @@ import org.apache.logging.log4j.util.Supplier;
 public class DefaultLogBuilder implements LogBuilder {
     private static Message EMPTY_MESSAGE = new SimpleMessage("");
     private static final String FQCN = DefaultLogBuilder.class.getName();
+    private static final Logger LOGGER = StatusLogger.getLogger();
 
     private final Logger logger;
     private Level level;
@@ -42,12 +44,17 @@ public class DefaultLogBuilder implements LogBuilder {
     private String textMessage;
     private Supplier<Message> supplier;
     private Object[] parameters;
+    private volatile boolean inUse;
+    private long threadId;
 
     public DefaultLogBuilder(Logger logger) {
         this.logger = logger;
+        this.inUse = false;
+        this.threadId = Thread.currentThread().getId();
     }
 
     public LogBuilder setLevel(Level level) {
+        this.inUse = true;
         this.level = level;
         this.marker = null;
         this.throwable = null;
@@ -115,19 +122,58 @@ public class DefaultLogBuilder implements LogBuilder {
         return this;
     }
 
+     @SafeVarargs
+     public final LogBuilder withParameters(java.util.function.Supplier<Object>... params) {
+         if (params != null && params.length > 0) {
+             if (parameters == null) {
+                 parameters = new Object[params.length];
+                 for (int i = 0; i < params.length; ++i) {
+                    parameters[i] = params[i].get();
+                 }
+             } else {
+                 Object[] prev = parameters;
+                 int count = parameters.length + params.length;
+                 parameters = new Object[count];
+                 System.arraycopy(prev, 0, parameters, 0, prev.length);
+                 for (int i = 0; i < params.length; ++i) {
+                     parameters[prev.length + i] = params[i].get();
+                 }
+             }
+         }
+        return this;
+    }
+
+    public boolean isInUse() {
+        return inUse;
+    }
+
     public void log() {
-        Message message;
-        if (msg != null) {
-            message = msg;
-        } else if (supplier != null) {
-            message = supplier.get();
-        } else if (object != null) {
-            message = logger.getMessageFactory().newMessage(object);
-        } else if (textMessage != null) {
-            message = logger.getMessageFactory().newMessage(textMessage, parameters);
-        } else {
-            message = EMPTY_MESSAGE;
+        if (!inUse) {
+            LOGGER.warn("Attempt to reuse LogBuilder was ignored. {}",
+                    StackLocatorUtil.getCallerClass(2));
+            return;
         }
-        logger.logMessage(level, marker, FQCN, location, message, throwable);
+        if (this.threadId != Thread.currentThread().getId()) {
+            LOGGER.warn("LogBuilder can only be used on the owning thread. {}",
+                    StackLocatorUtil.getCallerClass(2));
+        }
+        try {
+            Message message;
+            if (msg != null) {
+                message = msg;
+            } else if (supplier != null) {
+                message = supplier.get();
+            } else if (object != null) {
+                message = logger.getMessageFactory().newMessage(object);
+            } else if (textMessage != null) {
+                message = logger.getMessageFactory().newMessage(textMessage, parameters);
+            } else {
+                message = EMPTY_MESSAGE;
+            }
+            logger.logMessage(level, marker, FQCN, location, message, throwable);
+        } finally {
+            inUse = false;
+        }
+
     }
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/internal/LogBuilder.java b/log4j-api/src/main/java/org/apache/logging/log4j/internal/LogBuilder.java
index 8075412..93b40f8 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/internal/LogBuilder.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/internal/LogBuilder.java
@@ -19,12 +19,14 @@ package org.apache.logging.log4j.internal;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.message.Message;
 
+import java.util.function.Supplier;
+
 /**
- * Class Description goes here.
+ * Interface for constructing log events before logging them.
  */
 public interface LogBuilder {
 
-    public static final LogBuilder INSTANCE = new LogBuilder() {};
+    public static final LogBuilder NOOP = new LogBuilder() {};
 
     default LogBuilder withMarker(Marker marker) {
         return this;
@@ -54,11 +56,14 @@ public interface LogBuilder {
         return this;
     }
 
-
     default LogBuilder withParameters(Object... params) {
         return this;
     }
 
+    default LogBuilder withParameters(Supplier<Object>... params) {
+        return this;
+    }
+
     default void log() {
     }
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
index 9a9115a..3a9e465 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
@@ -16,8 +16,6 @@
  */
 package org.apache.logging.log4j.spi;
 
-import java.io.Serializable;
-
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LoggingException;
 import org.apache.logging.log4j.Marker;
@@ -44,6 +42,8 @@ import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.Strings;
 import org.apache.logging.log4j.util.Supplier;
 
+import java.io.Serializable;
+
 /**
  * Base implementation of a Logger. It is highly recommended that any Logger implementation extend this class.
  */
@@ -2755,77 +2755,114 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      * @since 3.0
      */
     @Override
-    public  LogBuilder atTrace() {
+    public  LogBuilder trace() {
         if (isTraceEnabled()) {
-            return logBuilder.get().setLevel(Level.TRACE);
+            DefaultLogBuilder builder = logBuilder.get();
+            if (builder.isInUse()) {
+                return new DefaultLogBuilder(this);
+            }
+            return builder.setLevel(Level.TRACE);
         } else {
-            return LogBuilder.INSTANCE;
+            return LogBuilder.NOOP;
         }
     }
     /**
-     * Constuct a trace log event.
+     * Constuct a debug log event.
      * @return a LogBuilder.
      * @since 3.0
      */
     @Override
-    public LogBuilder atDebug() {
+    public LogBuilder debug() {
         if (isDebugEnabled()) {
+            DefaultLogBuilder builder = logBuilder.get();
+            if (builder.isInUse()) {
+                return new DefaultLogBuilder(this);
+            }
             return logBuilder.get().setLevel(Level.DEBUG);
         } else {
-            return LogBuilder.INSTANCE;
+            return LogBuilder.NOOP;
         }
     }
     /**
-     * Constuct a trace log event.
+     * Constuct an informational log event.
      * @return a LogBuilder.
      * @since 3.0
      */
     @Override
-    public LogBuilder atInfo() {
+    public LogBuilder info() {
         if (isInfoEnabled()) {
+            DefaultLogBuilder builder = logBuilder.get();
+            if (builder.isInUse()) {
+                return new DefaultLogBuilder(this);
+            }
             return logBuilder.get().setLevel(Level.INFO);
         } else {
-            return LogBuilder.INSTANCE;
+            return LogBuilder.NOOP;
         }
     }
     /**
-     * Constuct a trace log event.
+     * Constuct a warning log event.
      * @return a LogBuilder.
      * @since 3.0
      */
     @Override
-    public LogBuilder atWarn() {
+    public LogBuilder warn() {
         if (isWarnEnabled()) {
+            DefaultLogBuilder builder = logBuilder.get();
+            if (builder.isInUse()) {
+                return new DefaultLogBuilder(this);
+            }
             return logBuilder.get().setLevel(Level.WARN);
         } else {
-            return LogBuilder.INSTANCE;
+            return LogBuilder.NOOP;
         }
     }
     /**
-     * Constuct a trace log event.
+     * Constuct an error log event.
      * @return a LogBuilder.
      * @since 3.0
      */
     @Override
-    public LogBuilder atError() {
+    public LogBuilder error() {
         if (isErrorEnabled()) {
+            DefaultLogBuilder builder = logBuilder.get();
+            if (builder.isInUse()) {
+                return new DefaultLogBuilder(this);
+            }
             return logBuilder.get().setLevel(Level.ERROR);
         } else {
-            return LogBuilder.INSTANCE;
+            return LogBuilder.NOOP;
         }
     }
     /**
-     * Constuct a trace log event.
+     * Constuct a fatal log event.
      * @return a LogBuilder.
      * @since 3.0
      */
     @Override
-    public LogBuilder atFatal() {
+    public LogBuilder fatal() {
         if (isFatalEnabled()) {
+            DefaultLogBuilder builder = logBuilder.get();
+            if (builder.isInUse()) {
+                return new DefaultLogBuilder(this);
+            }
             return logBuilder.get().setLevel(Level.FATAL);
         } else {
-            return LogBuilder.INSTANCE;
+            return LogBuilder.NOOP;
+        }
+    }
+    /**
+     * Constuct a fatal log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    @Override
+    public LogBuilder always() {
+        DefaultLogBuilder builder = logBuilder.get();
+        if (builder.isInUse()) {
+            return new DefaultLogBuilder(this);
         }
+        return logBuilder.get().setLevel(Level.OFF);
     }
     /**
      * Constuct a log event.
@@ -2837,7 +2874,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
         if (isEnabled(level)) {
             return logBuilder.get().setLevel(level);
         } else {
-            return LogBuilder.INSTANCE;
+            return LogBuilder.NOOP;
         }
     }
 
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
index 1026d56..3388515 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
@@ -59,9 +59,9 @@ public class LoggerTest {
 
     @Test
     public void builder() {
-        logger.atDebug().withLocation().withMessage("Hello").log();
-        logger.atError().withMarker(marker).withMessage("Hello {}").withParameters("John").log();
-        logger.atWarn().withMessage(new SimpleMessage("Log4j rocks!")).withThrowable(new Throwable("This is a test")).log();
+        logger.debug().withLocation().withMessage("Hello").log();
+        logger.error().withMarker(marker).withMessage("Hello {}").withParameters("John").log();
+        logger.warn().withMessage(new SimpleMessage("Log4j rocks!")).withThrowable(new Throwable("This is a test")).log();
         assertEquals(3, results.size());
         assertThat("Incorrect message 1", results.get(0), equalTo(" DEBUG org.apache.logging.log4j.LoggerTest.builder(LoggerTest.java:62) Hello"));
         assertThat("Incorrect message 2", results.get(1), equalTo("test ERROR Hello John"));


[logging-log4j2] 01/04: LOG4J2-2639 - Allow logging calls to be constructed using a builder pattern

Posted by rg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rgoers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 3bd605d2c4eb24657396d4fe4cee78edc3d2c1b6
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Sat Jun 22 08:35:23 2019 -0700

    LOG4J2-2639 - Allow logging calls to be constructed using a builder pattern
---
 .../main/java/org/apache/logging/log4j/Logger.java |  86 +++++++++-
 .../logging/log4j/internal/DefaultLogBuilder.java  | 133 +++++++++++++++
 .../apache/logging/log4j/internal/LogBuilder.java  |  51 ++++--
 .../log4j/message/AbstractMessageFactory.java      | 124 +-------------
 .../log4j/message/FormattedMessageFactory.java     |   9 +-
 .../log4j/message/LocalizedMessageFactory.java     |   8 +-
 .../logging/log4j/message/MessageFactory.java      | 186 ++++++++++++++++++++-
 .../logging/log4j/message/MessageFactory2.java     | 156 +----------------
 .../log4j/message/MessageFormatMessageFactory.java |   9 +-
 .../log4j/message/ParameterizedMessageFactory.java |   9 +-
 .../ParameterizedNoReferenceMessageFactory.java    |   9 +-
 .../log4j/message/ReusableMessageFactory.java      |   2 +-
 .../log4j/message/SimpleMessageFactory.java        |   9 +-
 .../message/StringFormatterMessageFactory.java     |   9 +-
 .../apache/logging/log4j/spi/AbstractLogger.java   | 144 ++++++++++++++--
 .../logging/log4j/spi/MessageFactory2Adapter.java  | 118 -------------
 .../apache/logging/log4j/AbstractLoggerTest.java   |   5 +-
 .../java/org/apache/logging/log4j/LoggerTest.java  |  20 ++-
 .../java/org/apache/logging/log4j/TestLogger.java  |  15 +-
 .../java/org/apache/logging/log4j/core/Logger.java |   7 +
 .../config/AwaitCompletionReliabilityStrategy.java |  19 +++
 .../AwaitUnconditionallyReliabilityStrategy.java   |  14 ++
 .../core/config/DefaultReliabilityStrategy.java    |  14 ++
 .../core/config/LockingReliabilityStrategy.java    |  19 +++
 .../logging/log4j/core/config/LoggerConfig.java    |  46 +++++
 .../log4j/core/config/ReliabilityStrategy.java     |  16 ++
 .../log4j/core/impl/DefaultLogEventFactory.java    |  19 +++
 .../logging/log4j/core/impl/Log4jLogEvent.java     |  24 +++
 .../logging/log4j/core/impl/LogEventFactory.java   |   5 +
 .../org/apache/logging/log4j/core/LoggerTest.java  |  41 +++--
 .../logging/log4j/taglib/SetLoggerTagTest.java     |  16 +-
 .../java/org/apache/logging/slf4j/LoggerTest.java  |  14 +-
 32 files changed, 853 insertions(+), 503 deletions(-)

diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
index 9bedc23..6927c42 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/Logger.java
@@ -16,13 +16,16 @@
  */
 package org.apache.logging.log4j;
 
+import org.apache.logging.log4j.internal.DefaultLogBuilder;
+import org.apache.logging.log4j.internal.LogBuilder;
 import org.apache.logging.log4j.message.EntryMessage;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.MessageFactory;
-import org.apache.logging.log4j.message.MessageFactory2;
 import org.apache.logging.log4j.util.MessageSupplier;
 import org.apache.logging.log4j.util.Supplier;
 
+import java.util.List;
+
 /**
  * This is the central interface in the log4j package. Most logging operations, except configuration, are done through
  * this interface.
@@ -1682,13 +1685,7 @@ public interface Logger {
     /**
      * Gets the message factory used to convert message Objects and Strings/CharSequences into actual log Messages.
      *
-     * Since version 2.6, Log4j internally uses message factories that implement the {@link MessageFactory2} interface.
-     * From version 2.6.2, the return type of this method was changed from {@link MessageFactory} to
-     * {@code <MF extends MessageFactory> MF}. The returned factory will always implement {@link MessageFactory2},
-     * but the return type of this method could not be changed to {@link MessageFactory2} without breaking binary
-     * compatibility.
-     *
-     * @return the message factory, as an instance of {@link MessageFactory2}
+     * @return the message factory, as an instance of {@link MessageFactory}
      */
     <MF extends MessageFactory> MF getMessageFactory();
 
@@ -4199,4 +4196,77 @@ public interface Logger {
     void warn(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7,
             Object p8, Object p9);
 
+    /**
+     * Logs a Message.
+     * @param level The logging Level to check.
+     * @param marker A Marker or null.
+     * @param fqcn The fully qualified class name of the logger entry point, used to determine the caller class and
+     *            method when location information needs to be logged.
+     * @param location The location of the caller.
+     * @param message The message format.
+     * @param throwable the exception to log, including its stack trace.
+     * @since 3.0
+     */
+    default void logMessage(Level level, Marker marker, String fqcn, StackTraceElement location, Message message,
+            Throwable throwable) {
+
+    }
+
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    default LogBuilder atTrace() {
+        return LogBuilder.INSTANCE;
+    }
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    default LogBuilder atDebug() {
+        return LogBuilder.INSTANCE;
+    }
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    default LogBuilder atInfo() {
+        return LogBuilder.INSTANCE;
+    }
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    default LogBuilder atWarn() {
+        return LogBuilder.INSTANCE;
+    }
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    default LogBuilder atError() {
+        return LogBuilder.INSTANCE;
+    }
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    default LogBuilder atFatal() {
+        return LogBuilder.INSTANCE;
+    }
+    /**
+     * Constuct a log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    default LogBuilder atLevel(Level level) {
+        return LogBuilder.INSTANCE;
+    }
+
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java b/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
new file mode 100644
index 0000000..cd80b84
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
@@ -0,0 +1,133 @@
+/*
+ * 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.internal;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.util.StackLocatorUtil;
+import org.apache.logging.log4j.util.Supplier;
+
+
+/**
+ * Collects data for a log event and then logs it.
+ */
+public class DefaultLogBuilder implements LogBuilder {
+    private static Message EMPTY_MESSAGE = new SimpleMessage("");
+    private static final String FQCN = DefaultLogBuilder.class.getName();
+
+    private final Logger logger;
+    private Level level;
+    private Marker marker;
+    private Throwable throwable;
+    private StackTraceElement location;
+    private Object object;
+    private Message msg;
+    private String textMessage;
+    private Supplier<Message> supplier;
+    private Object[] parameters;
+
+    public DefaultLogBuilder(Logger logger) {
+        this.logger = logger;
+    }
+
+    public LogBuilder setLevel(Level level) {
+        this.level = level;
+        this.marker = null;
+        this.throwable = null;
+        this.location = null;
+        this.object = null;
+        this.msg = null;
+        this.textMessage = null;
+        this.supplier = null;
+        this.parameters = null;
+        return this;
+    }
+
+    public LogBuilder withMarker(Marker marker) {
+        this.marker = marker;
+        return this;
+    }
+
+    public LogBuilder withThrowable(Throwable throwable) {
+        this.throwable = throwable;
+        return this;
+    }
+
+    public LogBuilder withLocation() {
+        location = StackLocatorUtil.getStackTraceElement(2);
+        return this;
+    }
+
+    public LogBuilder withLocation(StackTraceElement location) {
+        this.location = location;
+        return this;
+    }
+
+    public LogBuilder withMessage(String msg) {
+        this.textMessage = msg;
+        return this;
+    }
+
+    public LogBuilder withMessage(Object msg) {
+        this.object = msg;
+        return this;
+    }
+
+    public LogBuilder withMessage(Message msg) {
+        this.msg = msg;
+        return this;
+    }
+
+    public LogBuilder withMessage(Supplier<Message> supplier) {
+        this.supplier = supplier;
+        return this;
+    }
+
+    public LogBuilder withParameters(Object... params) {
+        if (params != null && params.length > 0) {
+            if (parameters == null) {
+                parameters = params;
+            } else {
+                Object[] prev = parameters;
+                int count = parameters.length + params.length;
+                parameters = new Object[count];
+                System.arraycopy(prev, 0, parameters, 0, prev.length);
+                System.arraycopy(params, 0, parameters, prev.length, params.length);
+            }
+        }
+        return this;
+    }
+
+    public void log() {
+        Message message;
+        if (msg != null) {
+            message = msg;
+        } else if (supplier != null) {
+            message = supplier.get();
+        } else if (object != null) {
+            message = logger.getMessageFactory().newMessage(object);
+        } else if (textMessage != null) {
+            message = logger.getMessageFactory().newMessage(textMessage, parameters);
+        } else {
+            message = EMPTY_MESSAGE;
+        }
+        logger.logMessage(level, marker, FQCN, location, message, throwable);
+    }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/internal/LogBuilder.java
similarity index 51%
copy from log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventFactory.java
copy to log4j-api/src/main/java/org/apache/logging/log4j/internal/LogBuilder.java
index ad9128c..8075412 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/internal/LogBuilder.java
@@ -14,22 +14,51 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
+package org.apache.logging.log4j.internal;
 
-package org.apache.logging.log4j.core.impl;
-
-import java.util.List;
-
-import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.message.Message;
 
 /**
- *
+ * Class Description goes here.
  */
-public interface LogEventFactory {
+public interface LogBuilder {
+
+    public static final LogBuilder INSTANCE = new LogBuilder() {};
+
+    default LogBuilder withMarker(Marker marker) {
+        return this;
+    }
+
+    default LogBuilder withThrowable(Throwable throwable) {
+        return this;
+    }
+
+    default LogBuilder withLocation() {
+        return this;
+    }
+
+    default LogBuilder withLocation(StackTraceElement location) {
+        return this;
+    }
+
+    default LogBuilder withMessage(Message msg) {
+        return this;
+    }
+
+    default LogBuilder withMessage(String msg) {
+        return this;
+    }
+
+    default LogBuilder withMessage(Object msg) {
+        return this;
+    }
+
+
+    default LogBuilder withParameters(Object... params) {
+        return this;
+    }
 
-    LogEvent createEvent(String loggerName, Marker marker, String fqcn, Level level, Message data,
-                         List<Property> properties, Throwable t);
+    default void log() {
+    }
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/AbstractMessageFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/AbstractMessageFactory.java
index 6429ed7..cc4f328 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/AbstractMessageFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/AbstractMessageFactory.java
@@ -19,128 +19,12 @@ package org.apache.logging.log4j.message;
 import java.io.Serializable;
 
 /**
- * Provides an abstract superclass for {@link MessageFactory2} implementations with default implementations (and for
- * {@link MessageFactory} by extension).
- * <p>
- * This class is immutable.
- * </p>
- * <h4>Note to implementors</h4>
- * <p>
- * Subclasses can implement the {@link MessageFactory2} methods when they can most effectively build {@link Message}
- * instances. If a subclass does not implement {@link MessageFactory2} methods, these calls are routed through
- * {@link #newMessage(String, Object...)} in this class.
+ * Provides an abstract superclass for {@link MessageFactory}. This class is now unnecessary as all default
+ * methods are provided by the (@link MessageFactory) interface.
  * </p>
+ * @deprecated MessageFactory has default methods that implement all the methods that were here.
  */
-public abstract class AbstractMessageFactory implements MessageFactory2, Serializable {
+public abstract class AbstractMessageFactory implements MessageFactory, Serializable {
     private static final long serialVersionUID = -1307891137684031187L;
 
-    @Override
-    public Message newMessage(final CharSequence message) {
-        return new SimpleMessage(message);
-    }
-
-    /*
-     * (non-Javadoc)
-     *
-     * @see org.apache.logging.log4j.message.MessageFactory#newMessage(java.lang.Object)
-     */
-    @Override
-    public Message newMessage(final Object message) {
-        return new ObjectMessage(message);
-    }
-
-    /*
-     * (non-Javadoc)
-     *
-     * @see org.apache.logging.log4j.message.MessageFactory#newMessage(java.lang.String)
-     */
-    @Override
-    public Message newMessage(final String message) {
-        return new SimpleMessage(message);
-    }
-
-    /**
-     * @since 2.6.1
-     */
-    @Override
-    public Message newMessage(final String message, final Object p0) {
-        return newMessage(message, new Object[] { p0 });
-    }
-
-    /**
-     * @since 2.6.1
-     */
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1) {
-        return newMessage(message, new Object[] { p0, p1 });
-    }
-
-    /**
-     * @since 2.6.1
-     */
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2) {
-        return newMessage(message, new Object[] { p0, p1, p2 });
-    }
-
-    /**
-     * @since 2.6.1
-     */
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3) {
-        return newMessage(message, new Object[] { p0, p1, p2, p3 });
-    }
-
-    /**
-     * @since 2.6.1
-     */
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4) {
-        return newMessage(message, new Object[] { p0, p1, p2, p3, p4 });
-    }
-
-    /**
-     * @since 2.6.1
-     */
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5) {
-        return newMessage(message, new Object[] { p0, p1, p2, p3, p4, p5 });
-    }
-
-    /**
-     * @since 2.6.1
-     */
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
-            final Object p6) {
-        return newMessage(message, new Object[] { p0, p1, p2, p3, p4, p5, p6 });
-    }
-
-    /**
-     * @since 2.6.1
-     */
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
-            final Object p6, final Object p7) {
-        return newMessage(message, new Object[] { p0, p1, p2, p3, p4, p5, p6, p7 });
-    }
-
-    /**
-     * @since 2.6.1
-     */
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
-            final Object p6, final Object p7, final Object p8) {
-        return newMessage(message, new Object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8 });
-    }
-
-    /**
-     * @since 2.6.1
-     */
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3, final Object p4, final Object p5,
-            final Object p6, final Object p7, final Object p8, final Object p9) {
-        return newMessage(message, new Object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 });
-    }
-
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessageFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessageFactory.java
index 805e24b..cf6ed3a 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessageFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessageFactory.java
@@ -16,16 +16,17 @@
  */
 package org.apache.logging.log4j.message;
 
+import java.io.Serializable;
+
 /**
- * Creates {@link FormattedMessage} instances for {@link MessageFactory2} methods (and {@link MessageFactory} by
- * extension.)
+ * Creates {@link FormattedMessage} instances for {@link MessageFactory} methods.
  * 
  * <h4>Note to implementors</h4>
  * <p>
- * This class implements all {@link MessageFactory2} methods.
+ * This class implements all {@link MessageFactory} methods.
  * </p>
  */
-public class FormattedMessageFactory extends AbstractMessageFactory {
+public class FormattedMessageFactory implements MessageFactory, Serializable {
 
     private static final long serialVersionUID = 1L;
 
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessageFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessageFactory.java
index b7e9803..d92878d 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessageFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessageFactory.java
@@ -16,19 +16,19 @@
  */
 package org.apache.logging.log4j.message;
 
+import java.io.Serializable;
 import java.util.ResourceBundle;
 
 /**
- * Creates {@link FormattedMessage} instances for {@link MessageFactory2} methods (and {@link MessageFactory} by
- * extension.)
+ * Creates {@link FormattedMessage} instances for {@link MessageFactory} methods.
  * 
  * <h4>Note to implementors</h4>
  * <p>
- * This class does <em>not</em> implement any {@link MessageFactory2} methods and lets the superclass funnel those calls
+ * This class does <em>not</em> implement any {@link MessageFactory} methods and lets the superclass funnel those calls
  * through {@link #newMessage(String, Object...)}.
  * </p>
  */
-public class LocalizedMessageFactory extends AbstractMessageFactory {
+public class LocalizedMessageFactory implements MessageFactory, Serializable {
     private static final long serialVersionUID = -1996295808703146741L;
 
     // FIXME: cannot use ResourceBundle name for serialization until Java 8
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory.java
index 009d5a6..fa7c672 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory.java
@@ -31,7 +31,9 @@ public interface MessageFactory {
      *            a message object
      * @return a new message
      */
-    Message newMessage(Object message);
+    default Message newMessage(Object message) {
+        return new ObjectMessage(message);
+    }
 
     /**
      * Creates a new message based on a String.
@@ -40,7 +42,9 @@ public interface MessageFactory {
      *            a message String
      * @return a new message
      */
-    Message newMessage(String message);
+    default Message newMessage(String message) {
+        return new SimpleMessage(message);
+    }
 
     /**
      * Creates a new parameterized message.
@@ -54,4 +58,182 @@ public interface MessageFactory {
      * @see StringFormatterMessageFactory
      */
     Message newMessage(String message, Object... params);
+
+    /**
+     * Creates a new message for the specified CharSequence.
+     * @param charSequence the (potentially mutable) CharSequence
+     * @return a new message for the specified CharSequence
+     */
+    default Message newMessage(CharSequence charSequence) {
+        return new SimpleMessage(charSequence);
+    }
+
+    /**
+     * Creates a new parameterized message.
+     *
+     * @param message a message template, the kind of message template depends on the implementation.
+     * @param p0 a message parameter
+     * @return a new message
+     * @see ParameterizedMessageFactory
+     */
+    default Message newMessage(String message, Object p0) {
+        return newMessage(message, new Object[] { p0 });
+    }
+
+    /**
+     * Creates a new parameterized message.
+     *
+     * @param message a message template, the kind of message template depends on the implementation.
+     * @param p0 a message parameter
+     * @param p1 a message parameter
+     * @return a new message
+     * @see ParameterizedMessageFactory
+     */
+    default Message newMessage(String message, Object p0, Object p1) {
+        return newMessage(message, new Object[] { p0, p1 });
+    }
+
+    /**
+     * Creates a new parameterized message.
+     *
+     * @param message a message template, the kind of message template depends on the implementation.
+     * @param p0 a message parameter
+     * @param p1 a message parameter
+     * @param p2 a message parameter
+     * @return a new message
+     * @see ParameterizedMessageFactory
+     */
+    default Message newMessage(String message, Object p0, Object p1, Object p2) {
+        return newMessage(message, new Object[] { p0, p1, p2 });
+    }
+
+    /**
+     * Creates a new parameterized message.
+     *
+     * @param message a message template, the kind of message template depends on the implementation.
+     * @param p0 a message parameter
+     * @param p1 a message parameter
+     * @param p2 a message parameter
+     * @param p3 a message parameter
+     * @return a new message
+     * @see ParameterizedMessageFactory
+     */
+    default Message newMessage(String message, Object p0, Object p1, Object p2, Object p3) {
+        return newMessage(message, new Object[] { p0, p1, p2, p3 });
+    }
+
+    /**
+     * Creates a new parameterized message.
+     *
+     * @param message a message template, the kind of message template depends on the implementation.
+     * @param p0 a message parameter
+     * @param p1 a message parameter
+     * @param p2 a message parameter
+     * @param p3 a message parameter
+     * @param p4 a message parameter
+     * @return a new message
+     * @see ParameterizedMessageFactory
+     */
+    default Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4) {
+        return newMessage(message, new Object[] { p0, p1, p2, p3, p4 });
+    }
+
+    /**
+     * Creates a new parameterized message.
+     *
+     * @param message a message template, the kind of message template depends on the implementation.
+     * @param p0 a message parameter
+     * @param p1 a message parameter
+     * @param p2 a message parameter
+     * @param p3 a message parameter
+     * @param p4 a message parameter
+     * @param p5 a message parameter
+     * @return a new message
+     * @see ParameterizedMessageFactory
+     */
+    default Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5) {
+        return newMessage(message, new Object[] { p0, p1, p2, p3, p4, p5 });
+    }
+
+    /**
+     * Creates a new parameterized message.
+     *
+     * @param message a message template, the kind of message template depends on the implementation.
+     * @param p0 a message parameter
+     * @param p1 a message parameter
+     * @param p2 a message parameter
+     * @param p3 a message parameter
+     * @param p4 a message parameter
+     * @param p5 a message parameter
+     * @param p6 a message parameter
+     * @return a new message
+     * @see ParameterizedMessageFactory
+     */
+    default Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5,
+            Object p6) {
+        return newMessage(message, new Object[] { p0, p1, p2, p3, p4, p5, p6 });
+    }
+
+    /**
+     * Creates a new parameterized message.
+     *
+     * @param message a message template, the kind of message template depends on the implementation.
+     * @param p0 a message parameter
+     * @param p1 a message parameter
+     * @param p2 a message parameter
+     * @param p3 a message parameter
+     * @param p4 a message parameter
+     * @param p5 a message parameter
+     * @param p6 a message parameter
+     * @param p7 a message parameter
+     * @return a new message
+     * @see ParameterizedMessageFactory
+     */
+    default Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5,
+            Object p6, Object p7) {
+        return newMessage(message, new Object[] { p0, p1, p2, p3, p4, p5, p6, p7 });
+    }
+
+    /**
+     * Creates a new parameterized message.
+     *
+     * @param message a message template, the kind of message template depends on the implementation.
+     * @param p0 a message parameter
+     * @param p1 a message parameter
+     * @param p2 a message parameter
+     * @param p3 a message parameter
+     * @param p4 a message parameter
+     * @param p5 a message parameter
+     * @param p6 a message parameter
+     * @param p7 a message parameter
+     * @param p8 a message parameter
+     * @return a new message
+     * @see ParameterizedMessageFactory
+     */
+    default Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5,
+            Object p6, Object p7, Object p8) {
+        return newMessage(message, new Object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8 });
+    }
+
+    /**
+     * Creates a new parameterized message.
+     *
+     * @param message a message template, the kind of message template depends on the implementation.
+     * @param p0 a message parameter
+     * @param p1 a message parameter
+     * @param p2 a message parameter
+     * @param p3 a message parameter
+     * @param p4 a message parameter
+     * @param p5 a message parameter
+     * @param p6 a message parameter
+     * @param p7 a message parameter
+     * @param p8 a message parameter
+     * @param p9 a message parameter
+     * @return a new message
+     * @see ParameterizedMessageFactory
+     */
+    default Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5,
+            Object p6, Object p7, Object p8, Object p9) {
+        return newMessage(message, new Object[] { p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 });
+    }
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory2.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory2.java
index 33004dd..2e2ad70 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory2.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory2.java
@@ -20,162 +20,8 @@ package org.apache.logging.log4j.message;
  * Creates messages. Implementations can provide different message format syntaxes.
  *
  * @see ParameterizedMessageFactory
+ * @deprecated MessageFactory now contains all interface methods.
  * @since 2.6
  */
 public interface MessageFactory2 extends MessageFactory {
-    
-    /**
-     * Creates a new message for the specified CharSequence.
-     * @param charSequence the (potentially mutable) CharSequence
-     * @return a new message for the specified CharSequence
-     */
-    Message newMessage(CharSequence charSequence);
-
-    /**
-     * Creates a new parameterized message.
-     *
-     * @param message a message template, the kind of message template depends on the implementation.
-     * @param p0 a message parameter
-     * @return a new message
-     * @see ParameterizedMessageFactory
-     */
-    Message newMessage(String message, Object p0);
-
-    /**
-     * Creates a new parameterized message.
-     *
-     * @param message a message template, the kind of message template depends on the implementation.
-     * @param p0 a message parameter
-     * @param p1 a message parameter
-     * @return a new message
-     * @see ParameterizedMessageFactory
-     */
-    Message newMessage(String message, Object p0, Object p1);
-
-    /**
-     * Creates a new parameterized message.
-     *
-     * @param message a message template, the kind of message template depends on the implementation.
-     * @param p0 a message parameter
-     * @param p1 a message parameter
-     * @param p2 a message parameter
-     * @return a new message
-     * @see ParameterizedMessageFactory
-     */
-    Message newMessage(String message, Object p0, Object p1, Object p2);
-
-    /**
-     * Creates a new parameterized message.
-     *
-     * @param message a message template, the kind of message template depends on the implementation.
-     * @param p0 a message parameter
-     * @param p1 a message parameter
-     * @param p2 a message parameter
-     * @param p3 a message parameter
-     * @return a new message
-     * @see ParameterizedMessageFactory
-     */
-    Message newMessage(String message, Object p0, Object p1, Object p2, Object p3);
-
-    /**
-     * Creates a new parameterized message.
-     *
-     * @param message a message template, the kind of message template depends on the implementation.
-     * @param p0 a message parameter
-     * @param p1 a message parameter
-     * @param p2 a message parameter
-     * @param p3 a message parameter
-     * @param p4 a message parameter
-     * @return a new message
-     * @see ParameterizedMessageFactory
-     */
-    Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4);
-
-    /**
-     * Creates a new parameterized message.
-     *
-     * @param message a message template, the kind of message template depends on the implementation.
-     * @param p0 a message parameter
-     * @param p1 a message parameter
-     * @param p2 a message parameter
-     * @param p3 a message parameter
-     * @param p4 a message parameter
-     * @param p5 a message parameter
-     * @return a new message
-     * @see ParameterizedMessageFactory
-     */
-    Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5);
-
-    /**
-     * Creates a new parameterized message.
-     *
-     * @param message a message template, the kind of message template depends on the implementation.
-     * @param p0 a message parameter
-     * @param p1 a message parameter
-     * @param p2 a message parameter
-     * @param p3 a message parameter
-     * @param p4 a message parameter
-     * @param p5 a message parameter
-     * @param p6 a message parameter
-     * @return a new message
-     * @see ParameterizedMessageFactory
-     */
-    Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6);
-
-    /**
-     * Creates a new parameterized message.
-     *
-     * @param message a message template, the kind of message template depends on the implementation.
-     * @param p0 a message parameter
-     * @param p1 a message parameter
-     * @param p2 a message parameter
-     * @param p3 a message parameter
-     * @param p4 a message parameter
-     * @param p5 a message parameter
-     * @param p6 a message parameter
-     * @param p7 a message parameter
-     * @return a new message
-     * @see ParameterizedMessageFactory
-     */
-    Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6,
-            Object p7);
-
-    /**
-     * Creates a new parameterized message.
-     *
-     * @param message a message template, the kind of message template depends on the implementation.
-     * @param p0 a message parameter
-     * @param p1 a message parameter
-     * @param p2 a message parameter
-     * @param p3 a message parameter
-     * @param p4 a message parameter
-     * @param p5 a message parameter
-     * @param p6 a message parameter
-     * @param p7 a message parameter
-     * @param p8 a message parameter
-     * @return a new message
-     * @see ParameterizedMessageFactory
-     */
-    Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6,
-            Object p7, Object p8);
-
-    /**
-     * Creates a new parameterized message.
-     *
-     * @param message a message template, the kind of message template depends on the implementation.
-     * @param p0 a message parameter
-     * @param p1 a message parameter
-     * @param p2 a message parameter
-     * @param p3 a message parameter
-     * @param p4 a message parameter
-     * @param p5 a message parameter
-     * @param p6 a message parameter
-     * @param p7 a message parameter
-     * @param p8 a message parameter
-     * @param p9 a message parameter
-     * @return a new message
-     * @see ParameterizedMessageFactory
-     */
-    Message newMessage(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6,
-            Object p7, Object p8, Object p9);
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessageFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessageFactory.java
index f75e68b..bab3c89 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessageFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessageFactory.java
@@ -16,16 +16,17 @@
  */
 package org.apache.logging.log4j.message;
 
+import java.io.Serializable;
+
 /**
- * Creates {@link FormattedMessage} instances for {@link MessageFactory2} methods (and {@link MessageFactory} by
- * extension.)
+ * Creates {@link FormattedMessage} instances for {@link MessageFactory} methods.
  * 
  * <h4>Note to implementors</h4>
  * <p>
- * This class implements all {@link MessageFactory2} methods.
+ * This class implements all {@link MessageFactory} methods.
  * </p>
  */
-public class MessageFormatMessageFactory extends AbstractMessageFactory {
+public class MessageFormatMessageFactory implements MessageFactory, Serializable {
     private static final long serialVersionUID = 3584821740584192453L;
 
     /**
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessageFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessageFactory.java
index 5878cac..8716f18 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessageFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessageFactory.java
@@ -16,9 +16,10 @@
  */
 package org.apache.logging.log4j.message;
 
+import java.io.Serializable;
+
 /**
- * Creates {@link FormattedMessage} instances for {@link MessageFactory2} methods (and {@link MessageFactory} by
- * extension.)
+ * Creates {@link FormattedMessage} instances for {@link MessageFactory}.
  * <p>
  * Enables the use of <code>{}</code> parameter markers in message strings.
  * </p>
@@ -31,10 +32,10 @@ package org.apache.logging.log4j.message;
  * 
  * <h4>Note to implementors</h4>
  * <p>
- * This class implements all {@link MessageFactory2} methods.
+ * This class implements all {@link MessageFactory} methods.
  * </p>
  */
-public final class ParameterizedMessageFactory extends AbstractMessageFactory {
+public final class ParameterizedMessageFactory implements MessageFactory, Serializable {
     /**
      * Instance of ParameterizedMessageFactory.
      */
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedNoReferenceMessageFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedNoReferenceMessageFactory.java
index fdf397b..3ad9e85 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedNoReferenceMessageFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterizedNoReferenceMessageFactory.java
@@ -18,9 +18,10 @@ package org.apache.logging.log4j.message;
 
 import org.apache.logging.log4j.status.StatusLogger;
 
+import java.io.Serializable;
+
 /**
- * Creates {@link FormattedMessage} instances for {@link MessageFactory2} methods (and {@link MessageFactory} by
- * extension.)
+ * Creates {@link FormattedMessage} instances for {@link MessageFactory} methods.
  * <p>
  * Creates {@link SimpleMessage} objects that do not retain a reference to the parameter object.
  * </p>
@@ -33,11 +34,11 @@ import org.apache.logging.log4j.status.StatusLogger;
  * </p>
  * <h4>Note to implementors</h4>
  * <p>
- * This class does <em>not</em> implement any {@link MessageFactory2} methods and lets the superclass funnel those calls
+ * This class does <em>not</em> implement any {@link MessageFactory} methods and lets the superclass funnel those calls
  * through {@link #newMessage(String, Object...)}.
  * </p>
  */
-public final class ParameterizedNoReferenceMessageFactory extends AbstractMessageFactory {
+public final class ParameterizedNoReferenceMessageFactory implements MessageFactory, Serializable {
     private static final long serialVersionUID = 5027639245636870500L;
 
     /**
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableMessageFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableMessageFactory.java
index bf30cfa..88a153b 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableMessageFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableMessageFactory.java
@@ -30,7 +30,7 @@ import org.apache.logging.log4j.util.PerformanceSensitive;
  * @since 2.6
  */
 @PerformanceSensitive("allocation")
-public final class ReusableMessageFactory implements MessageFactory2, Serializable {
+public final class ReusableMessageFactory implements MessageFactory, Serializable {
 
     /**
      * Instance of ReusableMessageFactory..
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessageFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessageFactory.java
index e85b8c0..43a7259 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessageFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessageFactory.java
@@ -16,9 +16,10 @@
  */
 package org.apache.logging.log4j.message;
 
+import java.io.Serializable;
+
 /**
- * Creates {@link FormattedMessage} instances for {@link MessageFactory2} methods (and {@link MessageFactory} by
- * extension.)
+ * Creates {@link FormattedMessage} instances for {@link MessageFactory} methods.
  * <p>
  * This uses is the simplest possible implementation of {@link Message}, the where you give the message to the
  * constructor argument as a String.
@@ -32,12 +33,12 @@ package org.apache.logging.log4j.message;
  * 
  * <h4>Note to implementors</h4>
  * <p>
- * This class implements all {@link MessageFactory2} methods.
+ * This class implements all {@link MessageFactory} methods.
  * </p>
  * 
  * @since 2.5
  */
-public final class SimpleMessageFactory extends AbstractMessageFactory {
+public final class SimpleMessageFactory implements MessageFactory, Serializable {
 
     /**
      * Instance of StringFormatterMessageFactory.
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormatterMessageFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormatterMessageFactory.java
index b6554d5..a2b0e96 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormatterMessageFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormatterMessageFactory.java
@@ -16,9 +16,10 @@
  */
 package org.apache.logging.log4j.message;
 
+import java.io.Serializable;
+
 /**
- * Creates {@link FormattedMessage} instances for {@link MessageFactory2} methods (and {@link MessageFactory} by
- * extension.)
+ * Creates {@link FormattedMessage} instances for {@link MessageFactory} methods.
  * <p>
  * Enables the use of {@link java.util.Formatter} strings in message strings.
  * </p>
@@ -30,10 +31,10 @@ package org.apache.logging.log4j.message;
  * </p>
  * <h4>Note to implementors</h4>
  * <p>
- * This class implements all {@link MessageFactory2} methods.
+ * This class implements all {@link MessageFactory} methods.
  * </p>
  */
-public final class StringFormatterMessageFactory extends AbstractMessageFactory {
+public final class StringFormatterMessageFactory implements MessageFactory, Serializable {
 
     /**
      * Instance of StringFormatterMessageFactory.
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
index 9b1b060..9a9115a 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
@@ -22,12 +22,13 @@ import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LoggingException;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.MarkerManager;
+import org.apache.logging.log4j.internal.DefaultLogBuilder;
+import org.apache.logging.log4j.internal.LogBuilder;
 import org.apache.logging.log4j.message.DefaultFlowMessageFactory;
 import org.apache.logging.log4j.message.EntryMessage;
 import org.apache.logging.log4j.message.FlowMessageFactory;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.MessageFactory;
-import org.apache.logging.log4j.message.MessageFactory2;
 import org.apache.logging.log4j.message.ParameterizedMessage;
 import org.apache.logging.log4j.message.ParameterizedMessageFactory;
 import org.apache.logging.log4j.message.ReusableMessageFactory;
@@ -102,9 +103,11 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
     private static final String CATCHING = "Catching";
 
     protected final String name;
-    private final MessageFactory2 messageFactory;
+    private final MessageFactory messageFactory;
     private final FlowMessageFactory flowMessageFactory;
     private static ThreadLocal<int[]> recursionDepthHolder = new ThreadLocal<>(); // LOG4J2-1518, LOG4J2-2031
+    private final ThreadLocal<DefaultLogBuilder> logBuilder;
+
 
     /**
      * Creates a new logger named after this class (or subclass).
@@ -113,6 +116,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
         this.name = getClass().getName();
         this.messageFactory = createDefaultMessageFactory();
         this.flowMessageFactory = createDefaultFlowMessageFactory();
+        this.logBuilder = new LocalLogBuilder(this);
     }
 
     /**
@@ -132,8 +136,9 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      */
     public AbstractLogger(final String name, final MessageFactory messageFactory) {
         this.name = name;
-        this.messageFactory = messageFactory == null ? createDefaultMessageFactory() : narrow(messageFactory);
+        this.messageFactory = messageFactory == null ? createDefaultMessageFactory() : messageFactory;
         this.flowMessageFactory = createDefaultFlowMessageFactory();
+        this.logBuilder = new LocalLogBuilder(this);
     }
 
     /**
@@ -214,22 +219,14 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
         }
     }
 
-    private static MessageFactory2 createDefaultMessageFactory() {
+    private static MessageFactory createDefaultMessageFactory() {
         try {
-            final MessageFactory result = DEFAULT_MESSAGE_FACTORY_CLASS.newInstance();
-            return narrow(result);
+            return DEFAULT_MESSAGE_FACTORY_CLASS.newInstance();
         } catch (final InstantiationException | IllegalAccessException e) {
             throw new IllegalStateException(e);
         }
     }
 
-    private static MessageFactory2 narrow(final MessageFactory result) {
-        if (result instanceof MessageFactory2) {
-            return (MessageFactory2) result;
-        }
-        return new MessageFactory2Adapter(result);
-    }
-
     private static FlowMessageFactory createDefaultFlowMessageFactory() {
         try {
             return DEFAULT_FLOW_MESSAGE_FACTORY_CLASS.newInstance();
@@ -2028,6 +2025,23 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
         logMessageSafely(fqcn, level, marker, msg, msg.getThrowable());
     }
 
+    public void logMessage(final Level level, final Marker marker, final String fqcn, final StackTraceElement location,
+            final Message message, final Throwable throwable) {
+        try {
+            incrementRecursionDepth();
+            log(level, marker, fqcn, location, message, throwable);
+        } catch (Exception ex) {
+            handleLogMessageException(ex, fqcn, message);
+        } finally {
+            decrementRecursionDepth();
+            ReusableMessageFactory.release(message);
+        }
+    }
+
+    protected void log(final Level level, final Marker marker, final String fqcn, final StackTraceElement location,
+            final Message message, final Throwable throwable) {
+    }
+
     @Override
     public void printf(final Level level, final Marker marker, final String format, final Object... params) {
         if (isEnabled(level, marker, format, params)) {
@@ -2734,4 +2748,108 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
             final Object p7, final Object p8, final Object p9) {
         logIfEnabled(FQCN, Level.WARN, null, message, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
     }
+
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    @Override
+    public  LogBuilder atTrace() {
+        if (isTraceEnabled()) {
+            return logBuilder.get().setLevel(Level.TRACE);
+        } else {
+            return LogBuilder.INSTANCE;
+        }
+    }
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    @Override
+    public LogBuilder atDebug() {
+        if (isDebugEnabled()) {
+            return logBuilder.get().setLevel(Level.DEBUG);
+        } else {
+            return LogBuilder.INSTANCE;
+        }
+    }
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    @Override
+    public LogBuilder atInfo() {
+        if (isInfoEnabled()) {
+            return logBuilder.get().setLevel(Level.INFO);
+        } else {
+            return LogBuilder.INSTANCE;
+        }
+    }
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    @Override
+    public LogBuilder atWarn() {
+        if (isWarnEnabled()) {
+            return logBuilder.get().setLevel(Level.WARN);
+        } else {
+            return LogBuilder.INSTANCE;
+        }
+    }
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    @Override
+    public LogBuilder atError() {
+        if (isErrorEnabled()) {
+            return logBuilder.get().setLevel(Level.ERROR);
+        } else {
+            return LogBuilder.INSTANCE;
+        }
+    }
+    /**
+     * Constuct a trace log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    @Override
+    public LogBuilder atFatal() {
+        if (isFatalEnabled()) {
+            return logBuilder.get().setLevel(Level.FATAL);
+        } else {
+            return LogBuilder.INSTANCE;
+        }
+    }
+    /**
+     * Constuct a log event.
+     * @return a LogBuilder.
+     * @since 3.0
+     */
+    @Override
+    public LogBuilder atLevel(Level level) {
+        if (isEnabled(level)) {
+            return logBuilder.get().setLevel(level);
+        } else {
+            return LogBuilder.INSTANCE;
+        }
+    }
+
+    private class LocalLogBuilder extends ThreadLocal<DefaultLogBuilder> {
+        private AbstractLogger logger;
+        LocalLogBuilder(AbstractLogger logger) {
+            this.logger = logger;
+        }
+
+        @Override
+        protected DefaultLogBuilder initialValue() {
+            return new DefaultLogBuilder(logger);
+        }
+    }
 }
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/MessageFactory2Adapter.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/MessageFactory2Adapter.java
deleted file mode 100644
index ff31515..0000000
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/MessageFactory2Adapter.java
+++ /dev/null
@@ -1,118 +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.spi;
-
-import java.util.Objects;
-
-import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.message.MessageFactory;
-import org.apache.logging.log4j.message.MessageFactory2;
-import org.apache.logging.log4j.message.SimpleMessage;
-
-/**
- * Adapts a legacy MessageFactory to the new MessageFactory2 interface.
- *
- * @since 2.6
- */
-public class MessageFactory2Adapter implements MessageFactory2 {
-    private final MessageFactory wrapped;
-
-    public MessageFactory2Adapter(final MessageFactory wrapped) {
-        this.wrapped = Objects.requireNonNull(wrapped);
-    }
-
-    public MessageFactory getOriginal() {
-        return wrapped;
-    }
-
-    @Override
-    public Message newMessage(final CharSequence charSequence) {
-        return new SimpleMessage(charSequence);
-    }
-
-    @Override
-    public Message newMessage(final String message, final Object p0) {
-        return wrapped.newMessage(message, p0);
-    }
-
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1) {
-        return wrapped.newMessage(message, p0, p1);
-    }
-
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2) {
-        return wrapped.newMessage(message, p0, p1, p2);
-    }
-
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2,
-            final Object p3) {
-        return wrapped.newMessage(message, p0, p1, p2, p3);
-    }
-
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
-            final Object p4) {
-        return wrapped.newMessage(message, p0, p1, p2, p3, p4);
-    }
-
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
-            final Object p4, final Object p5) {
-        return wrapped.newMessage(message, p0, p1, p2, p3, p4, p5);
-    }
-
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
-            final Object p4, final Object p5, final Object p6) {
-        return wrapped.newMessage(message, p0, p1, p2, p3, p4, p5, p6);
-    }
-
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
-            final Object p4, final Object p5, final Object p6, final Object p7) {
-        return wrapped.newMessage(message, p0, p1, p2, p3, p4, p5, p6, p7);
-    }
-
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
-            final Object p4, final Object p5, final Object p6, final Object p7, final Object p8) {
-        return wrapped.newMessage(message, p0, p1, p2, p3, p4, p5, p6, p7, p8);
-    }
-
-    @Override
-    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
-            final Object p4, final Object p5, final Object p6, final Object p7, final Object p8, final Object p9) {
-        return wrapped.newMessage(message, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
-    }
-
-    @Override
-    public Message newMessage(final Object message) {
-        return wrapped.newMessage(message);
-    }
-
-    @Override
-    public Message newMessage(final String message) {
-        return wrapped.newMessage(message);
-    }
-
-    @Override
-    public Message newMessage(final String message, final Object... params) {
-        return wrapped.newMessage(message, params);
-    }
-}
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/AbstractLoggerTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/AbstractLoggerTest.java
index a152aad..4a703cd 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/AbstractLoggerTest.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/AbstractLoggerTest.java
@@ -31,7 +31,6 @@ import org.apache.logging.log4j.message.ParameterizedMessage;
 import org.apache.logging.log4j.message.ParameterizedMessageFactory;
 import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.logging.log4j.spi.AbstractLogger;
-import org.apache.logging.log4j.spi.MessageFactory2Adapter;
 import org.apache.logging.log4j.status.StatusData;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.MessageSupplier;
@@ -989,7 +988,7 @@ public class AbstractLoggerTest {
         private int objectCount;
 
         CountingLogger() {
-            super("CountingLogger", new MessageFactory2Adapter(ParameterizedMessageFactory.INSTANCE));
+            super("CountingLogger", ParameterizedMessageFactory.INSTANCE);
         }
 
         void setCurrentLevel(final Level currentLevel) {
@@ -1216,7 +1215,7 @@ public class AbstractLoggerTest {
         private final boolean expectingThrowables;
 
         ThrowableExpectingLogger(final boolean expectingThrowables) {
-            super("ThrowableExpectingLogger", new MessageFactory2Adapter(ParameterizedMessageFactory.INSTANCE));
+            super("ThrowableExpectingLogger", ParameterizedMessageFactory.INSTANCE);
             this.expectingThrowables = expectingThrowables;
         }
 
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
index 351b36f..1026d56 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java
@@ -26,10 +26,10 @@ import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.MessageFactory;
 import org.apache.logging.log4j.message.ObjectMessage;
 import org.apache.logging.log4j.message.ParameterizedMessageFactory;
+import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.logging.log4j.message.SimpleMessageFactory;
 import org.apache.logging.log4j.message.StringFormatterMessageFactory;
 import org.apache.logging.log4j.message.StructuredDataMessage;
-import org.apache.logging.log4j.spi.MessageFactory2Adapter;
 import org.apache.logging.log4j.util.Strings;
 import org.apache.logging.log4j.util.Supplier;
 import org.junit.Before;
@@ -58,6 +58,18 @@ public class LoggerTest {
     private final List<String> results = logger.getEntries();
 
     @Test
+    public void builder() {
+        logger.atDebug().withLocation().withMessage("Hello").log();
+        logger.atError().withMarker(marker).withMessage("Hello {}").withParameters("John").log();
+        logger.atWarn().withMessage(new SimpleMessage("Log4j rocks!")).withThrowable(new Throwable("This is a test")).log();
+        assertEquals(3, results.size());
+        assertThat("Incorrect message 1", results.get(0), equalTo(" DEBUG org.apache.logging.log4j.LoggerTest.builder(LoggerTest.java:62) Hello"));
+        assertThat("Incorrect message 2", results.get(1), equalTo("test ERROR Hello John"));
+        assertThat("Incorrect message 3", results.get(2), startsWith(" WARN Log4j rocks! java.lang.Throwable: This is a test\n" +
+                "\tat org.apache.logging.log4j.LoggerTest.builder(LoggerTest.java:64)"));
+    }
+
+    @Test
     public void basicFlow() {
         logger.traceEntry();
         logger.traceExit();
@@ -253,9 +265,6 @@ public class LoggerTest {
     }
 
     private static void assertMessageFactoryInstanceOf(MessageFactory factory, final Class<?> cls) {
-        if (factory instanceof MessageFactory2Adapter) {
-            factory = ((MessageFactory2Adapter) factory).getOriginal();
-        }
         assertTrue(factory.getClass().isAssignableFrom(cls));
     }
 
@@ -327,9 +336,6 @@ public class LoggerTest {
 
     private void assertEqualMessageFactory(final MessageFactory messageFactory, final TestLogger testLogger) {
         MessageFactory actual = testLogger.getMessageFactory();
-        if (actual instanceof MessageFactory2Adapter) {
-            actual = ((MessageFactory2Adapter) actual).getOriginal();
-        }
         assertEquals(messageFactory, actual);
     }
 
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/TestLogger.java b/log4j-api/src/test/java/org/apache/logging/log4j/TestLogger.java
index 5f7abb7..b7a820c 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/TestLogger.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/TestLogger.java
@@ -53,6 +53,12 @@ public class TestLogger extends AbstractLogger {
 
     @Override
     public void logMessage(final String fqcn, final Level level, final Marker marker, final Message msg, final Throwable throwable) {
+        log(level, marker, fqcn, null, msg, throwable);
+    }
+
+    @Override
+    protected void log(final Level level, final Marker marker, final String fqcn, final StackTraceElement location,
+            final Message message, final Throwable throwable) {
         final StringBuilder sb = new StringBuilder();
         if (marker != null) {
             sb.append(marker);
@@ -60,14 +66,18 @@ public class TestLogger extends AbstractLogger {
         sb.append(' ');
         sb.append(level.toString());
         sb.append(' ');
-        sb.append(msg.getFormattedMessage());
+        if (location != null) {
+            sb.append(location.toString());
+            sb.append(' ');
+        }
+        sb.append(message.getFormattedMessage());
         final Map<String, String> mdc = ThreadContext.getImmutableContext();
         if (mdc.size() > 0) {
             sb.append(' ');
             sb.append(mdc.toString());
             sb.append(' ');
         }
-        final Object[] params = msg.getParameters();
+        final Object[] params = message.getParameters();
         Throwable t;
         if (throwable == null && params != null && params.length > 0 && params[params.length - 1] instanceof Throwable) {
             t = (Throwable) params[params.length - 1];
@@ -81,7 +91,6 @@ public class TestLogger extends AbstractLogger {
             sb.append(baos.toString());
         }
         list.add(sb.toString());
-        //System.out.println(sb.toString());
     }
 
     @Override
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
index ef90b40..856ca31 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
@@ -147,6 +147,13 @@ public class Logger extends AbstractLogger implements Supplier<LoggerConfig> {
     }
 
     @Override
+    protected void log(final Level level, final Marker marker, final String fqcn, final StackTraceElement location,
+            final Message message, final Throwable throwable) {
+        final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
+        strategy.log(this, getName(), fqcn, location, marker, level, message, throwable);
+    }
+
+    @Override
     public boolean isEnabled(final Level level, final Marker marker, final String message, final Throwable t) {
         return privateConfig.filter(level, marker, message, t);
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitCompletionReliabilityStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitCompletionReliabilityStrategy.java
index 3314706..e9031e8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitCompletionReliabilityStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitCompletionReliabilityStrategy.java
@@ -70,6 +70,25 @@ public class AwaitCompletionReliabilityStrategy implements ReliabilityStrategy {
      * (non-Javadoc)
      *
      * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
+     * java.lang.String, java.lang.String, java.lang.StackTraceElement, org.apache.logging.log4j.Marker,
+     * org.apache.logging.log4j.Level, org.apache.logging.log4j.message.Message, java.lang.Throwable)
+     */
+    @Override
+    public void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn,
+            final StackTraceElement location, final Marker marker, final Level level, final Message data,
+            final Throwable t) {
+        final LoggerConfig config = getActiveLoggerConfig(reconfigured);
+        try {
+            config.log(loggerName, fqcn, location, marker, level, data, t);
+        } finally {
+            config.getReliabilityStrategy().afterLogEvent();
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
      * org.apache.logging.log4j.core.LogEvent)
      */
     @Override
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitUnconditionallyReliabilityStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitUnconditionallyReliabilityStrategy.java
index 357f18b..ce88285 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitUnconditionallyReliabilityStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AwaitUnconditionallyReliabilityStrategy.java
@@ -60,6 +60,20 @@ public class AwaitUnconditionallyReliabilityStrategy implements ReliabilityStrat
 
     /*
      * (non-Javadoc)
+     *
+     * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
+     * java.lang.String, java.lang.String, java.lang.StackTraceElement, org.apache.logging.log4j.Marker,
+     * org.apache.logging.log4j.Level, org.apache.logging.log4j.message.Message, java.lang.Throwable)
+     */
+    @Override
+    public void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn,
+            final StackTraceElement location, final Marker marker, final Level level, final Message data,
+            final Throwable t) {
+        loggerConfig.log(loggerName, fqcn, location, marker, level, data, t);
+    }
+
+    /*
+     * (non-Javadoc)
      * 
      * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
      * org.apache.logging.log4j.core.LogEvent)
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultReliabilityStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultReliabilityStrategy.java
index 18fcae4..4777f2f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultReliabilityStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultReliabilityStrategy.java
@@ -51,6 +51,20 @@ public class DefaultReliabilityStrategy implements ReliabilityStrategy {
 
     /*
      * (non-Javadoc)
+     *
+     * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
+     * java.lang.String, java.lang.String, java.lang.StackTraceElement, org.apache.logging.log4j.Marker,
+     * org.apache.logging.log4j.Level, org.apache.logging.log4j.message.Message, java.lang.Throwable)
+     */
+    @Override
+    public void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn,
+            final StackTraceElement location, final Marker marker, final Level level, final Message data,
+            final Throwable t) {
+        loggerConfig.log(loggerName, fqcn, location, marker, level, data, t);
+    }
+
+    /*
+     * (non-Javadoc)
      * 
      * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
      * org.apache.logging.log4j.core.LogEvent)
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LockingReliabilityStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LockingReliabilityStrategy.java
index 35215c1..391f2ec 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LockingReliabilityStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LockingReliabilityStrategy.java
@@ -62,6 +62,25 @@ public class LockingReliabilityStrategy implements ReliabilityStrategy {
      * (non-Javadoc)
      *
      * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
+     * java.lang.String, java.lang.String, java.lang.StackTraceElement, org.apache.logging.log4j.Marker,
+     * org.apache.logging.log4j.Level, org.apache.logging.log4j.message.Message, java.lang.Throwable)
+     */
+    @Override
+    public void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn,
+            final StackTraceElement location, final Marker marker, final Level level, final Message data,
+            final Throwable t) {
+        final LoggerConfig config = getActiveLoggerConfig(reconfigured);
+        try {
+            config.log(loggerName, fqcn, location, marker, level, data, t);
+        } finally {
+            config.getReliabilityStrategy().afterLogEvent();
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
      * org.apache.logging.log4j.core.LogEvent)
      */
     @Override
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
index 7bfcdc1..2c7c186 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
@@ -385,6 +385,52 @@ public class LoggerConfig extends AbstractFilterable {
     /**
      * Logs an event.
      *
+     * @param loggerName The name of the Logger.
+     * @param fqcn The fully qualified class name of the caller.
+     * @param location the location of the caller.
+     * @param marker A Marker or null if none is present.
+     * @param level The event Level.
+     * @param data The Message.
+     * @param t A Throwable or null.
+     */
+    @PerformanceSensitive("allocation")
+    public void log(final String loggerName, final String fqcn, final StackTraceElement location, final Marker marker,
+            final Level level, final Message data, final Throwable t) {
+        List<Property> props = null;
+        if (!propertiesRequireLookup) {
+            props = properties;
+        } else {
+            if (properties != null) {
+                props = new ArrayList<>(properties.size());
+                final LogEvent event = Log4jLogEvent.newBuilder()
+                        .setMessage(data)
+                        .setMarker(marker)
+                        .setLevel(level)
+                        .setLoggerName(loggerName)
+                        .setLoggerFqcn(fqcn)
+                        .setThrown(t)
+                        .build();
+                for (int i = 0; i < properties.size(); i++) {
+                    final Property prop = properties.get(i);
+                    final String value = prop.isValueNeedsLookup() // since LOG4J2-1575
+                            ? config.getStrSubstitutor().replace(event, prop.getValue()) //
+                            : prop.getValue();
+                    props.add(Property.createProperty(prop.getName(), value));
+                }
+            }
+        }
+        final LogEvent logEvent = logEventFactory.createEvent(loggerName, marker, fqcn, location, level, data, props, t);
+        try {
+            log(logEvent, LoggerConfigPredicate.ALL);
+        } finally {
+            // LOG4J2-1583 prevent scrambled logs when logging calls are nested (logging in toString())
+            ReusableLogEventFactory.release(logEvent);
+        }
+    }
+
+    /**
+     * Logs an event.
+     *
      * @param event The log event.
      */
     public void log(final LogEvent event) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategy.java
index f21a92d..6400435 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategy.java
@@ -42,6 +42,22 @@ public interface ReliabilityStrategy {
      */
     void log(Supplier<LoggerConfig> reconfigured, String loggerName, String fqcn, Marker marker, Level level,
             Message data, Throwable t);
+    /**
+     * Logs an event.
+     *
+     * @param reconfigured supplies the next LoggerConfig if the strategy's LoggerConfig is no longer active
+     * @param loggerName The name of the Logger.
+     * @param fqcn The fully qualified class name of the caller.
+     * @param location The location of the caller or null.
+     * @param marker A Marker or null if none is present.
+     * @param level The event Level.
+     * @param data The Message.
+     * @param t A Throwable or null.
+     * @since 3.0
+     */
+    default void log(Supplier<LoggerConfig> reconfigured, String loggerName, String fqcn, StackTraceElement location,
+            Marker marker, Level level, Message data, Throwable t) {
+    }
 
     /**
      * Logs an event.
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultLogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultLogEventFactory.java
index 127b02a..343d965 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultLogEventFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultLogEventFactory.java
@@ -53,4 +53,23 @@ public class DefaultLogEventFactory implements LogEventFactory {
                                 final List<Property> properties, final Throwable t) {
         return new Log4jLogEvent(loggerName, marker, fqcn, level, data, properties, t);
     }
+
+    /**
+     * Creates a log event.
+     *
+     * @param loggerName The name of the Logger.
+     * @param marker An optional Marker.
+     * @param location The location of the caller
+     * @param level The event Level.
+     * @param data The Message.
+     * @param properties Properties to be added to the log event.
+     * @param t An optional Throwable.
+     * @return The LogEvent.
+     */
+    @Override
+    public LogEvent createEvent(final String loggerName, final Marker marker, final String fqcn,
+            final StackTraceElement location, final Level level, final Message data,
+            final List<Property> properties, final Throwable t) {
+        return new Log4jLogEvent(loggerName, marker, fqcn, location, level, data, properties, t);
+    }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
index 1090399..efa732c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
@@ -301,6 +301,30 @@ public class Log4jLogEvent implements LogEvent {
            nanoClock.nanoTime());
    }
 
+    /**
+     * Constructor.
+     * @param loggerName The name of the Logger.
+     * @param marker The Marker or null.
+     * @param source The location of the caller.
+     * @param level The logging Level.
+     * @param message The Message.
+     * @param properties the properties to be merged with ThreadContext key-value pairs into the event's ReadOnlyStringMap.
+     * @param t A Throwable or null.
+     */
+    // This constructor is called from LogEventFactories.
+    public Log4jLogEvent(final String loggerName, final Marker marker, final String fqcn, final StackTraceElement source,
+            final Level level, final Message message, final List<Property> properties, final Throwable t) {
+        this(loggerName, marker,fqcn, level, message, t,
+                null, createContextData(properties),
+                ThreadContext.getDepth() == 0 ? null : ThreadContext.cloneStack(), // mutable copy
+                0, // thread id
+                null, // thread name
+                0, // thread priority
+                source, // StackTraceElement source
+                CLOCK, //
+                nanoClock.nanoTime());
+    }
+
    /**
      * Constructor.
      * @param loggerName The name of the Logger.
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventFactory.java
index ad9128c..b2af73a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventFactory.java
@@ -32,4 +32,9 @@ public interface LogEventFactory {
 
     LogEvent createEvent(String loggerName, Marker marker, String fqcn, Level level, Message data,
                          List<Property> properties, Throwable t);
+
+    default LogEvent createEvent(String loggerName, Marker marker, String fqcn, StackTraceElement location, Level level,
+            Message data, List<Property> properties, Throwable t) {
+        return createEvent(loggerName, marker, fqcn, level, data, properties, t);
+    }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java
index 81f2d9d..59a4465 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java
@@ -16,12 +16,6 @@
  */
 package org.apache.logging.log4j.core;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
-
 import java.io.File;
 import java.util.Date;
 import java.util.HashMap;
@@ -32,6 +26,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.MarkerManager;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.config.Configuration;
@@ -41,16 +36,21 @@ import org.apache.logging.log4j.junit.LoggerContextRule;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.MessageFactory;
 import org.apache.logging.log4j.message.ParameterizedMessageFactory;
+import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.logging.log4j.message.StringFormatterMessageFactory;
 import org.apache.logging.log4j.message.StructuredDataMessage;
 import org.apache.logging.log4j.spi.AbstractLogger;
-import org.apache.logging.log4j.spi.MessageFactory2Adapter;
 import org.apache.logging.log4j.test.appender.ListAppender;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
 
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.junit.Assert.*;
+import static org.junit.Assert.assertThat;
+
 public class LoggerTest {
 
     private static final String CONFIG = "log4j-test2.xml";
@@ -84,6 +84,20 @@ public class LoggerTest {
     org.apache.logging.log4j.Logger loggerGrandchild;
 
     @Test
+    public void builder() {
+        logger.atDebug().withLocation().withMessage("Hello").log();
+        Marker marker = MarkerManager.getMarker("test");
+        logger.atError().withMarker(marker).withMessage("Hello {}").withParameters("John").log();
+        logger.atWarn().withMessage(new SimpleMessage("Log4j rocks!")).withThrowable(new Throwable("This is a test")).log();
+        final List<LogEvent> events = app.getEvents();
+        assertEventCount(events, 3);
+        assertEquals("Incorrect location", "org.apache.logging.log4j.core.LoggerTest.builder(LoggerTest.java:88)", events.get(0).getSource().toString());
+        assertEquals("Incorrect Level", Level.DEBUG, events.get(0).getLevel());
+        assertThat("Incorrect message", events.get(1).getMessage().getFormattedMessage(), equalTo("Hello John"));
+        assertNotNull("Missing Throwable", events.get(2).getThrown());
+    }
+
+    @Test
     public void basicFlow() {
         logger.traceEntry();
         logger.traceExit();
@@ -275,15 +289,12 @@ public class LoggerTest {
         return testLogger1;
     }
 
-    private static void checkMessageFactory(final MessageFactory messageFactory1, final Logger testLogger1) {
-        if (messageFactory1 == null) {
-            assertEquals(AbstractLogger.DEFAULT_MESSAGE_FACTORY_CLASS, testLogger1.getMessageFactory().getClass());
+    private static void checkMessageFactory(final MessageFactory messageFactory, final Logger testLogger) {
+        if (messageFactory == null) {
+            assertEquals(AbstractLogger.DEFAULT_MESSAGE_FACTORY_CLASS, testLogger.getMessageFactory().getClass());
         } else {
-            MessageFactory actual = testLogger1.getMessageFactory();
-            if (actual instanceof MessageFactory2Adapter) {
-                actual = ((MessageFactory2Adapter) actual).getOriginal();
-            }
-            assertEquals(messageFactory1, actual);
+            MessageFactory actual = testLogger.getMessageFactory();
+            assertEquals(messageFactory, actual);
         }
     }
 
diff --git a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/SetLoggerTagTest.java b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/SetLoggerTagTest.java
index 022ea58..bc6450d 100644
--- a/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/SetLoggerTagTest.java
+++ b/log4j-taglib/src/test/java/org/apache/logging/log4j/taglib/SetLoggerTagTest.java
@@ -24,7 +24,6 @@ import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.message.MessageFactory;
 import org.apache.logging.log4j.message.StringFormatterMessageFactory;
 import org.apache.logging.log4j.spi.AbstractLogger;
-import org.apache.logging.log4j.spi.MessageFactory2Adapter;
 import org.junit.Before;
 import org.junit.Test;
 import org.springframework.mock.web.MockPageContext;
@@ -165,17 +164,14 @@ public class SetLoggerTagTest {
         checkMessageFactory("The message factory is not correct.", factory, logger);
     }
 
-    private static void checkMessageFactory(final String msg, final MessageFactory messageFactory1,
-            final Logger testLogger1) {
-        if (messageFactory1 == null) {
+    private static void checkMessageFactory(final String msg, final MessageFactory messageFactory,
+            final Logger testLogger) {
+        if (messageFactory == null) {
             assertEquals(msg, AbstractLogger.DEFAULT_MESSAGE_FACTORY_CLASS,
-                    testLogger1.getMessageFactory().getClass());
+                    testLogger.getMessageFactory().getClass());
         } else {
-            MessageFactory actual = testLogger1.getMessageFactory();
-            if (actual instanceof MessageFactory2Adapter) {
-                actual = ((MessageFactory2Adapter) actual).getOriginal();
-            }
-            assertEquals(msg, messageFactory1, actual);
+            MessageFactory actual = testLogger.getMessageFactory();
+            assertEquals(msg, messageFactory, actual);
         }
     }
 
diff --git a/log4j-to-slf4j/src/test/java/org/apache/logging/slf4j/LoggerTest.java b/log4j-to-slf4j/src/test/java/org/apache/logging/slf4j/LoggerTest.java
index a115392..e994d19 100644
--- a/log4j-to-slf4j/src/test/java/org/apache/logging/slf4j/LoggerTest.java
+++ b/log4j-to-slf4j/src/test/java/org/apache/logging/slf4j/LoggerTest.java
@@ -29,7 +29,6 @@ import org.apache.logging.log4j.message.MessageFactory;
 import org.apache.logging.log4j.message.ParameterizedMessageFactory;
 import org.apache.logging.log4j.message.StringFormatterMessageFactory;
 import org.apache.logging.log4j.spi.AbstractLogger;
-import org.apache.logging.log4j.spi.MessageFactory2Adapter;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Test;
@@ -126,15 +125,12 @@ public class LoggerTest {
         return testLogger;
     }
 
-    private static void checkMessageFactory(final MessageFactory messageFactory1, final Logger testLogger1) {
-        if (messageFactory1 == null) {
-            assertEquals(AbstractLogger.DEFAULT_MESSAGE_FACTORY_CLASS, testLogger1.getMessageFactory().getClass());
+    private static void checkMessageFactory(final MessageFactory messageFactory, final Logger testLogger) {
+        if (messageFactory == null) {
+            assertEquals(AbstractLogger.DEFAULT_MESSAGE_FACTORY_CLASS, testLogger.getMessageFactory().getClass());
         } else {
-            MessageFactory actual = testLogger1.getMessageFactory();
-            if (actual instanceof MessageFactory2Adapter) {
-                actual = ((MessageFactory2Adapter) actual).getOriginal();
-            }
-            assertEquals(messageFactory1, actual);
+            MessageFactory actual = testLogger.getMessageFactory();
+            assertEquals(messageFactory, actual);
         }
     }
 


[logging-log4j2] 03/04: LOG4J2-2639 - more code review changes

Posted by rg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rgoers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 20f7341e7b1379cbf78c05d4f0ffd513f03ed7a9
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Mon Jun 24 07:34:30 2019 -0700

    LOG4J2-2639 - more code review changes
---
 .../logging/log4j/internal/DefaultLogBuilder.java  |  8 +++
 .../apache/logging/log4j/spi/AbstractLogger.java   | 64 ++++------------------
 2 files changed, 18 insertions(+), 54 deletions(-)

diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java b/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
index 2549663..6d1681f 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/internal/DefaultLogBuilder.java
@@ -47,6 +47,14 @@ public class DefaultLogBuilder implements LogBuilder {
     private volatile boolean inUse;
     private long threadId;
 
+    public DefaultLogBuilder(Logger logger, Level level) {
+        this.logger = logger;
+        this.level = level;
+        this.inUse = false;
+        this.threadId = Thread.currentThread().getId();
+        this.inUse = true;
+    }
+
     public DefaultLogBuilder(Logger logger) {
         this.logger = logger;
         this.inUse = false;
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
index 3a9e465..4918c52 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
@@ -2756,15 +2756,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      */
     @Override
     public  LogBuilder trace() {
-        if (isTraceEnabled()) {
-            DefaultLogBuilder builder = logBuilder.get();
-            if (builder.isInUse()) {
-                return new DefaultLogBuilder(this);
-            }
-            return builder.setLevel(Level.TRACE);
-        } else {
-            return LogBuilder.NOOP;
-        }
+        return atLevel(Level.TRACE);
     }
     /**
      * Constuct a debug log event.
@@ -2773,15 +2765,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      */
     @Override
     public LogBuilder debug() {
-        if (isDebugEnabled()) {
-            DefaultLogBuilder builder = logBuilder.get();
-            if (builder.isInUse()) {
-                return new DefaultLogBuilder(this);
-            }
-            return logBuilder.get().setLevel(Level.DEBUG);
-        } else {
-            return LogBuilder.NOOP;
-        }
+        return atLevel(Level.DEBUG);
     }
     /**
      * Constuct an informational log event.
@@ -2790,15 +2774,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      */
     @Override
     public LogBuilder info() {
-        if (isInfoEnabled()) {
-            DefaultLogBuilder builder = logBuilder.get();
-            if (builder.isInUse()) {
-                return new DefaultLogBuilder(this);
-            }
-            return logBuilder.get().setLevel(Level.INFO);
-        } else {
-            return LogBuilder.NOOP;
-        }
+        return atLevel(Level.INFO);
     }
     /**
      * Constuct a warning log event.
@@ -2807,15 +2783,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      */
     @Override
     public LogBuilder warn() {
-        if (isWarnEnabled()) {
-            DefaultLogBuilder builder = logBuilder.get();
-            if (builder.isInUse()) {
-                return new DefaultLogBuilder(this);
-            }
-            return logBuilder.get().setLevel(Level.WARN);
-        } else {
-            return LogBuilder.NOOP;
-        }
+        return atLevel(Level.WARN);
     }
     /**
      * Constuct an error log event.
@@ -2824,15 +2792,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      */
     @Override
     public LogBuilder error() {
-        if (isErrorEnabled()) {
-            DefaultLogBuilder builder = logBuilder.get();
-            if (builder.isInUse()) {
-                return new DefaultLogBuilder(this);
-            }
-            return logBuilder.get().setLevel(Level.ERROR);
-        } else {
-            return LogBuilder.NOOP;
-        }
+        return atLevel(Level.ERROR);
     }
     /**
      * Constuct a fatal log event.
@@ -2841,15 +2801,7 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
      */
     @Override
     public LogBuilder fatal() {
-        if (isFatalEnabled()) {
-            DefaultLogBuilder builder = logBuilder.get();
-            if (builder.isInUse()) {
-                return new DefaultLogBuilder(this);
-            }
-            return logBuilder.get().setLevel(Level.FATAL);
-        } else {
-            return LogBuilder.NOOP;
-        }
+        return atLevel(Level.FATAL);
     }
     /**
      * Constuct a fatal log event.
@@ -2872,6 +2824,10 @@ public abstract class AbstractLogger implements ExtendedLogger, Serializable {
     @Override
     public LogBuilder atLevel(Level level) {
         if (isEnabled(level)) {
+            DefaultLogBuilder builder = logBuilder.get();
+            if (builder.isInUse()) {
+                return new DefaultLogBuilder(this, level);
+            }
             return logBuilder.get().setLevel(level);
         } else {
             return LogBuilder.NOOP;