Skip to content

Commit cd3fadb

Browse files
committed
Bring the fallback StatusListener concept back
1 parent cd8912d commit cd3fadb

File tree

6 files changed

+124
-85
lines changed

6 files changed

+124
-85
lines changed

log4j-api-test/src/test/java/org/apache/logging/log4j/AbstractLoggerTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
@StatusLoggerLevel("WARN")
4848
@ResourceLock(value = Resources.MARKER_MANAGER, mode = ResourceAccessMode.READ)
4949
@SetSystemProperty(key = StatusLogger.BUFFER_CAPACITY_PROPERTY_NAME, value = "200")
50+
@SetSystemProperty(key = StatusLogger.FALLBACK_LISTENER_LEVEL_PROPERTY_NAME, value = "WARN")
5051
public class AbstractLoggerTest {
5152

5253
private static final StringBuilder CHAR_SEQ = new StringBuilder("CharSeq");

log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java

Lines changed: 65 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@
4848
* {@link StatusLogger} is expected to be a standalone, self-sufficient component that the logging system can rely on for low-level logging purposes.
4949
* <h3>Listeners</h3>
5050
* <p>
51-
* Each recorded event will first get buffered and used to notify the registered {@link StatusListener}s.
52-
* Listener registry is always initialized with a <em>default listener</em>, which is a {@link StatusConsoleListener}.
51+
* Each recorded event will first get buffered and then used to notify the registered {@link StatusListener}s.
52+
* If none are available, the <em>fallback listener</em> of type {@link StatusConsoleListener} will be used.
5353
* </p>
5454
* <p>
5555
* You can programmatically register listeners using {@link #registerListener(StatusListener)} method.
@@ -68,8 +68,8 @@
6868
* Consider the following example:
6969
* </p>
7070
* <ol>
71-
* <li>The default level is {@code ERROR}</li>
72-
* <li>You have <Configuration status="WARN">} in your {@code log4j2.xml}</li>
71+
* <li>The default level (of fallback listener) is {@code ERROR}</li>
72+
* <li>You have {@code <Configuration status="WARN">} in your {@code log4j2.xml}</li>
7373
* <li>Until your {@code log4j2.xml} configuration is read, the effective level will be {@code ERROR}</li>
7474
* <li>Once your {@code log4j2.xml} configuration is read, the effective level will be {@code WARN} as you configured</li>
7575
* </ol>
@@ -83,6 +83,7 @@
8383
* <h3>Debug mode</h3>
8484
* <p>
8585
* When the {@value Constants#LOG4J2_DEBUG} system property is present, any level-related filtering will be skipped and all events will be notified to listeners.
86+
* If no listeners are available, the <em>fallback listener</em> of type {@link StatusConsoleListener} will be used.
8687
* </p>
8788
*/
8889
public class StatusLogger extends AbstractLogger {
@@ -127,45 +128,45 @@ public class StatusLogger extends AbstractLogger {
127128
public static final String MAX_STATUS_ENTRIES = BUFFER_CAPACITY_PROPERTY_NAME;
128129

129130
/**
130-
* The name of the system property that can be configured with the {@link Level} name to use as the default listener level.
131+
* The name of the system property that can be configured with the {@link Level} name to use as the fallback listener level.
131132
* <p>
132-
* The listener registry is initialized with a default listener.
133-
* This default listener will accept entries filtered by the level provided in this configuration.
133+
* The fallback listener is used when the listener registry is empty.
134+
* The fallback listener will accept entries filtered by the level provided in this configuration.
134135
* </p>
135136
*
136137
* @since 2.23.0
137138
*/
138-
public static final String DEFAULT_LISTENER_LEVEL_PROPERTY_NAME = "log4j2.StatusLogger.level";
139+
public static final String FALLBACK_LISTENER_LEVEL_PROPERTY_NAME = "log4j2.StatusLogger.level";
139140

140141
/**
141-
* The default value of the {@link #DEFAULT_LISTENER_LEVEL_PROPERTY_NAME} system property: {@code ERROR}.
142+
* The default value of the {@link #FALLBACK_LISTENER_LEVEL_PROPERTY_NAME} system property: {@code ERROR}.
142143
*
143144
* @since 2.23.0
144145
*/
145-
public static final Level DEFAULT_LISTENER_LEVEL_DEFAULT_VALUE = Level.ERROR;
146+
public static final Level FALLBACK_LISTENER_LEVEL_DEFAULT_VALUE = Level.ERROR;
146147

147148
/**
148-
* The name of the system property that can be configured with the {@link Level} name to use as the default listener level.
149+
* The name of the system property that can be configured with the {@link Level} name to use as the fallback listener level.
149150
* <p>
150-
* The listener registry is initialized with a default listener.
151-
* This default listener will accept entries filtered by the level provided in this configuration.
151+
* The fallback listener is used when the listener registry is empty.
152+
* The fallback listener will accept entries filtered by the level provided in this configuration.
152153
* </p>
153154
*
154155
* @since 2.8
155-
* @deprecated Use {@link #DEFAULT_LISTENER_LEVEL_PROPERTY_NAME} instead.
156+
* @deprecated Use {@link #FALLBACK_LISTENER_LEVEL_PROPERTY_NAME} instead.
156157
*/
157158
@Deprecated
158-
public static final String DEFAULT_STATUS_LISTENER_LEVEL = DEFAULT_LISTENER_LEVEL_PROPERTY_NAME;
159+
public static final String DEFAULT_STATUS_LISTENER_LEVEL = FALLBACK_LISTENER_LEVEL_PROPERTY_NAME;
159160

160161
/**
161-
* The name of the system property that can be configured with a {@link java.time.format.DateTimeFormatter} pattern that will be passed to the default listener.
162+
* The name of the system property that can be configured with a {@link java.time.format.DateTimeFormatter} pattern that will be used while formatting the created {@link StatusData}.
162163
*
163164
* @since 2.23.0
164165
*/
165166
public static final String INSTANT_FORMAT_PROPERTY_NAME = "log4j2.StatusLogger.DateFormat";
166167

167168
/**
168-
* The name of the system property that can be configured with a {@link java.time.format.DateTimeFormatter} pattern that will be passed to the default listener.
169+
* The name of the system property that can be configured with a {@link java.time.format.DateTimeFormatter} pattern that will be used while formatting the created {@link StatusData}.
169170
*
170171
* @since 2.11.0
171172
* @deprecated Use {@link #INSTANT_FORMAT_PROPERTY_NAME} instead.
@@ -193,7 +194,7 @@ public static final class Config {
193194

194195
private final int bufferCapacity;
195196

196-
private final Level defaultListenerLevel;
197+
private final Level fallbackListenerLevel;
197198

198199
@Nullable
199200
private final DateTimeFormatter instantFormatter;
@@ -204,21 +205,21 @@ public static final class Config {
204205
*
205206
* @param debugEnabled the value of the {@value DEBUG_PROPERTY_NAME} property
206207
* @param bufferCapacity the value of the {@value BUFFER_CAPACITY_PROPERTY_NAME} property
207-
* @param defaultListenerLevel the value of the {@value DEFAULT_LISTENER_LEVEL_PROPERTY_NAME} property
208+
* @param fallbackListenerLevel the value of the {@value FALLBACK_LISTENER_LEVEL_PROPERTY_NAME} property
208209
* @param instantFormatter the value of the {@value INSTANT_FORMAT_PROPERTY_NAME} property
209210
*/
210211
public Config(
211212
boolean debugEnabled,
212213
int bufferCapacity,
213-
Level defaultListenerLevel,
214+
Level fallbackListenerLevel,
214215
@Nullable DateTimeFormatter instantFormatter) {
215216
this.debugEnabled = debugEnabled;
216217
if (bufferCapacity < 0) {
217218
throw new IllegalArgumentException(
218219
"was expecting a positive `bufferCapacity`, found: " + bufferCapacity);
219220
}
220221
this.bufferCapacity = bufferCapacity;
221-
this.defaultListenerLevel = requireNonNull(defaultListenerLevel, "defaultListenerLevel");
222+
this.fallbackListenerLevel = requireNonNull(fallbackListenerLevel, "fallbackListenerLevel");
222223
this.instantFormatter = requireNonNull(instantFormatter, "instantFormatter");
223224
}
224225

@@ -230,7 +231,7 @@ public Config() {
230231
final Properties fileProvidedProperties = readPropertiesFile();
231232
this.debugEnabled = readDebugEnabled(fileProvidedProperties);
232233
this.bufferCapacity = readBufferCapacity(fileProvidedProperties);
233-
this.defaultListenerLevel = readDefaultListenerLevel(fileProvidedProperties);
234+
this.fallbackListenerLevel = readFallbackListenerLevel(fileProvidedProperties);
234235
this.instantFormatter = readInstantFormatter(fileProvidedProperties);
235236
}
236237

@@ -253,9 +254,9 @@ private static int readBufferCapacity(final Properties fileProvidedProperties) {
253254
return capacityString != null ? Integer.parseInt(capacityString) : BUFFER_CAPACITY_DEFAULT_VALUE;
254255
}
255256

256-
private static Level readDefaultListenerLevel(final Properties fileProvidedProperties) {
257-
final String level = readProperty(fileProvidedProperties, DEFAULT_LISTENER_LEVEL_PROPERTY_NAME);
258-
return level != null ? Level.valueOf(level) : DEFAULT_LISTENER_LEVEL_DEFAULT_VALUE;
257+
private static Level readFallbackListenerLevel(final Properties fileProvidedProperties) {
258+
final String level = readProperty(fileProvidedProperties, FALLBACK_LISTENER_LEVEL_PROPERTY_NAME);
259+
return level != null ? Level.valueOf(level) : FALLBACK_LISTENER_LEVEL_DEFAULT_VALUE;
259260
}
260261

261262
private static DateTimeFormatter readInstantFormatter(final Properties fileProvidedProperties) {
@@ -296,7 +297,7 @@ private static Properties readPropertiesFile() {
296297

297298
private final Config config;
298299

299-
private final StatusConsoleListener defaultListener;
300+
private final StatusConsoleListener fallbackListener;
300301

301302
private final Collection<StatusListener> listeners;
302303

@@ -324,7 +325,7 @@ public StatusLogger() {
324325
StatusLogger.class.getSimpleName(),
325326
ParameterizedNoReferenceMessageFactory.INSTANCE,
326327
Config.getInstance(),
327-
new StatusConsoleListener(Config.getInstance().defaultListenerLevel));
328+
new StatusConsoleListener(Config.getInstance().fallbackListenerLevel));
328329
}
329330

330331
/**
@@ -334,20 +335,20 @@ public StatusLogger() {
334335
* @param name the logger name
335336
* @param messageFactory the message factory
336337
* @param config the configuration
337-
* @param defaultListener the default listener
338-
* @throws NullPointerException on null {@code name}, {@code messageFactory}, {@code config}, or {@code defaultListener}
338+
* @param fallbackListener the fallback listener
339+
* @throws NullPointerException on null {@code name}, {@code messageFactory}, {@code config}, or {@code fallbackListener}
339340
* @since 2.23.0
340341
*/
341342
public StatusLogger(
342343
final String name,
343344
final MessageFactory messageFactory,
344345
final Config config,
345-
final StatusConsoleListener defaultListener) {
346+
final StatusConsoleListener fallbackListener) {
346347
super(requireNonNull(name, "name"), requireNonNull(messageFactory, "messageFactory"));
347348
this.config = requireNonNull(config, "config");
348-
this.defaultListener = requireNonNull(defaultListener, "defaultListener");
349-
this.listeners = new ArrayList<>(Collections.singleton(defaultListener));
350-
this.leastSpecificListenerLevel = defaultListener.getStatusLevel();
349+
this.fallbackListener = requireNonNull(fallbackListener, "fallbackListener");
350+
this.listeners = new ArrayList<>(Collections.singleton(fallbackListener));
351+
this.leastSpecificListenerLevel = fallbackListener.getStatusLevel();
351352
}
352353

353354
/**
@@ -372,37 +373,37 @@ public static void setLogger(final StatusLogger logger) {
372373
}
373374

374375
/**
375-
* Sets the level of the default listener.
376+
* Sets the level of the fallback listener.
376377
*
377378
* @param level a level
378379
* @since 2.23.0
379380
*/
380-
public void setDefaultListenerLevel(final Level level) {
381+
public void setFallbackListenerLevel(final Level level) {
381382
requireNonNull(level, "level");
382-
defaultListener.setLevel(level);
383+
fallbackListener.setLevel(level);
383384
}
384385

385386
/**
386-
* Sets the output of the default listener.
387+
* Sets the output of the fallback listener.
387388
*
388389
* @param stream a print stream
389390
* @since 2.23.0
390391
*/
391-
public void setDefaultListenerOutput(final PrintStream stream) {
392+
public void setFallbackListenerOutput(final PrintStream stream) {
392393
requireNonNull(stream, "stream");
393-
defaultListener.setStream(stream);
394+
fallbackListener.setStream(stream);
394395
}
395396

396397
/**
397-
* Sets the level of the default listener.
398+
* Sets the level of the fallback listener.
398399
*
399400
* @param level a level
400-
* @deprecated Use {@link #setDefaultListenerLevel(Level)} instead.
401+
* @deprecated Use {@link #setFallbackListenerLevel(Level)} instead.
401402
*/
402403
@Deprecated
403404
public void setLevel(final Level level) {
404405
requireNonNull(level, "level");
405-
setDefaultListenerLevel(level);
406+
setFallbackListenerLevel(level);
406407
}
407408

408409
/**
@@ -439,29 +440,29 @@ public void removeListener(final StatusListener listener) {
439440
}
440441

441442
private void updateLeastSpecificListenerLevel() {
442-
Level localLeastSpecificListenerLevel = leastSpecificListenerLevel;
443+
Level foundLeastSpecificListenerLevel = fallbackListener.getStatusLevel();
443444
for (final StatusListener listener : listeners) {
444445
final Level listenerLevel = listener.getStatusLevel();
445-
if (listenerLevel.isLessSpecificThan(localLeastSpecificListenerLevel)) {
446-
localLeastSpecificListenerLevel = listener.getStatusLevel();
446+
if (listenerLevel.isLessSpecificThan(foundLeastSpecificListenerLevel)) {
447+
foundLeastSpecificListenerLevel = listener.getStatusLevel();
447448
}
448449
}
449450
// We must update `leastSpecificListenerLevel` in a single instruction!
450451
// It is `volatile` and accessed by `getLevel()` and `isEnabled()` without listener locks for efficiency.
451-
leastSpecificListenerLevel = localLeastSpecificListenerLevel;
452+
leastSpecificListenerLevel = foundLeastSpecificListenerLevel;
452453
}
453454

454455
/**
455456
*
456-
* Sets the level of the default listener.
457+
* Sets the level of the fallback listener.
457458
*
458459
* @param level a level
459-
* @deprecated Instead either use {@link #setDefaultListenerLevel(Level)}, or {@link #getListeners() get the specific listener} and change its {@link StatusListener#getStatusLevel() level}.
460+
* @deprecated Instead either use {@link #setFallbackListenerLevel(Level)}, or {@link #getListeners() get the specific listener} and change its {@link StatusListener#getStatusLevel() level}.
460461
*/
461462
@Deprecated
462463
public void updateListenerLevel(final Level level) {
463464
requireNonNull(level, "level");
464-
setDefaultListenerLevel(level);
465+
setFallbackListenerLevel(level);
465466
}
466467

467468
/**
@@ -479,18 +480,16 @@ public Iterable<StatusListener> getListeners() {
479480
}
480481

481482
/**
482-
* Clears the event buffer and removes the <em>registered</em> (not the default one!) listeners.
483+
* Clears the event buffer and removes the <em>registered</em> (not the fallback one!) listeners.
483484
*/
484485
public void reset() {
485486
listenerWriteLock.lock();
486487
try {
487488
final Iterator<StatusListener> listenerIterator = listeners.iterator();
488489
while (listenerIterator.hasNext()) {
489490
final StatusListener listener = listenerIterator.next();
490-
if (listener != defaultListener) {
491-
closeListenerSafely(listener);
492-
listenerIterator.remove();
493-
}
491+
closeListenerSafely(listener);
492+
listenerIterator.remove();
494493
}
495494
} finally {
496495
listenerWriteLock.unlock();
@@ -556,16 +555,23 @@ private void buffer(final StatusData statusData) {
556555
}
557556

558557
private void notifyListeners(final StatusData statusData) {
558+
final boolean foundListeners;
559559
listenerReadLock.lock();
560560
try {
561-
listeners.forEach(listener -> {
562-
if (config.debugEnabled || listener.getStatusLevel().isLessSpecificThan(statusData.getLevel())) {
563-
listener.log(statusData);
564-
}
565-
});
561+
foundListeners = !listeners.isEmpty();
562+
listeners.forEach(listener -> notifyListener(listener, statusData));
566563
} finally {
567564
listenerReadLock.unlock();
568565
}
566+
if (!foundListeners) {
567+
notifyListener(fallbackListener, statusData);
568+
}
569+
}
570+
571+
private void notifyListener(final StatusListener listener, final StatusData statusData) {
572+
if (config.debugEnabled || listener.getStatusLevel().isLessSpecificThan(statusData.getLevel())) {
573+
listener.log(statusData);
574+
}
569575
}
570576

571577
private StatusData createStatusData(

log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/action/AbstractActionTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import org.junitpioneer.jupiter.SetSystemProperty;
3131

3232
@SetSystemProperty(key = StatusLogger.BUFFER_CAPACITY_PROPERTY_NAME, value = "10")
33-
@SetSystemProperty(key = StatusLogger.DEFAULT_LISTENER_LEVEL_PROPERTY_NAME, value = "WARN")
33+
@SetSystemProperty(key = StatusLogger.FALLBACK_LISTENER_LEVEL_PROPERTY_NAME, value = "WARN")
3434
class AbstractActionTest {
3535

3636
// Test for LOG4J2-2658

log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationPropsTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ private void testConfiguration(
5555
.isEqualTo(expectedConfigName);
5656
final StatusLogger statusLogger = StatusLogger.getLogger();
5757
if (expectedStatusLevel == null) {
58-
verify(statusLogger, never()).setDefaultListenerLevel(any());
58+
verify(statusLogger, never()).setFallbackListenerLevel(any());
5959
} else {
60-
verify(statusLogger).setDefaultListenerLevel(eq(expectedStatusLevel));
60+
verify(statusLogger).setFallbackListenerLevel(eq(expectedStatusLevel));
6161
}
6262
assertThat(config.getRootLogger().getExplicitLevel()).isEqualTo(expectedRootLevel);
6363
}

log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,10 @@ public void initialize() {
186186
try {
187187
if (!this.initialized) {
188188
if (output != null) {
189-
LOGGER.setDefaultListenerOutput(output);
189+
LOGGER.setFallbackListenerOutput(output);
190190
}
191191
if (level != null) {
192-
LOGGER.setDefaultListenerLevel(level);
192+
LOGGER.setFallbackListenerLevel(level);
193193
}
194194
initialized = true;
195195
}

0 commit comments

Comments
 (0)