Skip to content

Commit 8434f99

Browse files
committed
Improve implementations of LogEvent.toImmutable()
The implementations of `LogEvent.toImmutable()` either use serialization or one of the `Log4jLogEvent.Builder` constructors and custom per class code. This PR: - Redirects all implementation of `LogEvent.toImmutable` to the `Builder(LogEvent)` constructor (except `Log4jLogEvent.toImmutable()`) - Improve the constructor to create really immutable and thread-safe instances. - Removes the usage of `ThrowableProxy` for purposes not related to serialization. - Fixes some implementations of `ReusableMessage.memento()`. - Uses `ReusableMessage.memento()` instead of `ImmutableMessage` where applicable.
1 parent 5d2b0a0 commit 8434f99

File tree

23 files changed

+286
-220
lines changed

23 files changed

+286
-220
lines changed

log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ public LoggingEvent rewrite(final LoggingEvent source) {
105105
.setThrown(source.getThrowableInformation().getThrowable())
106106
.setTimeMillis(source.getTimeStamp())
107107
.setNanoTime(0)
108-
.setThrownProxy(null)
109108
.build();
110109
}
111110
return new LogEventAdapter(event);

log4j-1.2-api/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ public LoggingEvent rewrite(final LoggingEvent source) {
110110
.setThrown(source.getThrowableInformation().getThrowable())
111111
.setTimeMillis(source.getTimeStamp())
112112
.setNanoTime(0)
113-
.setThrownProxy(null)
114113
.build();
115114
}
116115
return new LogEventAdapter(event);

