You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2022/04/24 18:00:28 UTC
[logging-log4j2] 07/11: [LOG4J2-3440] Synchronize Log4j 1.x and Log4j 2.x appenders
This is an automated email from the ASF dual-hosted git repository.
pkarwasz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit e0d25b863a1732ce4a56775b66438abce6838ecd
Author: Piotr P. Karwasz <pi...@karwasz.org>
AuthorDate: Sun Apr 3 14:35:24 2022 +0200
[LOG4J2-3440] Synchronize Log4j 1.x and Log4j 2.x appenders
Forwards the `addAppender`, `callAppenders`, `getAllAppenders` and
`getAppender` calls the the corresponding Log4j 2.x objects if Log4j 2.x
Core is present.
The `getAllAppenders` method only returns those appenders, which are
attached to homonymous logger config and are native Log4j 1.x appenders.
Conflicts:
log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java
---
.../src/main/java/org/apache/log4j/Category.java | 49 +++++++---
.../org/apache/log4j/bridge/AppenderAdapter.java | 7 +-
.../org/apache/log4j/legacy/core/CategoryUtil.java | 45 +++++++++-
.../test/java/org/apache/log4j/CategoryTest.java | 100 +++++++++++++++++++--
.../test/java/org/apache/log4j/ListAppender.java | 4 +
.../config/PropertiesReconfigurationTest.java | 16 +---
6 files changed, 183 insertions(+), 38 deletions(-)
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java b/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java
index cfafe8d1ea..0ebffc9c77 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java
@@ -16,13 +16,18 @@
*/
package org.apache.log4j;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Vector;
import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
+import org.apache.log4j.bridge.AppenderAdapter;
import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.LogEventWrapper;
import org.apache.log4j.helpers.AppenderAttachableImpl;
import org.apache.log4j.helpers.NullEnumeration;
import org.apache.log4j.legacy.core.CategoryUtil;
@@ -32,6 +37,7 @@ import org.apache.log4j.spi.AppenderAttachable;
import org.apache.log4j.spi.HierarchyEventListener;
import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.message.LocalizedMessage;
import org.apache.logging.log4j.message.MapMessage;
import org.apache.logging.log4j.message.Message;
@@ -194,11 +200,17 @@ public class Category implements AppenderAttachable {
*/
@Override
public void addAppender(final Appender appender) {
- if (aai == null) {
- aai = new AppenderAttachableImpl();
- }
- aai.addAppender(appender);
if (appender != null) {
+ if (LogManager.isLog4jCorePresent()) {
+ CategoryUtil.addAppender(logger, AppenderAdapter.adapt(appender));
+ } else {
+ synchronized (this) {
+ if (aai == null) {
+ aai = new AppenderAttachableImpl();
+ }
+ aai.addAppender(appender);
+ }
+ }
repository.fireAddAppenderEvent(this, appender);
}
}
@@ -233,6 +245,10 @@ public class Category implements AppenderAttachable {
* @param event the event to log.
*/
public void callAppenders(final LoggingEvent event) {
+ if (LogManager.isLog4jCorePresent()) {
+ CategoryUtil.log(logger, new LogEventWrapper(event));
+ return;
+ }
int writes = 0;
for (Category c = this; c != null; c = c.parent) {
// Protected against simultaneous call to addAppender, removeAppender,...
@@ -353,14 +369,23 @@ public class Category implements AppenderAttachable {
}
/**
- * Get the appenders contained in this category as an {@link Enumeration}. If no appenders can be found, then a
- * {@link NullEnumeration} is returned.
+ * Get all the Log4j 1.x appenders contained in this category as an
+ * {@link Enumeration}. Log4j 2.x appenders are omitted.
*
* @return Enumeration An enumeration of the appenders in this category.
*/
@Override
- @SuppressWarnings("rawtypes")
+ @SuppressWarnings("unchecked")
public Enumeration getAllAppenders() {
+ if (LogManager.isLog4jCorePresent()) {
+ final Collection<org.apache.logging.log4j.core.Appender> appenders = CategoryUtil.getAppenders(logger)
+ .values();
+ return Collections.enumeration(appenders.stream()
+ // omit native Log4j 2.x appenders
+ .filter(AppenderAdapter.Adapter.class::isInstance)
+ .map(AppenderWrapper::adapt)
+ .collect(Collectors.toSet()));
+ }
return aai == null ? NullEnumeration.getInstance() : aai.getAllAppenders();
}
@@ -372,14 +397,10 @@ public class Category implements AppenderAttachable {
*/
@Override
public Appender getAppender(final String name) {
- Appender appender = aai != null ? aai.getAppender(name) : null;
- if (appender == null && LogManager.isLog4jCorePresent()) {
- final org.apache.logging.log4j.core.Appender coreAppender = CategoryUtil.getAppenders(logger).get(name);
- if (coreAppender != null) {
- addAppender(appender = AppenderWrapper.adapt(coreAppender));
- }
+ if (LogManager.isLog4jCorePresent()) {
+ return AppenderWrapper.adapt(CategoryUtil.getAppenders(logger).get(name));
}
- return appender;
+ return aai != null ? aai.getAppender(name) : null;
}
public Priority getChainedPriority() {
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
index f57e29deab..23931b2ee6 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
@@ -24,6 +24,7 @@ import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.util.Strings;
/**
* Binds a Log4j 1.x Appender to Log4j 2.
@@ -62,7 +63,11 @@ public class AppenderAdapter {
private AppenderAdapter(Appender appender) {
this.appender = appender;
final org.apache.logging.log4j.core.Filter appenderFilter = FilterAdapter.adapt(appender.getFilter());
- this.adapter = new Adapter(appender.getName(), appenderFilter, null, true, null);
+ String name = appender.getName();
+ if (Strings.isEmpty(name)) {
+ name = String.format("0x%08x", appender.hashCode());
+ }
+ this.adapter = new Adapter(name, appenderFilter, null, true, null);
}
public Adapter getAdapter() {
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/legacy/core/CategoryUtil.java b/log4j-1.2-api/src/main/java/org/apache/log4j/legacy/core/CategoryUtil.java
index ea6b43cd0e..3e5dc2c515 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/legacy/core/CategoryUtil.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/legacy/core/CategoryUtil.java
@@ -16,14 +16,19 @@
*/
package org.apache.log4j.legacy.core;
+import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
+import java.util.Optional;
import java.util.function.Supplier;
+import org.apache.log4j.bridge.AppenderAdapter;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.spi.LoggerContext;
/**
@@ -40,13 +45,23 @@ public final class CategoryUtil {
}
/**
- * Delegates to {@link org.apache.logging.log4j.core.Logger#getAppenders()} if appropriate.
+ * Gets the appenders attached directly to this logger.
*
* @param logger The target logger.
* @return A Map containing the Appender's name as the key and the Appender as the value.
*/
public static Map<String, Appender> getAppenders(final Logger logger) {
- return get(logger, asCore(logger)::getAppenders, null);
+ return get(logger, () -> getDirectAppenders(logger), Collections.emptyMap());
+ }
+
+ private static Map<String, Appender> getDirectAppenders(final Logger logger) {
+ return CategoryUtil.getExactLoggerConfig(logger)
+ .map(LoggerConfig::getAppenders)
+ .orElse(Collections.emptyMap());
+ }
+
+ private static Optional<LoggerConfig> getExactLoggerConfig(final Logger logger) {
+ return Optional.of(asCore(logger).get()).filter(lc -> logger.getName().equals(lc.getName()));
}
/**
@@ -117,6 +132,32 @@ public final class CategoryUtil {
}
}
+ /**
+ * Adds an appender to the logger. This method requires a check for the presence
+ * of Log4j Core or it will cause a {@code ClassNotFoundException}.
+ *
+ * @param logger The target logger.
+ * @param appender A Log4j2 appender.
+ */
+ public static void addAppender(final Logger logger, final Appender appender) {
+ if (appender instanceof AppenderAdapter.Adapter) {
+ appender.start();
+ }
+ asCore(logger).addAppender(appender);
+ }
+
+ /**
+ * Sends the event to all appenders directly connected with the logger. This
+ * method requires a check for the presence of Log4j Core or it will cause a
+ * {@code ClassNotFoundException}.
+ *
+ * @param logger The target logger.
+ * @param event The event to send.
+ */
+ public static void log(final Logger logger, final LogEvent event) {
+ getExactLoggerConfig(logger).ifPresent(lc -> lc.log(event));
+ }
+
private CategoryUtil() {
}
}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java
index e490df3c45..e474681eb4 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java
@@ -17,6 +17,23 @@
package org.apache.log4j;
+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.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.spi.LoggingEvent;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
@@ -34,24 +51,20 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import java.lang.reflect.Method;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-
-import static org.junit.jupiter.api.Assertions.*;
-
/**
* Tests of Category.
*/
public class CategoryTest {
- private static ListAppender appender = new ListAppender("List");
+ private static final String VERSION1_APPENDER_NAME = "Version1List";
+ private static final String VERSION2_APPENDER_NAME = "List";
+ private static ListAppender appender = new ListAppender(VERSION2_APPENDER_NAME);
+ private static org.apache.log4j.ListAppender version1Appender = new org.apache.log4j.ListAppender();
@BeforeAll
public static void setupClass() {
appender.start();
+ version1Appender.setName(VERSION1_APPENDER_NAME);
System.setProperty(ConfigurationFactory.CONFIGURATION_FACTORY_PROPERTY, BasicConfigurationFactory.class.getName());
}
@@ -328,6 +341,75 @@ public class CategoryTest {
}
+ @Test
+ public void testAddAppender() {
+ try {
+ final Logger rootLogger = LogManager.getRootLogger();
+ int count = version1Appender.getEvents().size();
+ rootLogger.addAppender(version1Appender);
+ final Logger logger = LogManager.getLogger(CategoryTest.class);
+ final org.apache.log4j.ListAppender appender = new org.apache.log4j.ListAppender();
+ appender.setName("appender2");
+ logger.addAppender(appender);
+ // Root logger
+ rootLogger.info("testAddLogger");
+ assertEquals(++count, version1Appender.getEvents().size(), "adding at root works");
+ assertEquals(0, appender.getEvents().size(), "adding at child works");
+ // Another logger
+ logger.info("testAddLogger2");
+ assertEquals(++count, version1Appender.getEvents().size(), "adding at root works");
+ assertEquals(1, appender.getEvents().size(), "adding at child works");
+ // Call appenders
+ final LoggingEvent event = new LoggingEvent();
+ logger.callAppenders(event);
+ assertEquals(++count, version1Appender.getEvents().size(), "callAppenders");
+ assertEquals(2, appender.getEvents().size(), "callAppenders");
+ } finally {
+ LogManager.resetConfiguration();
+ }
+ }
+
+ @Test
+ public void testGetAppender() {
+ try {
+ final Logger rootLogger = LogManager.getRootLogger();
+ final org.apache.logging.log4j.core.Logger v2RootLogger = (org.apache.logging.log4j.core.Logger) rootLogger
+ .getLogger();
+ v2RootLogger.addAppender(AppenderAdapter.adapt(version1Appender));
+ v2RootLogger.addAppender(appender);
+ final List<Appender> rootAppenders = Collections.list(rootLogger.getAllAppenders());
+ assertEquals(1, rootAppenders.size(), "only v1 appenders");
+ assertTrue(rootAppenders.get(0) instanceof org.apache.log4j.ListAppender, "appender is a v1 ListAppender");
+ assertEquals(VERSION1_APPENDER_NAME, rootLogger.getAppender(VERSION1_APPENDER_NAME).getName(),
+ "explicitly named appender");
+ Appender v2ListAppender = rootLogger.getAppender(VERSION2_APPENDER_NAME);
+ assertTrue(v2ListAppender instanceof AppenderWrapper, "explicitly named appender");
+ assertTrue(((AppenderWrapper) v2ListAppender).getAppender() instanceof ListAppender,
+ "appender is a v2 ListAppender");
+
+ final Logger logger = LogManager.getLogger(CategoryTest.class);
+ final org.apache.logging.log4j.core.Logger v2Logger = (org.apache.logging.log4j.core.Logger) logger
+ .getLogger();
+ final org.apache.log4j.ListAppender loggerAppender = new org.apache.log4j.ListAppender();
+ loggerAppender.setName("appender2");
+ v2Logger.addAppender(AppenderAdapter.adapt(loggerAppender));
+ final List<Appender> appenders = Collections.list(logger.getAllAppenders());
+ assertEquals(1, appenders.size(), "no parent appenders");
+ assertEquals(loggerAppender, appenders.get(0));
+ assertNull(logger.getAppender(VERSION1_APPENDER_NAME), "no parent appenders");
+ assertNull(logger.getAppender(VERSION2_APPENDER_NAME), "no parent appenders");
+
+ final Logger childLogger = LogManager.getLogger(CategoryTest.class.getName() + ".child");
+ final Enumeration<Appender> childAppenders = childLogger.getAllAppenders();
+ assertFalse(childAppenders.hasMoreElements(), "no parent appenders");
+ assertNull(childLogger.getAppender("appender2"), "no parent appenders");
+ assertNull(childLogger.getAppender(VERSION1_APPENDER_NAME), "no parent appenders");
+ assertNull(childLogger.getAppender(VERSION2_APPENDER_NAME), "no parent appenders");
+ } finally {
+ LogManager.resetConfiguration();
+ }
+ }
+
/**
* Derived category to check method signature of forcedLog.
*/
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/ListAppender.java b/log4j-1.2-api/src/test/java/org/apache/log4j/ListAppender.java
index 573d98673c..c1d5a799aa 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/ListAppender.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/ListAppender.java
@@ -80,4 +80,8 @@ public class ListAppender extends AppenderSkeleton {
}
return getMessages();
}
+
+ public String toString() {
+ return String.format("ListAppender[%s]", getName());
+ }
}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesReconfigurationTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesReconfigurationTest.java
index ae2910e41f..c7774d4daf 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesReconfigurationTest.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesReconfigurationTest.java
@@ -128,24 +128,15 @@ public class PropertiesReconfigurationTest {
}
private void checkCustomAppender(final String appenderName, final boolean expectBoolean, final int expectInt, final String expectString) {
- final Logger logger = LogManager.getLogger("test");
+ final Logger logger = LogManager.getRootLogger();
final org.apache.log4j.Appender appender = logger.getAppender(appenderName);
assertNotNull(appender);
assertCustomNoopAppender(appender, expectBoolean, expectInt, expectString);
assertCustomNoopAppender(getAppenderFromContext(appenderName), expectBoolean, expectInt, expectString);
}
- private void checkCustomFileAppender(final boolean expectAppend, final Appender appender) {
- assertNotNull(appender);
- final FileAppender fileAppender = (FileAppender) appender;
- @SuppressWarnings("resource")
- final FileManager manager = fileAppender.getManager();
- assertNotNull(manager);
- assertEquals(expectAppend, manager.isAppend());
- }
-
private void checkCustomFileAppender(final String appenderName, final boolean expectBoolean, final int expectInt, final String expectString) {
- final Logger logger = LogManager.getLogger("test");
+ final Logger logger = LogManager.getRootLogger();
final org.apache.log4j.Appender appender = logger.getAppender(appenderName);
assertNotNull(appender);
assertCustomFileAppender(appender, expectBoolean, expectInt, expectString);
@@ -153,13 +144,14 @@ public class PropertiesReconfigurationTest {
}
private void checkFileAppender(final boolean expectAppend, final String appenderName) {
- final Logger logger = LogManager.getLogger("test");
+ final Logger logger = LogManager.getRootLogger();
final org.apache.log4j.Appender appender = logger.getAppender(appenderName);
assertNotNull(appender);
final AppenderWrapper appenderWrapper = (AppenderWrapper) appender;
checkCoreFileAppender(expectAppend, appenderWrapper.getAppender());
}
+ @SuppressWarnings("unchecked")
private <T extends org.apache.log4j.Appender> T getAppenderFromContext(final String appenderName) {
final LoggerContext context = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
final LoggerConfig loggerConfig = context.getConfiguration().getRootLogger();