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;