You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2016/04/22 07:58:36 UTC

[02/15] logging-log4j2 git commit: LOG4J2-1342 added methods to ReusableMessage to enable passing parameters to async logger background threads

LOG4J2-1342 added methods to ReusableMessage to enable passing parameters to async logger background threads


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/a5f6a8be
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/a5f6a8be
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/a5f6a8be

Branch: refs/heads/master
Commit: a5f6a8be04eb8b7306b1419f967591635b2a2455
Parents: 8b09f29
Author: rpopma <rp...@apache.org>
Authored: Fri Apr 22 12:10:34 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Fri Apr 22 12:10:34 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/message/ReusableMessage.java  | 31 +++++++
 .../log4j/message/ReusableObjectMessage.java    | 19 ++++
 .../message/ReusableParameterizedMessage.java   | 20 ++++
 .../log4j/message/ReusableSimpleMessage.java    | 18 ++++
 .../core/async/AsyncLoggerConfigDisruptor.java  |  2 +-
 .../log4j/core/async/RingBufferLogEvent.java    | 98 +++++++++++++-------
 .../log4j/core/impl/MutableLogEvent.java        | 67 ++++++++++---
 7 files changed, 209 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a5f6a8be/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableMessage.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableMessage.java
index a6da9c4..0536b23 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableMessage.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableMessage.java
@@ -30,4 +30,35 @@ import org.apache.logging.log4j.util.StringBuilderFormattable;
  */
 @PerformanceSensitive("allocation")
 public interface ReusableMessage extends Message, StringBuilderFormattable {
+
+    /**
+     * Returns the parameter array that was used to initialize this reusable message and replaces it with the specified
+     * array. The returned parameter array will no longer be modified by this reusable message. The specified array is
+     * now "owned" by this reusable message and can be modified if necessary for the next log event.
+     * </p><p>
+     * ReusableMessages that have no parameters return the specified array.
+     * </p><p>
+     * This method is used by asynchronous loggers to pass the parameter array to a background thread without
+     * allocating new objects.
+     * The actual number of parameters in the returned array can be determined with {@link #getParameterCount()}.
+     * </p>
+     *
+     * @param emptyReplacement the parameter array that can be used for subsequent uses of this reusable message.
+     *         This replacement array must have at least 10 elements (the number of varargs supported by the Logger
+     *         API).
+     * @return the parameter array for the current message content. This may be a vararg array of any length, or it may
+     *         be a reusable array of 10 elements used to hold the unrolled vararg parameters.
+     * @see #getParameterCount()
+     */
+    Object[] swapParameters(Object[] emptyReplacement);
+
+    /**
+     * Returns the number of parameters that was used to initialize this reusable message for the current content.
+     * <p>
+     * The parameter array returned by {@link #swapParameters(Object[])} may be larger than the actual number of
+     * parameters. Callers should use this method to determine how many elements the array contains.
+     * </p>
+     * @return the current number of parameters
+     */
+    short getParameterCount();
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a5f6a8be/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java
index 12f62f4..920eff4 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java
@@ -91,4 +91,23 @@ public class ReusableObjectMessage implements ReusableMessage {
     public Throwable getThrowable() {
         return obj instanceof Throwable ? (Throwable) obj : null;
     }
+
+    /**
+     * This message does not have any parameters, so this method returns the specified array.
+     * @param emptyReplacement the parameter array to return
+     * @return the specified array
+     */
+    @Override
+    public Object[] swapParameters(final Object[] emptyReplacement) {
+        return emptyReplacement;
+    }
+
+    /**
+     * This message does not have any parameters so this method always returns zero.
+     * @return 0 (zero)
+     */
+    @Override
+    public short getParameterCount() {
+        return 0;
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a5f6a8be/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java
index 87cdc1d..4913c64 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java
@@ -55,6 +55,26 @@ public class ReusableParameterizedMessage implements ReusableMessage {
         return varargs == null ? params : varargs;
     }
 
+    // see interface javadoc
+    @Override
+    public Object[] swapParameters(final Object[] emptyReplacement) {
+        Object[] result;
+        if (varargs == null) {
+            result = params;
+            params = emptyReplacement;
+        } else {
+            result = varargs;
+            varargs = emptyReplacement;
+        }
+        return result;
+    }
+
+    // see interface javadoc
+    @Override
+    public short getParameterCount() {
+        return (short) argCount;
+    }
+
     private void init(final String messagePattern, final int argCount, final Object[] paramArray) {
         this.varargs = null;
         this.messagePattern = messagePattern;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a5f6a8be/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java
index ed6e39e..9fae16c 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java
@@ -61,6 +61,24 @@ public class ReusableSimpleMessage implements ReusableMessage, CharSequence {
         buffer.append(charSequence);
     }
 
+    /**
+     * This message does not have any parameters, so this method returns the specified array.
+     * @param emptyReplacement the parameter array to return
+     * @return the specified array
+     */
+    @Override
+    public Object[] swapParameters(final Object[] emptyReplacement) {
+        return emptyReplacement;
+    }
+
+    /**
+     * This message does not have any parameters so this method always returns zero.
+     * @return 0 (zero)
+     */
+    @Override
+    public short getParameterCount() {
+        return 0;
+    }
 
     // CharSequence impl
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a5f6a8be/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
index 2c1b84f..503e7d8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
@@ -145,7 +145,7 @@ public class AsyncLoggerConfigDisruptor implements AsyncLoggerConfigDelegate {
     private static final EventFactory<Log4jEventWrapper> MUTABLE_FACTORY = new EventFactory<Log4jEventWrapper>() {
         @Override
         public Log4jEventWrapper newInstance() {
-            return new Log4jEventWrapper(new MutableLogEvent());
+            return new Log4jEventWrapper(new MutableLogEvent(new Object[10]));
         }
     };
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a5f6a8be/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
index e1e6ab0..72ae8ac 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
@@ -16,7 +16,11 @@
  */
 package org.apache.logging.log4j.core.async;
 
-import com.lmax.disruptor.EventFactory;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext.ContextStack;
@@ -32,9 +36,7 @@ import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.logging.log4j.message.TimestampMessage;
 import org.apache.logging.log4j.util.Strings;
 
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
+import com.lmax.disruptor.EventFactory;
 
 /**
  * When the Disruptor is started, the RingBuffer is populated with event objects. These objects are then re-used during
@@ -46,7 +48,6 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
     public static final Factory FACTORY = new Factory();
 
     private static final long serialVersionUID = 8462119088943934758L;
-    private static final Object[] PARAMS = new Object[0];
     private static final Message EMPTY = new SimpleMessage(Strings.EMPTY);
 
     /**
@@ -59,56 +60,63 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
             RingBufferLogEvent result = new RingBufferLogEvent();
             if (Constants.ENABLE_THREADLOCALS) {
                 result.messageText = new StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE);
+                result.parameters = new Object[10];
             }
             return result;
         }
     }
 
-    private transient AsyncLogger asyncLogger;
-    private String loggerName;
-    private Marker marker;
-    private String fqcn;
+    private int threadPriority;
+    private long threadId;
+    private long currentTimeMillis;
+    private long nanoTime;
+    private short parameterCount;
+    private boolean includeLocation;
+    private boolean endOfBatch = false;
     private Level level;
-    private StringBuilder messageText;
+    private String threadName;
+    private String loggerName;
     private Message message;
+    private StringBuilder messageText;
+    private Object[] parameters;
     private transient Throwable thrown;
     private ThrowableProxy thrownProxy;
     private Map<String, String> contextMap;
-    private ContextStack contextStack;
-    private long threadId;
-    private String threadName;
-    private int threadPriority;
+    private Marker marker;
+    private String fqcn;
     private StackTraceElement location;
-    private long currentTimeMillis;
-    private boolean endOfBatch;
-    private boolean includeLocation;
-    private long nanoTime;
+    private ContextStack contextStack;
+
+    private transient AsyncLogger asyncLogger;
 
     public void setValues(final AsyncLogger anAsyncLogger, final String aLoggerName, final Marker aMarker,
             final String theFqcn, final Level aLevel, final Message msg, final Throwable aThrowable,
             final Map<String, String> aMap, final ContextStack aContextStack, long threadId,
             final String threadName, int threadPriority, final StackTraceElement aLocation, final long aCurrentTimeMillis, final long aNanoTime) {
-        this.asyncLogger = anAsyncLogger;
-        this.loggerName = aLoggerName;
-        this.marker = aMarker;
-        this.fqcn = theFqcn;
+        this.threadPriority = threadPriority;
+        this.threadId = threadId;
+        this.currentTimeMillis = aCurrentTimeMillis;
+        this.nanoTime = aNanoTime;
         this.level = aLevel;
+        this.threadName = threadName;
+        this.loggerName = aLoggerName;
+        setMessage(msg);
         this.thrown = aThrowable;
         this.thrownProxy = null;
         this.contextMap = aMap;
-        this.contextStack = aContextStack;
-        this.threadId = threadId;
-        this.threadName = threadName;
-        this.threadPriority = threadPriority;
+        this.marker = aMarker;
+        this.fqcn = theFqcn;
         this.location = aLocation;
-        this.currentTimeMillis = aCurrentTimeMillis;
-        this.nanoTime = aNanoTime;
-        setMessage(msg);
+        this.contextStack = aContextStack;
+        this.asyncLogger = anAsyncLogger;
     }
 
     private void setMessage(final Message msg) {
         if (msg instanceof ReusableMessage) {
-            ((ReusableMessage) msg).formatTo(getMessageTextForWriting());
+            ReusableMessage reusable = (ReusableMessage) msg;
+            reusable.formatTo(getMessageTextForWriting());
+            parameters = reusable.swapParameters(parameters);
+            parameterCount = reusable.getParameterCount();
         } else {
             // if the Message instance is reused, there is no point in freezing its message here
             if (!Constants.FORMAT_MESSAGES_IN_BACKGROUND && msg != null) { // LOG4J2-898: user may choose
@@ -215,7 +223,7 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
      */
     @Override
     public Object[] getParameters() {
-        return PARAMS;
+        return parameters == null ? null : Arrays.copyOf(parameters, parameterCount);
     }
 
     /**
@@ -234,6 +242,27 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
         buffer.append(messageText);
     }
 
+    /**
+     * Replaces this ReusableMessage's parameter array with the specified value and return the original array
+     * @param emptyReplacement the parameter array that can be used for subsequent uses of this reusable message
+     * @return the original parameter array
+     * @see ReusableMessage#swapParameters(Object[])
+     */
+    @Override
+    public Object[] swapParameters(final Object[] emptyReplacement) {
+        final Object[] result = this.parameters;
+        this.parameters = emptyReplacement;
+        return result;
+    }
+
+    /*
+     * @see ReusableMessage#getParameterCount
+     */
+    @Override
+    public short getParameterCount() {
+        return parameterCount;
+    }
+
 
     // CharSequence impl
 
@@ -362,7 +391,14 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
         this.contextMap = null;
         this.contextStack = null;
         this.location = null;
+
         trimMessageText();
+
+        if (parameters != null) {
+            for (int i = 0; i < parameters.length; i++) {
+                parameters[i] = null;
+            }
+        }
     }
 
     // ensure that excessively long char[] arrays are not kept in memory forever

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a5f6a8be/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
index b619615..0393b0c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.impl;
 
 import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
+import java.util.Arrays;
 import java.util.Map;
 
 import org.apache.logging.log4j.Level;
@@ -35,27 +36,36 @@ import org.apache.logging.log4j.util.Strings;
  * @since 2.6
  */
 public class MutableLogEvent implements LogEvent, ReusableMessage {
-    private static final Object[] PARAMS = new Object[0];
     private static final Message EMPTY = new SimpleMessage(Strings.EMPTY);
 
-    private String loggerFqcn;
-    private Marker marker;
+    private int threadPriority;
+    private long threadId;
+    private long timeMillis;
+    private long nanoTime;
+    private short parameterCount;
+    private boolean includeLocation;
+    private boolean endOfBatch = false;
     private Level level;
+    private String threadName;
     private String loggerName;
     private Message message;
-    private long timeMillis;
+    private StringBuilder messageText;
+    private Object[] parameters;
     private Throwable thrown;
     private ThrowableProxy thrownProxy;
     private Map<String, String> contextMap;
-    private ThreadContext.ContextStack contextStack;
-    private long threadId;
-    private String threadName;
-    private int threadPriority;
+    private Marker marker;
+    private String loggerFqcn;
     private StackTraceElement source;
-    private boolean includeLocation;
-    private boolean endOfBatch = false;
-    private long nanoTime;
-    private StringBuilder messageText;
+    private ThreadContext.ContextStack contextStack;
+
+    public MutableLogEvent() {
+        this(null);
+    }
+
+    public MutableLogEvent(final Object[] replacementParameters) {
+        this.parameters = replacementParameters;
+    }
 
     /**
      * Initialize the fields of this {@code MutableLogEvent} from another event.
@@ -107,6 +117,11 @@ public class MutableLogEvent implements LogEvent, ReusableMessage {
         // threadName = null; // no need to clear threadName
 
         trimMessageText();
+        if (parameters != null) {
+            for (int i = 0; i < parameters.length; i++) {
+                parameters[i] = null;
+            }
+        }
 
         // primitive fields that cannot be cleared:
         //timeMillis;
@@ -171,7 +186,10 @@ public class MutableLogEvent implements LogEvent, ReusableMessage {
 
     public void setMessage(final Message msg) {
         if (msg instanceof ReusableMessage) {
-            ((ReusableMessage) msg).formatTo(getMessageTextForWriting()); // init messageText
+            ReusableMessage reusable = (ReusableMessage) msg;
+            reusable.formatTo(getMessageTextForWriting());
+            parameters = reusable.swapParameters(parameters);
+            parameterCount = reusable.getParameterCount();
         } else {
             // if the Message instance is reused, there is no point in freezing its message here
             if (!Constants.FORMAT_MESSAGES_IN_BACKGROUND && msg != null) { // LOG4J2-898: user may choose
@@ -212,7 +230,7 @@ public class MutableLogEvent implements LogEvent, ReusableMessage {
      */
     @Override
     public Object[] getParameters() {
-        return PARAMS;
+        return parameters == null ? null : Arrays.copyOf(parameters, parameterCount);
     }
 
     /**
@@ -231,6 +249,27 @@ public class MutableLogEvent implements LogEvent, ReusableMessage {
         buffer.append(messageText);
     }
 
+    /**
+     * Replaces this ReusableMessage's parameter array with the specified value and return the original array
+     * @param emptyReplacement the parameter array that can be used for subsequent uses of this reusable message
+     * @return the original parameter array
+     * @see ReusableMessage#swapParameters(Object[])
+     */
+    @Override
+    public Object[] swapParameters(final Object[] emptyReplacement) {
+        final Object[] result = this.parameters;
+        this.parameters = emptyReplacement;
+        return result;
+    }
+
+    /*
+     * @see ReusableMessage#getParameterCount
+     */
+    @Override
+    public short getParameterCount() {
+        return parameterCount;
+    }
+
     @Override
     public Throwable getThrown() {
         return thrown;