log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ public <S> void forEachParameter(final ParameterConsumer<S> action, final S stat
128128

129129
@Override
130130
public Message memento() {
131-
return new ObjectMessage(obj);
131+
Message message = new ObjectMessage(obj);
132+
message.getFormattedMessage();
133+
return message;
132134
}
133135

134136
@Override

log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@ public <S> void forEachParameter(final ParameterConsumer<S> action, final S stat
114114

115115
@Override
116116
public Message memento() {
117-
return new ParameterizedMessage(messagePattern, getTrimmedParams());
117+
Message message = new ParameterizedMessage(messagePattern, getTrimmedParams());
118+
message.getFormattedMessage();
119+
return message;
118120
}
119121

120122
private void init(final String messagePattern, final int argCount, final Object[] args) {

log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ public <S> void forEachParameter(final ParameterConsumer<S> action, final S stat
8585

8686
@Override
8787
public Message memento() {
88-
return new SimpleMessage(charSequence);
88+
SimpleMessage message = new SimpleMessage(charSequence);
89+
message.getFormattedMessage();
90+
return message;
8991
}
9092

9193
// CharSequence impl

log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/ListAppender.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
3636
import org.apache.logging.log4j.core.config.plugins.PluginElement;
3737
import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
38-
import org.apache.logging.log4j.core.impl.MutableLogEvent;
3938
import org.apache.logging.log4j.core.layout.SerializedLayout;
4039
import org.awaitility.Awaitility;
4140

@@ -121,12 +120,7 @@ public ListAppender(
121120
public void append(final LogEvent event) {
122121
final Layout<? extends Serializable> layout = getLayout();
123122
if (layout == null) {
124-
if (event instanceof MutableLogEvent) {
125-
// must take snapshot or subsequent calls to logger.log() will modify this event
126-
events.add(((MutableLogEvent) event).createMemento());
127-
} else {
128-
events.add(event);
129-
}
123+
events.add(event.toImmutable());
130124
} else if (layout instanceof SerializedLayout) {
131125
final byte[] header = layout.getHeader();
132126
final byte[] content = layout.toByteArray(event);

log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/BlockingAppender.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.apache.logging.log4j.core.config.plugins.PluginElement;
3434
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
3535
import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
36-
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
3736

3837
/**
3938
* Appender that can be halted and resumed, for testing queue-full scenarios.
@@ -58,7 +57,7 @@ public void append(final LogEvent event) {
5857
// may be a reusable event, make a copy, don't keep a reference to the original event
5958
final List<LogEvent> events = logEvents;
6059
if (events != null) {
61-
events.add(Log4jLogEvent.createMemento(event));
60+
events.add(event.toImmutable());
6261
}
6362

6463
if (countDownLatch == null) {

log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.apache.logging.log4j.Level;
3030
import org.apache.logging.log4j.Marker;
3131
import org.apache.logging.log4j.MarkerManager;
32+
import org.apache.logging.log4j.ThreadContext;
3233
import org.apache.logging.log4j.ThreadContext.ContextStack;
3334
import org.apache.logging.log4j.core.LogEvent;
3435
import org.apache.logging.log4j.core.impl.ThrowableProxy;
@@ -202,7 +203,7 @@ void testSerializationDeserialization() throws IOException, ClassNotFoundExcepti
202203
final Level level = Level.TRACE;
203204
final Message data = new SimpleMessage("message");
204205
final Throwable t = new InternalError("not a real error");
205-
final ContextStack contextStack = null;
206+
final ContextStack contextStack = ThreadContext.getImmutableStack();
206207
final String threadName = "main";
207208
final StackTraceElement location = null;
208209
evt.setValues(
@@ -223,25 +224,31 @@ void testSerializationDeserialization() throws IOException, ClassNotFoundExcepti
223224
new DummyNanoClock(1));
224225
((StringMap) evt.getContextData()).putValue("key", "value");
225226

226-
final RingBufferLogEvent other = SerialUtil.deserialize(SerialUtil.serialize(evt));
227-
assertThat(other.getLoggerName()).isEqualTo(loggerName);
228-
assertThat(other.getMarker()).isEqualTo(marker);
229-
assertThat(other.getLoggerFqcn()).isEqualTo(fqcn);
230-
assertThat(other.getLevel()).isEqualTo(level);
231-
assertThat(other.getMessage()).isEqualTo(data);
232-
assertThat(other.getThrown()).isNull();
233-
assertThat(other.getThrownProxy()).isEqualTo(new ThrowableProxy(t));
234-
assertThat(other.getContextData()).isEqualTo(evt.getContextData());
235-
assertThat(other.getContextStack()).isEqualTo(contextStack);
236-
assertThat(other.getThreadName()).isEqualTo(threadName);
237-
assertThat(other.getSource()).isEqualTo(location);
238-
assertThat(other.getTimeMillis()).isEqualTo(12345);
239-
assertThat(other.getInstant().getNanoOfMillisecond()).isEqualTo(678);
227+
final LogEvent other = SerialUtil.deserialize(SerialUtil.serialize(evt));
228+
assertThat(other.getLoggerName()).as("Logger name").isEqualTo(loggerName);
229+
assertThat(other.getMarker()).as("Marker").isEqualTo(marker);
230+
assertThat(other.getLoggerFqcn())
231+
.as("Fully qualified class name of logger implementation")
232+
.isEqualTo(fqcn);
233+
assertThat(other.getLevel()).as("Log event level").isEqualTo(level);
234+
assertThat(other.getMessage()).as("Log event message").isEqualTo(data);
235+
assertThat(other.getThrown()).as("Thrown exception").isNull();
236+
assertThat(other.getThrownProxy())
237+
.as("Serialization proxy for thrown exception")
238+
.isEqualTo(new ThrowableProxy(t));
239+
assertThat(other.getContextData()).as("Context data map").isEqualTo(evt.getContextData());
240+
assertThat(other.getContextStack()).as("Context data stack").isEqualTo(contextStack);
241+
assertThat(other.getThreadName()).as("Thread name").isEqualTo(threadName);
242+
assertThat(other.getSource()).as("Log event location").isEqualTo(location);
243+
assertThat(other.getTimeMillis()).as("Log event timestamp in millis").isEqualTo(12345);
244+
assertThat(other.getInstant().getNanoOfMillisecond())
245+
.as("Log event timestamp in nanos of millis")
246+
.isEqualTo(678);
240247
}
241248

242249
@SuppressWarnings("deprecation")
243250
@Test
244-
void testCreateMementoReturnsCopy() {
251+
void testToImmutableReturnsCopy() {
245252
final RingBufferLogEvent evt = new RingBufferLogEvent();
246253
final String loggerName = "logger.name";
247254
final Marker marker = MarkerManager.getMarker("marked man");
@@ -270,7 +277,7 @@ void testCreateMementoReturnsCopy() {
270277
new DummyNanoClock(1));
271278
((StringMap) evt.getContextData()).putValue("key", "value");
272279

273-
final LogEvent actual = evt.createMemento();
280+
final LogEvent actual = evt.toImmutable();
274281
assertThat(actual.getLoggerName()).isEqualTo(evt.getLoggerName());
275282
assertThat(actual.getMarker()).isEqualTo(evt.getMarker());
276283
assertThat(actual.getLoggerFqcn()).isEqualTo(evt.getLoggerFqcn());
@@ -289,7 +296,7 @@ void testCreateMementoReturnsCopy() {
289296
}
290297

291298
@Test
292-
void testCreateMementoRetainsParametersAndFormat() {
299+
void testToImmutableRetainsParametersAndFormat() {
293300
final RingBufferLogEvent evt = new RingBufferLogEvent();
294301
// Initialize the event with parameters
295302
evt.swapParameters(new Object[10]);
@@ -322,7 +329,7 @@ void testCreateMementoRetainsParametersAndFormat() {
322329
new DummyNanoClock(1));
323330
((StringMap) evt.getContextData()).putValue("key", "value");
324331

325-
final Message actual = evt.createMemento().getMessage();
332+
final Message actual = evt.toImmutable().getMessage();
326333
assertThat(actual.getFormat()).isEqualTo("Hello {}!");
327334
assertThat(actual.getParameters()).isEqualTo(new String[] {"World"});
328335
assertThat(actual.getFormattedMessage()).isEqualTo("Hello World!");

log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public void testInitFromReusableCopiesFormatString() {
137137
assertEquals("msg in a bottle", memento.getFormattedMessage(), "formatted");
138138
assertArrayEquals(new String[] {"bottle"}, memento.getParameters(), "parameters");
139139

140-
final Message eventMementoMessage = mutable.createMemento().getMessage();
140+
final Message eventMementoMessage = mutable.toImmutable().getMessage();
141141
assertEquals("msg in a {}", eventMementoMessage.getFormat(), "format");
142142
assertEquals("msg in a bottle", eventMementoMessage.getFormattedMessage(), "formatted");
143143
assertArrayEquals(new String[] {"bottle"}, eventMementoMessage.getParameters(), "parameters");

log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/SmtpManagerTest.java

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,13 @@
1616
*/
1717
package org.apache.logging.log4j.core.net;
1818

19-
import static org.hamcrest.CoreMatchers.instanceOf;
20-
import static org.hamcrest.CoreMatchers.is;
21-
import static org.hamcrest.MatcherAssert.assertThat;
19+
import static org.assertj.core.api.Assertions.assertThat;
2220
import static org.junit.jupiter.api.Assertions.assertEquals;
2321

2422
import org.apache.logging.log4j.core.LogEvent;
2523
import org.apache.logging.log4j.core.appender.SmtpAppender;
2624
import org.apache.logging.log4j.core.async.RingBufferLogEvent;
2725
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
28-
import org.apache.logging.log4j.core.impl.MementoMessage;
2926
import org.apache.logging.log4j.core.impl.MutableLogEvent;
3027
import org.apache.logging.log4j.core.util.ClockFactory;
3128
import org.apache.logging.log4j.core.util.DummyNanoClock;
@@ -72,17 +69,14 @@ private void testAdd(final LogEvent event) {
7269
.setBufferSize(10)
7370
.build();
7471
final MailManager mailManager = appender.getManager();
75-
assertThat("is instance of SmtpManager", mailManager instanceof SmtpManager);
72+
assertThat(mailManager).isInstanceOf(SmtpManager.class);
7673
final SmtpManager smtpManager = (SmtpManager) mailManager;
7774
smtpManager.removeAllBufferedEvents(); // in case this smtpManager is reused
7875
smtpManager.add(event);
7976

8077
final LogEvent[] bufferedEvents = smtpManager.removeAllBufferedEvents();
81-
assertThat("unexpected number of buffered events", bufferedEvents.length, is(1));
82-
assertThat(
83-
"expected the immutable version of the event to be buffered",
84-
bufferedEvents[0].getMessage(),
85-
is(instanceOf(MementoMessage.class)));
78+
assertThat(bufferedEvents).as("Buffered events").hasSize(1);
79+
assertThat(bufferedEvents[0].getMessage()).as("Immutable message").isNotInstanceOf(ReusableMessage.class);
8680
}
8781

8882
// LOG4J2-3172: make sure existing protections are not violated

0 commit comments

Comments
 (0)