Skip to content

Commit c8d60bc

Browse files
committed
Merge remote-tracking branch 'origin/2.x' into 2.x-docgen
2 parents 0ab7d89 + af045db commit c8d60bc

File tree

47 files changed

+815
-85
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+815
-85
lines changed

.github/workflows/scorecards-analysis.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,6 @@ jobs:
7070
retention-days: 5
7171

7272
- name: "Upload to code-scanning"
73-
uses: github/codeql-action/upload-sarif@379614612a29c9e28f31f39a59013eb8012a51f0 # 2.1.22
73+
uses: github/codeql-action/upload-sarif@47b3d888fe66b639e431abf22ebca059152f1eea # 2.1.22
7474
with:
7575
sarif_file: results.sarif
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.status;
18+
19+
import static org.apache.logging.log4j.status.StatusLogger.DEFAULT_FALLBACK_LISTENER_BUFFER_CAPACITY;
20+
import static org.assertj.core.api.Assertions.assertThat;
21+
22+
import java.util.Properties;
23+
import org.junit.jupiter.api.Test;
24+
import uk.org.webcompere.systemstubs.SystemStubs;
25+
26+
class StatusLoggerBufferCapacityTest {
27+
28+
@Test
29+
void valid_buffer_capacity_should_be_effective() {
30+
31+
// Create a `StatusLogger` configuration
32+
final Properties statusLoggerConfigProperties = new Properties();
33+
final int bufferCapacity = 10;
34+
assertThat(bufferCapacity).isNotEqualTo(DEFAULT_FALLBACK_LISTENER_BUFFER_CAPACITY);
35+
statusLoggerConfigProperties.put(StatusLogger.MAX_STATUS_ENTRIES, "" + bufferCapacity);
36+
final StatusLogger.Config statusLoggerConfig = new StatusLogger.Config(statusLoggerConfigProperties);
37+
38+
// Verify the buffer capacity
39+
assertThat(statusLoggerConfig.bufferCapacity).isEqualTo(bufferCapacity);
40+
}
41+
42+
@Test
43+
void invalid_buffer_capacity_should_cause_fallback_to_defaults() throws Exception {
44+
45+
// Create a `StatusLogger` configuration using an invalid buffer capacity
46+
final Properties statusLoggerConfigProperties = new Properties();
47+
final int invalidBufferCapacity = -10;
48+
statusLoggerConfigProperties.put(StatusLogger.MAX_STATUS_ENTRIES, "" + invalidBufferCapacity);
49+
final StatusLogger.Config[] statusLoggerConfigRef = {null};
50+
final String stderr = SystemStubs.tapSystemErr(
51+
() -> statusLoggerConfigRef[0] = new StatusLogger.Config(statusLoggerConfigProperties));
52+
final StatusLogger.Config statusLoggerConfig = statusLoggerConfigRef[0];
53+
54+
// Verify the stderr dump
55+
assertThat(stderr).contains("Failed reading the buffer capacity");
56+
57+
// Verify the buffer capacity
58+
assertThat(statusLoggerConfig.bufferCapacity).isEqualTo(DEFAULT_FALLBACK_LISTENER_BUFFER_CAPACITY);
59+
}
60+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.status;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
21+
import edu.umd.cs.findbugs.annotations.Nullable;
22+
import java.time.Instant;
23+
import java.time.ZoneId;
24+
import java.time.format.DateTimeFormatter;
25+
import java.util.Properties;
26+
import org.junit.jupiter.api.Test;
27+
import org.junit.jupiter.params.ParameterizedTest;
28+
import org.junit.jupiter.params.provider.CsvSource;
29+
import uk.org.webcompere.systemstubs.SystemStubs;
30+
31+
class StatusLoggerDateTest {
32+
33+
@ParameterizedTest
34+
@CsvSource({"yyyy-MM-dd", "HH:mm:ss", "HH:mm:ss.SSS"})
35+
void common_date_patterns_should_work(final String instantPattern) {
36+
37+
// Create a `StatusLogger` configuration
38+
final Properties statusLoggerConfigProperties = new Properties();
39+
statusLoggerConfigProperties.put(StatusLogger.STATUS_DATE_FORMAT, instantPattern);
40+
final ZoneId zoneId = ZoneId.of("UTC");
41+
statusLoggerConfigProperties.put(StatusLogger.STATUS_DATE_FORMAT_ZONE, zoneId.toString());
42+
final StatusLogger.Config statusLoggerConfig = new StatusLogger.Config(statusLoggerConfigProperties);
43+
44+
// Verify the formatter
45+
final DateTimeFormatter formatter =
46+
DateTimeFormatter.ofPattern(instantPattern).withZone(zoneId);
47+
verifyFormatter(statusLoggerConfig.instantFormatter, formatter);
48+
}
49+
50+
@Test
51+
void invalid_date_format_should_cause_fallback_to_defaults() throws Exception {
52+
final String invalidFormat = "l";
53+
verifyInvalidDateFormatAndZone(invalidFormat, "UTC", "failed reading the instant format", null);
54+
}
55+
56+
@Test
57+
void invalid_date_format_zone_should_cause_fallback_to_defaults() throws Exception {
58+
final String invalidZone = "XXX";
59+
final String format = "yyyy";
60+
verifyInvalidDateFormatAndZone(
61+
format,
62+
invalidZone,
63+
"Failed reading the instant formatting zone ID",
64+
DateTimeFormatter.ofPattern(format).withZone(ZoneId.systemDefault()));
65+
}
66+
67+
private static void verifyInvalidDateFormatAndZone(
68+
final String format,
69+
final String zone,
70+
final String stderrMessage,
71+
@Nullable final DateTimeFormatter formatter)
72+
throws Exception {
73+
74+
// Create a `StatusLogger` configuration using invalid input
75+
final Properties statusLoggerConfigProperties = new Properties();
76+
statusLoggerConfigProperties.put(StatusLogger.STATUS_DATE_FORMAT, format);
77+
statusLoggerConfigProperties.put(StatusLogger.STATUS_DATE_FORMAT_ZONE, zone);
78+
final StatusLogger.Config[] statusLoggerConfigRef = {null};
79+
final String stderr = SystemStubs.tapSystemErr(
80+
() -> statusLoggerConfigRef[0] = new StatusLogger.Config(statusLoggerConfigProperties));
81+
final StatusLogger.Config statusLoggerConfig = statusLoggerConfigRef[0];
82+
83+
// Verify the stderr dump
84+
assertThat(stderr).contains(stderrMessage);
85+
86+
// Verify the formatter
87+
verifyFormatter(statusLoggerConfig.instantFormatter, formatter);
88+
}
89+
90+
/**
91+
* {@link DateTimeFormatter} doesn't have an {@link Object#equals(Object)} implementation, hence <a href="https://stackoverflow.com/a/63887712/1278899">this manual <em>behavioral</em> comparison</a>.
92+
*
93+
* @param actual the actual formatter
94+
* @param expected the expected formatter
95+
*/
96+
private static void verifyFormatter(@Nullable DateTimeFormatter actual, @Nullable DateTimeFormatter expected) {
97+
if (expected == null) {
98+
assertThat(actual).isNull();
99+
} else {
100+
assertThat(actual).isNotNull();
101+
final Instant instant = Instant.now();
102+
assertThat(actual.format(instant)).isEqualTo(expected.format(instant));
103+
}
104+
}
105+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.status;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.mockito.ArgumentMatchers.any;
21+
import static org.mockito.Mockito.doThrow;
22+
import static org.mockito.Mockito.mock;
23+
import static org.mockito.Mockito.when;
24+
25+
import org.apache.logging.log4j.Level;
26+
import org.junit.jupiter.api.AfterEach;
27+
import org.junit.jupiter.api.BeforeEach;
28+
import org.junit.jupiter.api.Test;
29+
import org.junit.jupiter.api.extension.ExtendWith;
30+
import org.junit.jupiter.api.parallel.ResourceLock;
31+
import uk.org.webcompere.systemstubs.SystemStubs;
32+
import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
33+
34+
@ExtendWith(SystemStubsExtension.class)
35+
@ResourceLock("log4j2.StatusLogger")
36+
class StatusLoggerFailingListenerTest {
37+
38+
public static final StatusLogger STATUS_LOGGER = StatusLogger.getLogger();
39+
40+
private StatusListener listener;
41+
42+
@BeforeEach
43+
void createAndRegisterListener() {
44+
listener = mock(StatusListener.class);
45+
STATUS_LOGGER.registerListener(listener);
46+
}
47+
48+
@AfterEach
49+
void unregisterListener() {
50+
STATUS_LOGGER.removeListener(listener);
51+
}
52+
53+
@Test
54+
void logging_with_failing_listener_should_not_cause_stack_overflow() throws Exception {
55+
56+
// Set up a failing listener on `log(StatusData)`
57+
when(listener.getStatusLevel()).thenReturn(Level.ALL);
58+
final Exception listenerFailure = new RuntimeException("test failure " + Math.random());
59+
doThrow(listenerFailure).when(listener).log(any());
60+
61+
// Log something and verify exception dump
62+
final String stderr = SystemStubs.tapSystemErr(() -> STATUS_LOGGER.error("foo"));
63+
final String listenerFailureClassName = listenerFailure.getClass().getCanonicalName();
64+
assertThat(stderr).contains(listenerFailureClassName + ": " + listenerFailure.getMessage());
65+
}
66+
}

log4j-api-test/src/test/java/org/apache/logging/log4j/status/StatusLoggerLevelTest.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,24 @@
1616
*/
1717
package org.apache.logging.log4j.status;
1818

19+
import static org.apache.logging.log4j.status.StatusLogger.DEFAULT_FALLBACK_LISTENER_LEVEL;
1920
import static org.assertj.core.api.Assertions.assertThat;
2021
import static org.mockito.Mockito.mock;
2122
import static org.mockito.Mockito.when;
2223

24+
import java.util.Properties;
2325
import org.apache.logging.log4j.Level;
2426
import org.junit.jupiter.api.Test;
27+
import uk.org.webcompere.systemstubs.SystemStubs;
2528

2629
class StatusLoggerLevelTest {
2730

2831
@Test
2932
void effective_level_should_be_the_least_specific_one() {
3033

3134
// Verify the initial level
32-
final StatusLogger logger = StatusLogger.getLogger();
33-
final Level fallbackListenerLevel = Level.ERROR;
35+
final StatusLogger logger = new StatusLogger();
36+
final Level fallbackListenerLevel = DEFAULT_FALLBACK_LISTENER_LEVEL;
3437
assertThat(logger.getLevel()).isEqualTo(fallbackListenerLevel);
3538

3639
// Register a less specific listener
@@ -82,4 +85,23 @@ void effective_level_should_be_the_least_specific_one() {
8285
logger.removeListener(listener1);
8386
assertThat(logger.getLevel()).isEqualTo(fallbackListenerLevel); // Verify that the level is changed
8487
}
88+
89+
@Test
90+
void invalid_level_should_cause_fallback_to_defaults() throws Exception {
91+
92+
// Create a `StatusLogger` configuration using an invalid level
93+
final Properties statusLoggerConfigProperties = new Properties();
94+
final String invalidLevelName = "FOO";
95+
statusLoggerConfigProperties.put(StatusLogger.DEFAULT_STATUS_LISTENER_LEVEL, invalidLevelName);
96+
final StatusLogger.Config[] statusLoggerConfigRef = {null};
97+
final String stderr = SystemStubs.tapSystemErr(
98+
() -> statusLoggerConfigRef[0] = new StatusLogger.Config(statusLoggerConfigProperties));
99+
final StatusLogger.Config statusLoggerConfig = statusLoggerConfigRef[0];
100+
101+
// Verify the stderr dump
102+
assertThat(stderr).contains("Failed reading the level");
103+
104+
// Verify the level
105+
assertThat(statusLoggerConfig.fallbackListenerLevel).isEqualTo(DEFAULT_FALLBACK_LISTENER_LEVEL);
106+
}
85107
}

0 commit comments

Comments
 (0)