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:04 UTC

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

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);
         }
     }