Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,51 +16,52 @@
*/
package org.apache.logging.log4j.core.async;

import static org.hamcrest.CoreMatchers.sameInstance;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;

import java.util.Arrays;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.ThreadContext.ContextStack;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.time.Clock;
import org.apache.logging.log4j.core.time.NanoClock;
import org.apache.logging.log4j.core.time.internal.DummyNanoClock;
import org.apache.logging.log4j.core.time.internal.FixedPreciseClock;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ReusableMessageFactory;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.spi.MutableThreadContextStack;
import org.apache.logging.log4j.util.StringMap;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

/**
* Tests the RingBufferLogEvent class.
*/
@Tag("async")
public class RingBufferLogEventTest {
class RingBufferLogEventTest {

@Test
public void testToImmutable() {
void testToImmutable() {
final LogEvent logEvent = new RingBufferLogEvent();
assertNotSame(logEvent, logEvent.toImmutable());
assertThat(logEvent).isNotSameAs(logEvent.toImmutable());
}

/**
* @see <a href="https://issues.apache.org/jira/browse/LOG4J2-2816">LOG4J2-2816</a>
* Reproduces <a href="https://issues.apache.org/jira/browse/LOG4J2-2816">LOG4J2-2816</a>.
*/
@Test
public void testIsPopulated() {
void testIsPopulated() {
final RingBufferLogEvent evt = new RingBufferLogEvent();

assertFalse(evt.isPopulated());
assertThat(evt.isPopulated()).isFalse();

final String loggerName = null;
final Marker marker = null;
Expand Down Expand Up @@ -88,15 +89,15 @@ public void testIsPopulated() {
new FixedPreciseClock(),
new DummyNanoClock(1));

assertTrue(evt.isPopulated());
assertThat(evt.isPopulated()).isTrue();

evt.clear();

assertFalse(evt.isPopulated());
assertThat(evt.isPopulated()).isFalse();
}

@Test
public void testGetLevelReturnsOffIfNullLevelSet() {
void testGetLevelReturnsOffIfNullLevelSet() {
final RingBufferLogEvent evt = new RingBufferLogEvent();
final String loggerName = null;
final Marker marker = null;
Expand All @@ -123,11 +124,11 @@ public void testGetLevelReturnsOffIfNullLevelSet() {
location,
new FixedPreciseClock(),
new DummyNanoClock(1));
assertEquals(Level.OFF, evt.getLevel());
assertThat(evt.getLevel()).isEqualTo(Level.OFF);
}

@Test
public void testGetMessageReturnsNonNullMessage() {
void testGetMessageReturnsNonNullMessage() {
final RingBufferLogEvent evt = new RingBufferLogEvent();
final String loggerName = null;
final Marker marker = null;
Expand All @@ -154,11 +155,11 @@ public void testGetMessageReturnsNonNullMessage() {
location,
new FixedPreciseClock(),
new DummyNanoClock(1));
assertNotNull(evt.getMessage());
assertThat(evt.getMessage()).isNotNull();
}

@Test
public void testGetMillisReturnsConstructorMillisForNormalMessage() {
void testGetMillisReturnsConstructorMillisForNormalMessage() {
final RingBufferLogEvent evt = new RingBufferLogEvent();
final String loggerName = null;
final Marker marker = null;
Expand All @@ -185,12 +186,12 @@ public void testGetMillisReturnsConstructorMillisForNormalMessage() {
location,
new FixedPreciseClock(123, 456),
new DummyNanoClock(1));
assertEquals(123, evt.getTimeMillis());
assertEquals(456, evt.getInstant().getNanoOfMillisecond());
assertThat(evt.getTimeMillis()).isEqualTo(123);
assertThat(evt.getInstant().getNanoOfMillisecond()).isEqualTo(456);
}

@Test
public void testCreateMementoReturnsCopy() {
void testCreateMementoReturnsCopy() {
final RingBufferLogEvent evt = new RingBufferLogEvent();
final String loggerName = "logger.name";
final Marker marker = MarkerManager.getMarker("marked man");
Expand Down Expand Up @@ -220,24 +221,24 @@ public void testCreateMementoReturnsCopy() {
evt.getContextData().putValue("key", "value");

final LogEvent actual = evt.toMemento();
assertEquals(evt.getLoggerName(), actual.getLoggerName());
assertEquals(evt.getMarker(), actual.getMarker());
assertEquals(evt.getLoggerFqcn(), actual.getLoggerFqcn());
assertEquals(evt.getLevel(), actual.getLevel());
assertEquals(evt.getMessage(), actual.getMessage());
assertEquals(evt.getThrown(), actual.getThrown());
assertEquals(evt.getContextData(), actual.getContextData());
assertEquals(evt.getContextStack(), actual.getContextStack());
assertEquals(evt.getThreadName(), actual.getThreadName());
assertEquals(evt.getTimeMillis(), actual.getTimeMillis());
assertEquals(
evt.getInstant().getNanoOfMillisecond(), actual.getInstant().getNanoOfMillisecond());
assertEquals(evt.getSource(), actual.getSource());
assertEquals(evt.getThrownProxy(), actual.getThrownProxy());
assertThat(actual.getLoggerName()).isEqualTo(evt.getLoggerName());
assertThat(actual.getMarker()).isEqualTo(evt.getMarker());
assertThat(actual.getLoggerFqcn()).isEqualTo(evt.getLoggerFqcn());
assertThat(actual.getLevel()).isEqualTo(evt.getLevel());
assertThat(actual.getMessage()).isEqualTo(evt.getMessage());
assertThat(actual.getThrown()).isEqualTo(evt.getThrown());
assertThat(actual.getContextData()).isEqualTo(evt.getContextData());
assertThat(actual.getContextStack()).isEqualTo(evt.getContextStack());
assertThat(actual.getThreadName()).isEqualTo(evt.getThreadName());
assertThat(actual.getTimeMillis()).isEqualTo(evt.getTimeMillis());
assertThat(actual.getInstant().getNanoOfMillisecond())
.isEqualTo(evt.getInstant().getNanoOfMillisecond());
assertThat(actual.getSource()).isEqualTo(evt.getSource());
assertThat(actual.getThrownProxy()).isEqualTo(evt.getThrownProxy());
}

@Test
public void testCreateMementoRetainsParametersAndFormat() {
void testCreateMementoRetainsParametersAndFormat() {
final RingBufferLogEvent evt = new RingBufferLogEvent();
// Initialize the event with parameters
evt.swapParameters(new Object[10]);
Expand Down Expand Up @@ -271,16 +272,16 @@ public void testCreateMementoRetainsParametersAndFormat() {
evt.getContextData().putValue("key", "value");

final Message actual = evt.toMemento().getMessage();
assertEquals("Hello {}!", actual.getFormat());
assertArrayEquals(new String[] {"World"}, actual.getParameters());
assertEquals("Hello World!", actual.getFormattedMessage());
assertThat(actual.getFormat()).isEqualTo("Hello {}!");
assertThat(actual.getParameters()).isEqualTo(new String[] {"World"});
assertThat(actual.getFormattedMessage()).isEqualTo("Hello World!");
} finally {
factory.recycle(message);
ReusableMessageFactory.release(message);
}
}

@Test
public void testMementoReuse() {
void testMementoReuse() {
final RingBufferLogEvent evt = new RingBufferLogEvent();
// Initialize the event with parameters
evt.swapParameters(new Object[10]);
Expand Down Expand Up @@ -315,25 +316,99 @@ public void testMementoReuse() {

final Message memento1 = evt.memento();
final Message memento2 = evt.memento();
assertThat(memento1, sameInstance(memento2));
assertThat(memento1).isSameAs(memento2);
} finally {
factory.recycle(message);
}
}

@Test
public void testMessageTextNeverThrowsNpe() {
void testMessageTextNeverThrowsNpe() {
final RingBufferLogEvent evt = new RingBufferLogEvent();
try {
evt.getFormattedMessage();
} catch (final NullPointerException e) {
fail("the messageText field was not set");
}
assertThatCode(evt::getFormattedMessage).doesNotThrowAnyException();
}

@Test
public void testForEachParameterNothingSet() {
void testForEachParameterNothingSet() {
final RingBufferLogEvent evt = new RingBufferLogEvent();
evt.forEachParameter((parameter, parameterIndex, state) -> fail("Should not have been called"), null);
assertThatCode(() -> evt.forEachParameter(
(parameter, parameterIndex, state) -> fail("Should not have been called"), null))
.doesNotThrowAnyException();
}

/**
* Reproduces <a href="https://github.com/apache/logging-log4j2/issues/2234">#2234</a>.
*/
@Test
void testGettersAndClear() {

// Create mock fields
final long salt = (long) (Math.random() * 1_000L);
final AsyncLogger asyncLogger = mock(AsyncLogger.class);
final String loggerName = "LoggerName-" + salt;
final Marker marker = MarkerManager.getMarker("marker-" + salt);
final String fqcn = "a.b.c_" + salt;
final Level level = Level.TRACE;
final Message message = mock(Message.class);
final Throwable throwable = mock(Throwable.class);
final StringMap contextData = mock(StringMap.class);
final ContextStack contextStack = mock(ContextStack.class);
final String threadName = "threadName-" + salt;
final StackTraceElement location = new RuntimeException().getStackTrace()[0];

// Create the log event
final Clock clock = mock(Clock.class);
final NanoClock nanoClock = mock(NanoClock.class);
final RingBufferLogEvent event = new RingBufferLogEvent();
event.setValues(
asyncLogger,
loggerName,
marker,
fqcn,
level,
message,
throwable,
contextData,
contextStack,
-1,
threadName,
-1,
location,
clock,
nanoClock);

// Verify getters
assertThat(event.getLoggerName()).isSameAs(loggerName);
assertThat(event.getMarker()).isSameAs(marker);
assertThat(event.getLoggerFqcn()).isSameAs(fqcn);
assertThat(event.getLevel()).isSameAs(level);
assertThat(event.getMessage()).isSameAs(message);
assertThat(event.getThrowable()).isSameAs(throwable);
assertThat(event.getContextData()).isSameAs(contextData);
assertThat(event.getContextStack()).isSameAs(contextStack);
assertThat(event.getThreadName()).isSameAs(threadName);
assertThat(event.getSource()).isSameAs(location);

// Verify clear
event.clear();
assertThat(event.getLoggerName()).isNull();
assertThat(event.getMarker()).isNull();
assertThat(event.getLoggerFqcn()).isNull();
assertThat(event.getLevel()).isEqualTo(Level.OFF);
verify(message).getFormattedMessage();
assertThat(event.getMessage())
.isNotSameAs(message)
.extracting(Message::getFormattedMessage, as(InstanceOfAssertFactories.STRING))
.isEmpty();
assertThat(event.getThrowable()).isNull();
verify(contextData).isFrozen();
verify(contextData).clear();
assertThat(event.getContextData()).isSameAs(contextData);
assertThat(event.getContextStack()).isNull();
assertThat(event.getThreadName()).isNull();
assertThat(event.getSource()).isNull();

// Verify interaction exhaustion
verifyNoMoreInteractions(asyncLogger, message, throwable, contextData, contextStack);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -475,26 +475,23 @@ public void setNanoTime(final long nanoTime) {
@Override
public void clear() {
this.populated = false;

this.asyncLogger = null;
this.loggerName = null;
this.marker = null;
this.fqcn = null;
this.level = null;
this.message = null;
this.messageFormat = null;
this.threadName = null;
this.loggerName = null;
clearMessage();
this.thrown = null;
this.thrownProxy = null;
this.contextStack = null;
clearContextData();
this.marker = null;
this.fqcn = null;
this.location = null;
if (contextData != null) {
if (contextData.isFrozen()) { // came from CopyOnWrite thread context
contextData = null;
} else {
contextData.clear();
}
}
this.contextStack = null;
this.asyncLogger = null;
}

private void clearMessage() {
message = null;
messageFormat = null;
// ensure that excessively long char[] arrays are not kept in memory forever
StringBuilders.trimToMaxSize(messageText, Constants.MAX_REUSABLE_MESSAGE_SIZE);

Expand All @@ -503,6 +500,16 @@ public void clear() {
}
}

private void clearContextData() {
if (contextData != null) {
if (contextData.isFrozen()) { // came from CopyOnWrite thread context
contextData = null;
} else {
contextData.clear();
}
}
}

/**
* Initializes the specified {@code Log4jLogEvent.Builder} from this {@code RingBufferLogEvent}.
* @param builder the builder whose fields to populate
Expand Down
2 changes: 1 addition & 1 deletion log4j-spring-cloud-config-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<properties>
<!-- Dependency version -->
<spring-boot.version>3.2.2</spring-boot.version>
<spring-cloud.version>4.1.0</spring-cloud.version>
<spring-cloud.version>4.1.1</spring-cloud.version>
<spring-framework.version>6.1.3</spring-framework.version>

<!--
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://logging.apache.org/log4j/changelog"
xsi:schemaLocation="http://logging.apache.org/log4j/changelog https://logging.apache.org/log4j/changelog-0.1.3.xsd"
type="updated">
<issue id="2236" link="https://github.com/apache/logging-log4j2/pull/2236"/>
<description format="asciidoc">Update `org.springframework.cloud:spring-cloud-context` to version `4.1.1`</description>
</entry>
1 change: 1 addition & 0 deletions src/site/_release-notes/_3.x.x.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,6 @@ This release contains...
* Update `org.slf4j:slf4j-api` to version `2.0.10` (https://github.com/apache/logging-log4j2/pull/2136[2136])
* Update `org.springframework.boot:spring-boot-autoconfigure` to version `3.2.2` (https://github.com/apache/logging-log4j2/pull/2222[2222])
* Update `org.springframework.boot:spring-boot-dependencies` to version `3.2.1` (https://github.com/apache/logging-log4j2/pull/2123[2123])
* Update `org.springframework.cloud:spring-cloud-context` to version `4.1.1` (https://github.com/apache/logging-log4j2/pull/2236[2236])
* Update `org.springframework:spring-framework-bom` to version `6.1.3` (https://github.com/apache/logging-log4j2/pull/2223[2223])
* Update `uk.org.webcompere:system-stubs-core` to version `2.1.6` (https://github.com/apache/logging-log4j2/pull/2196[2196])