Repository: logging-log4j2 Updated Branches: refs/heads/master 4c587de33 -> 7060cc307
LOG4J2-2253 Added ParameterVisitableMessage.forEachParameter This method allows us to iterate over parameters in a ParameterVisitableMessage without array creation. Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/41648dfa Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/41648dfa Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/41648dfa Branch: refs/heads/master Commit: 41648dfa16a7176860e3af30b483e85775c48b9d Parents: ae7f125 Author: Carter Kozak <c4kof...@gmail.com> Authored: Wed Feb 14 14:48:00 2018 -0500 Committer: rpopma <rpo...@apache.org> Committed: Mon Feb 26 19:03:43 2018 +0900 ---------------------------------------------------------------------- .../log4j/message/ParameterConsumer.java | 26 +++++++++++++++++ .../message/ParameterVisitableMessage.java | 30 ++++++++++++++++++++ .../log4j/message/ReusableObjectMessage.java | 7 ++++- .../message/ReusableParameterizedMessage.java | 10 ++++++- .../log4j/message/ReusableSimpleMessage.java | 6 +++- .../ReusableParameterizedMessageTest.java | 22 ++++++++++++++ .../log4j/core/async/RingBufferLogEvent.java | 17 +++++++---- .../log4j/core/impl/MutableLogEvent.java | 11 ++++++- .../core/async/RingBufferLogEventTest.java | 12 ++++++++ 9 files changed, 131 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/41648dfa/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java new file mode 100644 index 0000000..ff8c148 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java @@ -0,0 +1,26 @@ +package org.apache.logging.log4j.message; + +/** + * An operation that accepts two input arguments and returns no result. + * + * <p> + * The third parameter lets callers pass in a stateful object to be modified with the key-value pairs, + * so the ParameterConsumer implementation itself can be stateless and potentially reusable. + * </p> + * + * @param <S> state data + * @see ReusableMessage + * @since 2.11 + */ +public interface ParameterConsumer<S> { + + /** + * Performs an operation given the specified arguments. + * + * @param parameter the parameter + * @param parameterIndex Index of the parameter + * @param state + */ + void accept(Object parameter, short parameterIndex, S state); + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/41648dfa/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitableMessage.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitableMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitableMessage.java new file mode 100644 index 0000000..5cb6228 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitableMessage.java @@ -0,0 +1,30 @@ +package org.apache.logging.log4j.message; + +import org.apache.logging.log4j.util.PerformanceSensitive; + +/** + * Allows message parameters to be iterated over without any allocation + * or memory copies. + * + * @since 2.11 + */ +@PerformanceSensitive("allocation") +public interface ParameterVisitableMessage extends Message { + + /** + * Performs the given action for each parameter until all values + * have been processed or the action throws an exception. + * <p> + * The second parameter lets callers pass in a stateful object to be modified with the key-value pairs, + * so the TriConsumer implementation itself can be stateless and potentially reusable. + * </p> + * + * @param action The action to be performed for each key-value pair in this collection + * @param state the object to be passed as the third parameter to each invocation on the + * specified ParameterConsumer. + * @param <S> type of the third parameter + * @since 2.11 + */ + <S> void forEachParameter(ParameterConsumer<S> action, S state); + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/41648dfa/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 c4ffa22..603381f 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 @@ -24,7 +24,7 @@ import org.apache.logging.log4j.util.StringBuilders; * @since 2.6 */ @PerformanceSensitive("allocation") -public class ReusableObjectMessage implements ReusableMessage { +public class ReusableObjectMessage implements ReusableMessage, ParameterVisitableMessage { private static final long serialVersionUID = 6922476812535519960L; private transient Object obj; @@ -113,6 +113,11 @@ public class ReusableObjectMessage implements ReusableMessage { } @Override + public <S> void forEachParameter(ParameterConsumer<S> action, S state) { + action.accept(obj, (short) 0, state); + } + + @Override public Message memento() { return new ObjectMessage(obj); } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/41648dfa/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 daf2994..55a079c 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 @@ -30,7 +30,7 @@ import org.apache.logging.log4j.util.StringBuilders; * @since 2.6 */ @PerformanceSensitive("allocation") -public class ReusableParameterizedMessage implements ReusableMessage { +public class ReusableParameterizedMessage implements ReusableMessage, ParameterVisitableMessage { private static final int MIN_BUILDER_SIZE = 512; private static final int MAX_PARMS = 10; @@ -105,6 +105,14 @@ public class ReusableParameterizedMessage implements ReusableMessage { } @Override + public <S> void forEachParameter(ParameterConsumer<S> action, S state) { + Object[] parameters = getParams(); + for (short i = 0; i < argCount; i++) { + action.accept(parameters[i], i, state); + } + } + + @Override public Message memento() { return new ParameterizedMessage(messagePattern, getTrimmedParams()); } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/41648dfa/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 905b694..03c290a 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 @@ -23,7 +23,7 @@ import org.apache.logging.log4j.util.PerformanceSensitive; * @since 2.6 */ @PerformanceSensitive("allocation") -public class ReusableSimpleMessage implements ReusableMessage, CharSequence { +public class ReusableSimpleMessage implements ReusableMessage, CharSequence, ParameterVisitableMessage { private static final long serialVersionUID = -9199974506498249809L; private static Object[] EMPTY_PARAMS = new Object[0]; private CharSequence charSequence; @@ -81,6 +81,10 @@ public class ReusableSimpleMessage implements ReusableMessage, CharSequence { } @Override + public <S> void forEachParameter(ParameterConsumer<S> action, S state) { + } + + @Override public Message memento() { return new SimpleMessage(charSequence); } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/41648dfa/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java index b25735c..38f157d 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java @@ -19,6 +19,9 @@ package org.apache.logging.log4j.message; import org.apache.logging.log4j.junit.Mutable; import org.junit.Test; +import java.util.LinkedList; +import java.util.List; + import static org.junit.Assert.*; /** @@ -144,4 +147,23 @@ public class ReusableParameterizedMessageTest { msg.set(testMsg, "msgs", EXCEPTION2); assertSame(EXCEPTION2, msg.getThrowable()); } + + @Test + public void testParameterConsumer() { + final String testMsg = "Test message {}"; + final ReusableParameterizedMessage msg = new ReusableParameterizedMessage(); + final Throwable EXCEPTION1 = new IllegalAccessError("#1"); + msg.set(testMsg, "msg", EXCEPTION1); + List<Object> expected = new LinkedList<>(); + expected.add("msg"); + expected.add(EXCEPTION1); + final List<Object> actual = new LinkedList<>(); + msg.forEachParameter(new ParameterConsumer<Void>() { + @Override + public void accept(Object parameter, short parameterIndex, Void state) { + actual.add(parameter); + } + }, null); + assertEquals(expected, actual); + } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/41648dfa/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 0a2964d..4fee2ef 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 @@ -32,11 +32,7 @@ import org.apache.logging.log4j.core.time.NanoClock; import org.apache.logging.log4j.core.util.*; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; -import org.apache.logging.log4j.message.Message; -import org.apache.logging.log4j.message.ParameterizedMessage; -import org.apache.logging.log4j.message.ReusableMessage; -import org.apache.logging.log4j.message.SimpleMessage; -import org.apache.logging.log4j.message.TimestampMessage; +import org.apache.logging.log4j.message.*; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.StringBuilders; import org.apache.logging.log4j.util.StringMap; @@ -48,7 +44,7 @@ import com.lmax.disruptor.EventFactory; * When the Disruptor is started, the RingBuffer is populated with event objects. These objects are then re-used during * the life of the RingBuffer. */ -public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequence { +public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequence, ParameterVisitableMessage { /** The {@code EventFactory} for {@code RingBufferLogEvent}s. */ public static final Factory FACTORY = new Factory(); @@ -284,6 +280,15 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen } @Override + public <S> void forEachParameter(ParameterConsumer<S> action, S state) { + if (parameters != null) { + for (short i = 0; i < parameterCount; i++) { + action.accept(parameters[i], i, state); + } + } + } + + @Override public Message memento() { if (message != null) { return message; http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/41648dfa/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 b427c4a..b5993fe 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 @@ -42,7 +42,7 @@ import org.apache.logging.log4j.util.Strings; * Mutable implementation of the {@code LogEvent} interface. * @since 2.6 */ -public class MutableLogEvent implements LogEvent, ReusableMessage { +public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisitableMessage { private static final Message EMPTY = new SimpleMessage(Strings.EMPTY); private int threadPriority; @@ -254,6 +254,15 @@ public class MutableLogEvent implements LogEvent, ReusableMessage { return parameters == null ? null : Arrays.copyOf(parameters, parameterCount); } + @Override + public <S> void forEachParameter(ParameterConsumer<S> action, S state) { + if (parameters != null) { + for (short i = 0; i < parameterCount; i++) { + action.accept(parameters[i], i, state); + } + } + } + /** * @see ReusableMessage#getThrowable() */ http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/41648dfa/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java index cc50b42..fdc03d4 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java @@ -32,6 +32,7 @@ import org.apache.logging.log4j.categories.AsyncLoggers; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.core.time.internal.FixedPreciseClock; +import org.apache.logging.log4j.message.ParameterConsumer; import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.core.impl.ThrowableProxy; @@ -189,4 +190,15 @@ public class RingBufferLogEventTest { fail("the messageText field was not set"); } } + + @Test + public void testForEachParameterNothingSet() { + final RingBufferLogEvent evt = new RingBufferLogEvent(); + evt.forEachParameter(new ParameterConsumer<Void>() { + @Override + public void accept(Object parameter, short parameterIndex, Void state) { + fail("Should not have been called"); + } + }, null); + } }